mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-25 08:59:03 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e496f8ecc2 | |||
| 9d8132978f | |||
| 73c29f666f | |||
| d895c9fa91 | |||
| b5e66387c3 | |||
| 1fbfdbccf8 | |||
| 2648f18b12 | |||
| 908c0e2cd5 | |||
| 4f3530db5e | |||
| 73137891c4 | |||
| c28087ac44 | |||
| 9e9dd3a521 | |||
| 3bf689f339 | |||
| 86c326ef12 | |||
| 5ae97d47f1 | |||
| 762512b7dc | |||
| 9c848a6215 | |||
| 9c86e15ddb | |||
| 57ccdb0044 | |||
| 1172175cc8 | |||
| 9ed8ad5903 | |||
| e4da8b979e | |||
| 4b83fd8a40 | |||
| cd80da58d8 | |||
| a1f7010e08 | |||
| 3499d2fa75 | |||
| 948e039574 | |||
| 27dc37713b |
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
+7
-1
@@ -68,9 +68,15 @@ CMakeFiles/
|
||||
.DS_Store
|
||||
/firmware/CMakeCache.txt
|
||||
|
||||
# Python env/ venv
|
||||
# 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
|
||||
|
||||
@@ -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:
|
||||
|
||||
[](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
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "string_format.hpp"
|
||||
#include "ui_freqman.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "radio.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace tonekey;
|
||||
@@ -112,10 +113,14 @@ SPECOptionsView::SPECOptionsView(
|
||||
: View{parent_rect} {
|
||||
set_style(style);
|
||||
|
||||
add_children({&label_config,
|
||||
&options_config,
|
||||
&text_speed,
|
||||
&field_speed});
|
||||
add_children({
|
||||
&label_config,
|
||||
&options_config,
|
||||
&text_speed,
|
||||
&field_speed,
|
||||
&text_rx_cal,
|
||||
&field_rx_iq_phase_cal,
|
||||
});
|
||||
|
||||
options_config.set_selected_index(view->get_spec_bw_index());
|
||||
options_config.on_change = [this, view](size_t n, OptionsField::value_t bw) {
|
||||
@@ -126,6 +131,12 @@ SPECOptionsView::SPECOptionsView(
|
||||
field_speed.on_change = [this, view](int32_t v) {
|
||||
view->set_spec_trigger(v);
|
||||
};
|
||||
|
||||
field_rx_iq_phase_cal.set_range(0, hackrf_r9 ? 63 : 31); // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31]
|
||||
field_rx_iq_phase_cal.set_value(view->get_spec_iq_phase_calibration_value()); // using accessor function of AnalogAudioView to read iq_phase_calibration_value from rx_audio.ini
|
||||
field_rx_iq_phase_cal.on_change = [this, view](int32_t v) {
|
||||
view->set_spec_iq_phase_calibration_value(v); // using accessor function of AnalogAudioView to write inside SPEC submenu, register value to max283x and save it to rx_audio.ini
|
||||
};
|
||||
}
|
||||
|
||||
/* AnalogAudioView *******************************************************/
|
||||
@@ -213,6 +224,15 @@ void AnalogAudioView::set_spec_bw(size_t index, uint32_t bw) {
|
||||
receiver_model.set_baseband_bandwidth(bw / 2);
|
||||
}
|
||||
|
||||
uint8_t AnalogAudioView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
|
||||
return iq_phase_calibration_value;
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // define accessor functions
|
||||
iq_phase_calibration_value = cal_value;
|
||||
radio::set_rx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
}
|
||||
|
||||
uint16_t AnalogAudioView::get_spec_trigger() {
|
||||
return spec_trigger;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class SPECOptionsView : public View {
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
Text text_rx_cal{
|
||||
{19 * 8, 0 * 16, 11 * 8, 1 * 16}, // 18 (x col.) x char_size, 12 (length) x 8 blanking space to delete previous chars.
|
||||
"Rx_IQ_CAL "};
|
||||
NumberField field_rx_iq_phase_cal{
|
||||
{28 * 8, 0 * 16},
|
||||
2,
|
||||
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
};
|
||||
|
||||
class AnalogAudioView : public View {
|
||||
@@ -152,14 +162,22 @@ class AnalogAudioView : public View {
|
||||
uint16_t get_spec_trigger();
|
||||
void set_spec_trigger(uint16_t trigger);
|
||||
|
||||
uint8_t get_spec_iq_phase_calibration_value();
|
||||
void set_spec_iq_phase_calibration_value(uint8_t cal_value);
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{};
|
||||
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_audio", app_settings::Mode::RX,
|
||||
app_settings::Options::UseGlobalTargetFrequency};
|
||||
"rx_audio",
|
||||
app_settings::Mode::RX,
|
||||
app_settings::Options::UseGlobalTargetFrequency,
|
||||
{
|
||||
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
|
||||
}};
|
||||
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16};
|
||||
const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16};
|
||||
|
||||
@@ -479,7 +479,7 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
|
||||
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { portapack::persistent_memory::debug_dump(); }},
|
||||
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { stack_dump(); }},
|
||||
{"Memory Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryDumpView>(); }},
|
||||
{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
|
||||
//{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
|
||||
{"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>(); } },
|
||||
|
||||
@@ -38,23 +38,29 @@ DfuMenu::DfuMenu(NavigationView& nav)
|
||||
&text_info_line_5,
|
||||
&text_info_line_6,
|
||||
&text_info_line_7,
|
||||
&text_info_line_8});
|
||||
&text_info_line_8,
|
||||
&text_info_line_9,
|
||||
&text_info_line_10});
|
||||
}
|
||||
|
||||
void DfuMenu::paint(Painter& painter) {
|
||||
auto utilisation = get_cpu_utilisation_in_percent();
|
||||
size_t m0_fragmented_free_space = 0;
|
||||
const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
|
||||
|
||||
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
|
||||
text_info_line_2.set(to_string_dec_uint((uint32_t)get_free_stack_space(), 6));
|
||||
text_info_line_3.set(to_string_dec_uint(utilisation, 6));
|
||||
text_info_line_4.set(to_string_dec_uint(shared_memory.m4_heap_usage, 6));
|
||||
text_info_line_5.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
|
||||
text_info_line_6.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
||||
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
||||
text_info_line_8.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
||||
text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6));
|
||||
text_info_line_3.set(to_string_dec_uint(m0_fragments, 6));
|
||||
text_info_line_4.set(to_string_dec_uint((uint32_t)get_free_stack_space(), 6));
|
||||
text_info_line_5.set(to_string_dec_uint(utilisation, 6));
|
||||
text_info_line_6.set(to_string_dec_uint(shared_memory.m4_heap_usage, 6));
|
||||
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
|
||||
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
||||
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
||||
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
||||
|
||||
constexpr auto margin = 5;
|
||||
constexpr auto lines = 8 + 2;
|
||||
constexpr auto lines = 10 + 2;
|
||||
|
||||
painter.fill_rectangle(
|
||||
{{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},
|
||||
|
||||
@@ -49,14 +49,16 @@ class DfuMenu : public View {
|
||||
Text text_head{{6 * CHARACTER_WIDTH, 3 * LINE_HEIGHT, 11 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, "Performance"};
|
||||
|
||||
Labels labels{
|
||||
{{6 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "M0 heap:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "M0 stack:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "M0 cpu %:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 8 * LINE_HEIGHT}, "M4 heap:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 9 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 10 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}};
|
||||
{{6 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "M0 core:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "M0 heap:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "M0 frags:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 8 * LINE_HEIGHT}, "M0 stack:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 9 * LINE_HEIGHT}, "M0 cpu %:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 10 * LINE_HEIGHT}, "M4 heap:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()},
|
||||
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}};
|
||||
|
||||
Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
@@ -66,6 +68,8 @@ class DfuMenu : public View {
|
||||
Text text_info_line_6{{15 * CHARACTER_WIDTH, 10 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_7{{15 * CHARACTER_WIDTH, 11 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
};
|
||||
|
||||
class DfuMenu2 : public View {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ void LevelView::focus() {
|
||||
}
|
||||
|
||||
LevelView::~LevelView() {
|
||||
// reset performance counters request to default
|
||||
shared_memory.request_m4_performance_counter = 0;
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
@@ -58,12 +60,16 @@ LevelView::LevelView(NavigationView& nav)
|
||||
&text_ctcss,
|
||||
&freq_stats_rssi,
|
||||
&freq_stats_db,
|
||||
&freq_stats_rx,
|
||||
&audio_mode,
|
||||
&peak_mode,
|
||||
&rssi,
|
||||
&rssi_graph});
|
||||
|
||||
// activate vertical bar mode
|
||||
rssi.set_vertical_rssi(true);
|
||||
// activate counters for RxSat
|
||||
shared_memory.request_m4_performance_counter = 2;
|
||||
|
||||
change_mode(NFM_MODULATION); // Start on AM
|
||||
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector
|
||||
@@ -139,13 +145,15 @@ LevelView::LevelView(NavigationView& nav)
|
||||
freqman_set_step_option_short(step_mode);
|
||||
freq_stats_rssi.set_style(&Styles::white);
|
||||
freq_stats_db.set_style(&Styles::white);
|
||||
freq_stats_rx.set_style(&Styles::white);
|
||||
}
|
||||
|
||||
void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||
static int16_t last_max_db = -1000;
|
||||
static int16_t last_min_rssi = -1000;
|
||||
static int16_t last_avg_rssi = -1000;
|
||||
static int16_t last_max_rssi = -1000;
|
||||
static int16_t last_max_db = 0;
|
||||
static uint8_t last_min_rssi = 0;
|
||||
static uint8_t last_avg_rssi = 0;
|
||||
static uint8_t last_max_rssi = 0;
|
||||
static uint8_t last_rx_sat = 0;
|
||||
|
||||
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
|
||||
|
||||
@@ -154,12 +162,18 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||
last_max_db = statistics.max_db;
|
||||
freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db");
|
||||
}
|
||||
// refresh sat
|
||||
uint8_t rx_sat = ((uint32_t)shared_memory.m4_performance_counter) * 100 / 127;
|
||||
if (last_rx_sat != rx_sat) {
|
||||
last_rx_sat = rx_sat;
|
||||
freq_stats_rx.set("RxSat: " + to_string_dec_uint(rx_sat) + "%");
|
||||
}
|
||||
// refresh rssi
|
||||
if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) {
|
||||
last_min_rssi = rssi_graph.get_graph_min();
|
||||
last_avg_rssi = rssi_graph.get_graph_avg();
|
||||
last_max_rssi = rssi_graph.get_graph_max();
|
||||
freq_stats_rssi.set("RSSI: " + to_string_dec_int(last_min_rssi) + "/" + to_string_dec_int(last_avg_rssi) + "/" + to_string_dec_int(last_max_rssi) + ",dt: " + to_string_dec_int(rssi_graph.get_graph_delta()));
|
||||
freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi) + ", dt: " + to_string_dec_uint(rssi_graph.get_graph_delta()));
|
||||
}
|
||||
} /* on_statistic_updates */
|
||||
|
||||
|
||||
@@ -62,8 +62,6 @@ class LevelView : public View {
|
||||
void on_statistics_update(const ChannelStatistics& statistics);
|
||||
void set_display_freq(int64_t freq);
|
||||
|
||||
// TODO: needed?
|
||||
int32_t db{0};
|
||||
rf::Frequency freq_ = {0};
|
||||
|
||||
Labels labels{
|
||||
@@ -138,6 +136,7 @@ class LevelView : public View {
|
||||
{"peak:5s", 5000},
|
||||
{"peak:10s", 10000},
|
||||
}};
|
||||
|
||||
OptionsField rssi_resolution{
|
||||
{44 + 20 * 8, 4 * 16 + 4},
|
||||
4,
|
||||
@@ -149,9 +148,14 @@ class LevelView : public View {
|
||||
{"240x", 240},
|
||||
}};
|
||||
|
||||
// RxSat: XX%
|
||||
Text freq_stats_rx{
|
||||
{0 * 8, 5 * 16 + 4, 10 * 8, 14},
|
||||
};
|
||||
|
||||
RSSIGraph rssi_graph{
|
||||
// 240x320 =>
|
||||
{0, 5 * 16 + 4, 240 - 5 * 8, 320 - (5 * 16 + 4)},
|
||||
{0, 6 * 16 + 4, 240 - 5 * 8, 320 - (6 * 16 + 4)},
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
|
||||
@@ -338,7 +338,7 @@ MicTXView::MicTXView(
|
||||
&field_rxlna,
|
||||
&field_rxvga,
|
||||
&field_rxamp,
|
||||
hackrf_r9 ? &field_tx_iq_phase_cal_2839 : &field_tx_iq_phase_cal_2837,
|
||||
&field_tx_iq_phase_cal,
|
||||
&tx_button,
|
||||
&tx_icon});
|
||||
|
||||
@@ -372,19 +372,12 @@ MicTXView::MicTXView(
|
||||
};
|
||||
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
if (hackrf_r9) { // MAX2839 has 6 bits IQ CAL phasse adjustment.
|
||||
field_tx_iq_phase_cal_2839.set_value(iq_phase_calibration_value);
|
||||
field_tx_iq_phase_cal_2839.on_change = [this](int32_t v) {
|
||||
iq_phase_calibration_value = v;
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
};
|
||||
} else { // MAX2837 has 5 bits IQ CAL phase adjustment.
|
||||
field_tx_iq_phase_cal_2837.set_value(iq_phase_calibration_value);
|
||||
field_tx_iq_phase_cal_2837.on_change = [this](int32_t v) {
|
||||
iq_phase_calibration_value = v;
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
};
|
||||
}
|
||||
field_tx_iq_phase_cal.set_range(0, hackrf_r9 ? 63 : 31); // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31]
|
||||
field_tx_iq_phase_cal.set_value(iq_phase_calibration_value);
|
||||
field_tx_iq_phase_cal.on_change = [this](int32_t v) {
|
||||
iq_phase_calibration_value = v;
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
};
|
||||
|
||||
options_gain.on_change = [this](size_t, int32_t v) {
|
||||
mic_gain_x10 = v;
|
||||
|
||||
@@ -342,18 +342,10 @@ class MicTXView : public View {
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_tx_iq_phase_cal_2837{
|
||||
NumberField field_tx_iq_phase_cal{
|
||||
{24 * 8, (33 * 8)},
|
||||
2,
|
||||
{0, 31}, // 5 bits IQ CAL phase adjustment.
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_tx_iq_phase_cal_2839{
|
||||
{24 * 8, (33 * 8)},
|
||||
2,
|
||||
{0, 63}, // 6 bits IQ CAL phasse adjustment.
|
||||
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "log_file.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@@ -556,8 +554,6 @@ void TextEditorView::open_file(const fs::path& path) {
|
||||
viewer.set_file(*file_);
|
||||
}
|
||||
|
||||
portapack::persistent_memory::set_apply_fake_brightness(false); // work around to resolve the display issue in notepad app. not elegant i know, so TODO.
|
||||
|
||||
refresh_ui();
|
||||
}
|
||||
|
||||
|
||||
@@ -5764,8 +5764,8 @@ static constexpr uint8_t bitmap_icon_brightness_data[] = {
|
||||
0x00,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x84,
|
||||
0x21,
|
||||
0x08,
|
||||
0x10,
|
||||
0xC0,
|
||||
@@ -5786,8 +5786,8 @@ static constexpr uint8_t bitmap_icon_brightness_data[] = {
|
||||
0x03,
|
||||
0x08,
|
||||
0x10,
|
||||
0x80,
|
||||
0x01,
|
||||
0x84,
|
||||
0x21,
|
||||
0x80,
|
||||
0x01,
|
||||
0x00,
|
||||
|
||||
+1
-1
@@ -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--;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
+9
@@ -38,6 +38,7 @@ MEMORY
|
||||
ram_external_app_spainter(rwx) : org = 0xADBC0000, len = 32k
|
||||
ram_external_app_keyfob(rwx) : org = 0xADBD0000, len = 32k
|
||||
ram_external_app_tetris(rwx) : org = 0xADBE0000, len = 32k
|
||||
ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -132,4 +133,12 @@ SECTIONS
|
||||
*(*ui*external_app*tetris*);
|
||||
} > ram_external_app_tetris
|
||||
|
||||
.external_app_extsensors : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_extsensors.application_information));
|
||||
*(*ui*external_app*extsensors*);
|
||||
} > ram_external_app_extsensors
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -150,7 +150,7 @@ void MAX2837::init() {
|
||||
}
|
||||
|
||||
void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) {
|
||||
/* IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
|
||||
/* TX IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
|
||||
|
||||
// TX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,0,1 (5dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
|
||||
set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins .
|
||||
@@ -324,14 +324,41 @@ bool MAX2837::set_frequency(const rf::Frequency lo_frequency) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MAX2837::set_rx_lo_iq_calibration(const size_t v) {
|
||||
/*
|
||||
void MAX2837::set_rx_lo_iq_calibration(const size_t v) { // Original code , rewritten below
|
||||
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1;
|
||||
_dirty[Register::RX_TOP_RX_BIAS] = 1;
|
||||
_map.r.rxrf_2.iqerr_trim = v;
|
||||
_dirty[Register::RXRF_2] = 1;
|
||||
flush();
|
||||
}
|
||||
*/
|
||||
|
||||
void MAX2837::set_rx_LO_iq_phase_calibration(const size_t v) {
|
||||
/* RX IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
|
||||
|
||||
// RX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,1,0 (3dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
|
||||
set_mode(Mode::Rx_Calibration); // write to ram 3 LOGIC Pins .
|
||||
|
||||
gpio_max283x_enable.output();
|
||||
gpio_max2837_rxenable.output();
|
||||
gpio_max2837_txenable.output();
|
||||
|
||||
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1; // reg 8 D9, RX LO IQ Phase calibration SPI control. Active when Address 8 D<9> = 1.
|
||||
flush_one(Register::RX_TOP_RX_BIAS);
|
||||
|
||||
_map.r.rxrf_2.iqerr_trim = v; // reg 1 D9:D5, RX LO I/Q Phase SPI 5 bits Adjust
|
||||
flush_one(Register::RXRF_2);
|
||||
|
||||
// Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated.
|
||||
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
|
||||
flush_one(Register::SPI_EN);
|
||||
}
|
||||
|
||||
void MAX2837::set_rx_bias_trim(const size_t v) {
|
||||
_map.r.rx_top_rx_bias.EN_Bias_Trim = 1;
|
||||
|
||||
@@ -828,7 +828,7 @@ class MAX2837 : public MAX283x {
|
||||
|
||||
bool set_frequency(const rf::Frequency lo_frequency) override;
|
||||
|
||||
void set_rx_lo_iq_calibration(const size_t v) override;
|
||||
void set_rx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_tx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_rx_bias_trim(const size_t v);
|
||||
void set_vco_bias(const size_t v);
|
||||
|
||||
@@ -367,13 +367,38 @@ bool MAX2839::set_frequency(const rf::Frequency lo_frequency) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MAX2839::set_rx_lo_iq_calibration(const size_t v) {
|
||||
/*
|
||||
void MAX2839::set_rx_LO_iq_phase_calibration(const size_t v) { // Original code , rewritten below
|
||||
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1;
|
||||
_dirty[Register::RXRF_2] = 1;
|
||||
_map.r.rxrf_1.iqerr_trim = v;
|
||||
_dirty[Register::RXRF_1] = 1;
|
||||
flush();
|
||||
}*/
|
||||
|
||||
void MAX2839::set_rx_LO_iq_phase_calibration(const size_t v) {
|
||||
/* RX IQ phase deg CAL adj (+4 ...-4) in 64 steps (6 bits), 000000 = +4deg (Q lags I by 94degs, default), 011111 = +0deg, 111111 = -4deg (Q lags I by 86degs) */
|
||||
|
||||
// RX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,1,0 (3dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
|
||||
set_mode(Mode::Rx_Calibration); // write to ram 3 LOGIC Pins .
|
||||
|
||||
gpio_max283x_enable.output(); // max2839 has only 2 x pins + regs to decide mode.
|
||||
gpio_max2839_rxtx.output(); // Here is combined rx & tx pin in one port.
|
||||
|
||||
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1; // reg 2 D<2> = 1, RX LO IQ calibration SPI control. Active when Address 2 D<2> = 1.
|
||||
_dirty[Register::RXRF_2] = 1;
|
||||
|
||||
_map.r.rxrf_1.iqerr_trim = v;
|
||||
_dirty[Register::RXRF_1] = 1;
|
||||
flush();
|
||||
|
||||
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (CAL mode 1)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
|
||||
flush_one(Register::SPI_EN);
|
||||
}
|
||||
|
||||
void MAX2839::set_rx_buff_vcm(const size_t v) {
|
||||
|
||||
@@ -82,11 +82,11 @@ struct RXENABLE_Type {
|
||||
static_assert(sizeof(RXENABLE_Type) == sizeof(reg_t), "RXENABLE_Type wrong size");
|
||||
|
||||
struct RXRF_1_Type {
|
||||
reg_t LNAband : 1;
|
||||
reg_t LNAband : 2; // Datasheet says D1:D0 , 2 bits, maybe D1 Rx_B, D0 Rx_A , (original code said wrongly ,reg_t LNAband : 1; that was of for max2837, not max2839 )
|
||||
reg_t RESERVED0 : 1;
|
||||
reg_t MIMOmode : 1;
|
||||
reg_t iqerr_trim : 5;
|
||||
reg_t RESERVED1 : 6;
|
||||
reg_t iqerr_trim : 6; // Datasheet says D9_D4 , that means 6 bits, (original code said wrongly ,reg_t iqerr_trim : 5; )
|
||||
reg_t RESERVED1 : 6; // we are using 16 bits , even top part mapping is not used
|
||||
};
|
||||
|
||||
static_assert(sizeof(RXRF_1_Type) == sizeof(reg_t), "RXRF_1_Type wrong size");
|
||||
@@ -689,7 +689,7 @@ class MAX2839 : public MAX283x {
|
||||
void set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) override;
|
||||
void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override;
|
||||
bool set_frequency(const rf::Frequency lo_frequency) override;
|
||||
void set_rx_lo_iq_calibration(const size_t v) override;
|
||||
void set_rx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_tx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_rx_buff_vcm(const size_t v) override;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class MAX283x {
|
||||
|
||||
virtual bool set_frequency(const rf::Frequency lo_frequency);
|
||||
|
||||
virtual void set_rx_lo_iq_calibration(const size_t v);
|
||||
virtual void set_rx_LO_iq_phase_calibration(const size_t v);
|
||||
virtual void set_tx_LO_iq_phase_calibration(const size_t v);
|
||||
|
||||
virtual void set_rx_buff_vcm(const size_t v);
|
||||
|
||||
@@ -253,6 +253,10 @@ void set_tx_max283x_iq_phase_calibration(const size_t v) {
|
||||
second_if->set_tx_LO_iq_phase_calibration(v);
|
||||
}
|
||||
|
||||
void set_rx_max283x_iq_phase_calibration(const size_t v) {
|
||||
second_if->set_rx_LO_iq_phase_calibration(v);
|
||||
}
|
||||
|
||||
/*void enable(Configuration configuration) {
|
||||
configure(configuration);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum);
|
||||
void set_baseband_rate(const uint32_t rate);
|
||||
void set_antenna_bias(const bool on);
|
||||
void set_tx_max283x_iq_phase_calibration(const size_t v);
|
||||
void set_rx_max283x_iq_phase_calibration(const size_t v);
|
||||
|
||||
/* Use ReceiverModel or TransmitterModel instead. */
|
||||
// void enable(Configuration configuration);
|
||||
|
||||
@@ -163,19 +163,19 @@ void RSSI::paint(Painter& painter) {
|
||||
}
|
||||
}
|
||||
|
||||
int16_t RSSI::get_min() {
|
||||
uint8_t RSSI::get_min() {
|
||||
return min_;
|
||||
}
|
||||
|
||||
int16_t RSSI::get_avg() {
|
||||
uint8_t RSSI::get_avg() {
|
||||
return avg_;
|
||||
}
|
||||
|
||||
int16_t RSSI::get_max() {
|
||||
uint8_t RSSI::get_max() {
|
||||
return max_;
|
||||
}
|
||||
|
||||
int16_t RSSI::get_delta() {
|
||||
uint8_t RSSI::get_delta() {
|
||||
return max_ - min_;
|
||||
}
|
||||
|
||||
@@ -213,19 +213,19 @@ void RSSI::on_statistics_update(const RSSIStatistics& statistics) {
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
int16_t RSSIGraph::get_graph_min() {
|
||||
uint8_t RSSIGraph::get_graph_min() {
|
||||
return graph_min_;
|
||||
}
|
||||
|
||||
int16_t RSSIGraph::get_graph_avg() {
|
||||
uint8_t RSSIGraph::get_graph_avg() {
|
||||
return graph_avg_;
|
||||
}
|
||||
|
||||
int16_t RSSIGraph::get_graph_max() {
|
||||
uint8_t RSSIGraph::get_graph_max() {
|
||||
return graph_max_;
|
||||
}
|
||||
|
||||
int16_t RSSIGraph::get_graph_delta() {
|
||||
uint8_t RSSIGraph::get_graph_delta() {
|
||||
return graph_max_ - graph_min_;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ class RSSI : public Widget {
|
||||
}
|
||||
|
||||
// get last used/received min/avg/max/delta
|
||||
int16_t get_min();
|
||||
int16_t get_avg();
|
||||
int16_t get_max();
|
||||
int16_t get_delta();
|
||||
uint8_t get_min();
|
||||
uint8_t get_avg();
|
||||
uint8_t get_max();
|
||||
uint8_t get_delta();
|
||||
void set_vertical_rssi(bool enabled);
|
||||
void set_peak(bool enabled, size_t duration);
|
||||
|
||||
@@ -63,10 +63,10 @@ class RSSI : public Widget {
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
|
||||
private:
|
||||
int16_t min_ = 0;
|
||||
int16_t avg_ = 0;
|
||||
int16_t max_ = 0;
|
||||
int16_t peak_ = 0;
|
||||
int8_t min_ = 0;
|
||||
int8_t avg_ = 0;
|
||||
int8_t max_ = 0;
|
||||
int8_t peak_ = 0;
|
||||
size_t peak_duration_ = 0;
|
||||
bool instant_exec_{false};
|
||||
|
||||
@@ -115,10 +115,10 @@ class RSSIGraph : public Widget {
|
||||
void on_hide() override;
|
||||
void on_show() override;
|
||||
// get whole graph_list min/avg/max/delta
|
||||
int16_t get_graph_min();
|
||||
int16_t get_graph_avg();
|
||||
int16_t get_graph_max();
|
||||
int16_t get_graph_delta();
|
||||
uint8_t get_graph_min();
|
||||
uint8_t get_graph_avg();
|
||||
uint8_t get_graph_max();
|
||||
uint8_t get_graph_delta();
|
||||
|
||||
private:
|
||||
int16_t graph_min_ = 0;
|
||||
|
||||
@@ -861,6 +861,7 @@ NavigationView* SystemView::get_navigation_view() {
|
||||
}
|
||||
|
||||
void SystemView::toggle_overlay() {
|
||||
static uint8_t last_perf_counter_status = shared_memory.request_m4_performance_counter;
|
||||
switch (++overlay_active) {
|
||||
case 1:
|
||||
this->add_child(&this->overlay);
|
||||
@@ -879,7 +880,7 @@ void SystemView::toggle_overlay() {
|
||||
case 3:
|
||||
this->remove_child(&this->overlay2);
|
||||
this->set_dirty();
|
||||
shared_memory.request_m4_performance_counter = 0;
|
||||
shared_memory.request_m4_performance_counter = last_perf_counter_status;
|
||||
overlay_active = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -320,10 +320,6 @@ class BMPView : public View {
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
Text text_info{
|
||||
{4 * 8, 284, 20 * 8, 16},
|
||||
"Version " VERSION_STRING};
|
||||
|
||||
Button button_done{
|
||||
{240, 0, 1, 1},
|
||||
""};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
#ifndef __RSSI_STATS_COLLECTOR_H__
|
||||
#define __RSSI_STATS_COLLECTOR_H__
|
||||
|
||||
#include "rssi.hpp"
|
||||
#include "message.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include "rssi.hpp"
|
||||
#include "message.hpp"
|
||||
|
||||
class RSSIStatisticsCollector {
|
||||
public:
|
||||
template <typename Callback>
|
||||
|
||||
@@ -120,6 +120,7 @@ class Message {
|
||||
SubGhzDData = 62,
|
||||
GPSPosData = 63,
|
||||
OrientationData = 64,
|
||||
EnvironmentData = 65,
|
||||
MAX
|
||||
};
|
||||
|
||||
@@ -132,10 +133,10 @@ class Message {
|
||||
};
|
||||
|
||||
struct RSSIStatistics {
|
||||
uint32_t accumulator{0};
|
||||
uint32_t min{0};
|
||||
uint32_t max{0};
|
||||
uint32_t count{0};
|
||||
uint16_t accumulator{0};
|
||||
uint8_t min{0};
|
||||
uint8_t max{0};
|
||||
uint16_t count{0};
|
||||
};
|
||||
|
||||
class RSSIStatisticsMessage : public Message {
|
||||
@@ -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__*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -34,6 +35,21 @@
|
||||
|
||||
// #include "portapack_persistent_memory.hpp"
|
||||
|
||||
// Darkened pixel bit mask for each possible shift value.
|
||||
static const uint16_t darken_mask[4] = {
|
||||
0b1111111111111111, // RrrrrGgggggBbbbb
|
||||
0b0111101111101111, // 0Rrrr0Ggggg0Bbbb
|
||||
0b0011100111100111, // 00Rrr00Gggg00Bbb
|
||||
0b0001100011100011 // 000Rr000Ggg000Bb
|
||||
};
|
||||
|
||||
// To darken, dividing each color level R/G/B by 2^shift.
|
||||
#define DARKENED_PIXEL(pixel, shift) ((pixel >> shift) & darken_mask[shift])
|
||||
|
||||
// To un-darken, multiply each color level by 2^shift (might still be darker that before since some bits may have been lost above).
|
||||
// This function will only be called when the pixel has previously been darkened, so no masking is needed.
|
||||
#define UNDARKENED_PIXEL(pixel, shift) (pixel << shift)
|
||||
|
||||
namespace portapack {
|
||||
|
||||
class IO {
|
||||
@@ -147,7 +163,7 @@ class IO {
|
||||
|
||||
void lcd_write_pixel(ui::Color pixel) {
|
||||
if (get_dark_cover()) {
|
||||
darken_color(pixel, get_brightness()); // Darken the pixel color
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
|
||||
}
|
||||
lcd_write_data(pixel.v);
|
||||
}
|
||||
@@ -158,7 +174,7 @@ class IO {
|
||||
|
||||
void lcd_write_pixels(ui::Color pixel, size_t n) {
|
||||
if (get_dark_cover()) {
|
||||
darken_color(pixel, get_brightness()); // Darken the pixel color
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
|
||||
}
|
||||
while (n--) {
|
||||
lcd_write_data(pixel.v);
|
||||
@@ -167,7 +183,7 @@ class IO {
|
||||
|
||||
void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) {
|
||||
if (get_dark_cover()) {
|
||||
darken_color(pixel, get_brightness()); // Darken the pixel color
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
|
||||
}
|
||||
auto v = pixel.v;
|
||||
n >>= 3;
|
||||
@@ -331,25 +347,6 @@ class IO {
|
||||
addr(1); /* Set up for data phase (most likely after a command) */
|
||||
}
|
||||
|
||||
void darken_color(ui::Color& pixel, uint8_t darken_level_shift) {
|
||||
// TODO: 1. do we need edge control?
|
||||
// currently didn't see and issue without edge control
|
||||
// but maybe hurts screen hardware without one?
|
||||
|
||||
// TODO: 2. de-color mode for accessibility
|
||||
// TODO: 3. high contrast mode for accessibility
|
||||
|
||||
uint16_t r = (pixel.v >> 11) & 0x1F; // Extract red
|
||||
uint16_t g = (pixel.v >> 5) & 0x3F; // Extract green
|
||||
uint16_t b = pixel.v & 0x1F; // Extract blue
|
||||
|
||||
r = r >> darken_level_shift; // Darken red
|
||||
g = g >> darken_level_shift; // Darken green
|
||||
b = b >> darken_level_shift; // Darken blue
|
||||
|
||||
pixel.v = (r << 11) | (g << 5) | b; // Combine back to color, check UI::color for the color layout
|
||||
}
|
||||
|
||||
// void high_contrast(ui::Color& pixel, size_t contrast_level_shift) { // TODO
|
||||
// uint16_t r = (pixel.v >> 11) & 0x1F;
|
||||
// uint16_t g = (pixel.v >> 5) & 0x3F;
|
||||
@@ -417,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) {
|
||||
|
||||
@@ -73,6 +73,7 @@ struct image_tag_t {
|
||||
char c[4];
|
||||
};
|
||||
|
||||
constexpr image_tag_t image_tag_none{0, 0, 0, 0};
|
||||
constexpr image_tag_t image_tag_acars{'P', 'A', 'C', 'A'};
|
||||
constexpr image_tag_t image_tag_adsb_rx{'P', 'A', 'D', 'R'};
|
||||
constexpr image_tag_t image_tag_afsk_rx{'P', 'A', 'F', 'R'};
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,82 @@
|
||||
# Drone Analog FPV Channels
|
||||
# https://oscarliang.com/fpv-channels/
|
||||
f=5865000000,d=FPV Ch A-1
|
||||
f=5845000000,d=FPV Ch A-2
|
||||
f=5825000000,d=FPV Ch A-3
|
||||
f=5805000000,d=FPV Ch A-4
|
||||
f=5785000000,d=FPV Ch A-5
|
||||
f=5765000000,d=FPV Ch A-6
|
||||
f=5745000000,d=FPV Ch A-7
|
||||
f=5725000000,d=FPV Ch A-8
|
||||
f=5733000000,d=FPV Ch B-1
|
||||
f=5752000000,d=FPV Ch B-2
|
||||
f=5771000000,d=FPV Ch B-3
|
||||
f=5790000000,d=FPV Ch B-4
|
||||
f=5809000000,d=FPV Ch B-5
|
||||
f=5828000000,d=FPV Ch B-6
|
||||
f=5847000000,d=FPV Ch B-7
|
||||
f=5866000000,d=FPV Ch B-8
|
||||
f=5705000000,d=FPV Ch E-1
|
||||
f=5685000000,d=FPV Ch E-2
|
||||
f=5665000000,d=FPV Ch E-3
|
||||
f=5645000000,d=FPV Ch E-4
|
||||
f=5885000000,d=FPV Ch E-5
|
||||
f=5905000000,d=FPV Ch E-6
|
||||
f=5925000000,d=FPV Ch E-7
|
||||
f=5945000000,d=FPV Ch E-8
|
||||
f=5740000000,d=FPV Ch F-1
|
||||
f=5760000000,d=FPV Ch F-2
|
||||
f=5780000000,d=FPV Ch F-3
|
||||
f=5800000000,d=FPV Ch F-4
|
||||
f=5820000000,d=FPV Ch F-5
|
||||
f=5840000000,d=FPV Ch F-6
|
||||
f=5860000000,d=FPV Ch F-7
|
||||
f=5880000000,d=FPV Ch F-8
|
||||
f=5658000000,d=FPV Ch R-1
|
||||
f=5695000000,d=FPV Ch R-2
|
||||
f=5732000000,d=FPV Ch R-3
|
||||
f=5769000000,d=FPV Ch R-4
|
||||
f=5806000000,d=FPV Ch R-5
|
||||
f=5843000000,d=FPV Ch R-6
|
||||
f=5880000000,d=FPV Ch R-7
|
||||
f=5917000000,d=FPV Ch R-8
|
||||
f=5362000000,d=FPV Ch D-1
|
||||
f=5399000000,d=FPV Ch D-2
|
||||
f=5436000000,d=FPV Ch D-3
|
||||
f=5473000000,d=FPV Ch D-4
|
||||
f=5510000000,d=FPV Ch D-5
|
||||
f=5547000000,d=FPV Ch D-6
|
||||
f=5584000000,d=FPV Ch D-7
|
||||
f=5621000000,d=FPV Ch D-8
|
||||
f=5325000000,d=FPV Ch U-1
|
||||
f=5348000000,d=FPV Ch U-2
|
||||
f=5366000000,d=FPV Ch U-3
|
||||
f=5384000000,d=FPV Ch U-4
|
||||
f=5402000000,d=FPV Ch U-5
|
||||
f=5420000000,d=FPV Ch U-6
|
||||
f=5438000000,d=FPV Ch U-7
|
||||
f=5456000000,d=FPV Ch U-8
|
||||
f=5474000000,d=FPV Ch O-1
|
||||
f=5492000000,d=FPV Ch O-2
|
||||
f=5510000000,d=FPV Ch O-3
|
||||
f=5528000000,d=FPV Ch O-4
|
||||
f=5546000000,d=FPV Ch O-5
|
||||
f=5564000000,d=FPV Ch O-6
|
||||
f=5582000000,d=FPV Ch O-7
|
||||
f=5600000000,d=FPV Ch O-8
|
||||
f=5333000000,d=FPV Ch L-1
|
||||
f=5373000000,d=FPV Ch L-2
|
||||
f=5413000000,d=FPV Ch L-3
|
||||
f=5453000000,d=FPV Ch L-4
|
||||
f=5493000000,d=FPV Ch L-5
|
||||
f=5533000000,d=FPV Ch L-6
|
||||
f=5573000000,d=FPV Ch L-7
|
||||
f=5613000000,d=FPV Ch L-8
|
||||
f=5653000000,d=FPV Ch H-1
|
||||
f=5693000000,d=FPV Ch H-2
|
||||
f=5733000000,d=FPV Ch H-3
|
||||
f=5773000000,d=FPV Ch H-4
|
||||
f=5813000000,d=FPV Ch H-5
|
||||
f=5853000000,d=FPV Ch H-6
|
||||
f=5893000000,d=FPV Ch H-7
|
||||
f=5933000000,d=FPV Ch H-8
|
||||
+22
-22
@@ -1,22 +1,22 @@
|
||||
a=150000,b=285000,m=AM,bw=DSB,s=5kHz,d=Longwave broadcast band|BCB (EU)
|
||||
a=525000,b=1605000,m=AM,bw=DSB,s=5kHz,d=AM broadcast band|BCB (EU & J)
|
||||
a=530000,b=1710000,m=AM,bw=DSB,s=5kHz,d=AM broadcast band|BCB (US)
|
||||
a=1800000,b=29700000,m=WFM,bw=16k,d=Amateur_radio|Amateur
|
||||
a=26900000,b=27400000,m=WFM,bw=16k,d=Citizens_band_radio|Citizens band
|
||||
a=28000000,b=30000000,m=WFM,bw=16k,d=Amateur_radio|Amateur
|
||||
a=29000000,b=54000000,m=WFM,bw=16k,d=Land mobile
|
||||
a=50000000,b=54000000,m=WFM,bw=16k,d=Amateur_radio|Amateur
|
||||
a=65000000,b=85000000,m=WFM,bw=16k,d=Land mobile (EU)
|
||||
a=108000000,b=136000000,m=WFM,bw=16k,d=Aircraft
|
||||
a=120000000,b=160000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (EU)
|
||||
a=132000000,b=174000000,m=WFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=142000000,b=170000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=144000000,b=148000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=216000000,b=222000000,m=WFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=222000000,b=225000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=335000000,b=384000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=406000000,b=512000000,m=WFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=450000000,b=470000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=430000000,b=450000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=806000000,b=947000000,m=WFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=1200000000,b=1600000000,m=WFM,bw=16k,s=50kHz,d=Amateur|Land mobile|GPS
|
||||
a=150000,b=285000,m=AM,bw=DSB 9k,s=5kHz,d=Longwave broadcast band|BCB (EU)
|
||||
a=525000,b=1605000,m=AM,bw=DSB 9k,s=5kHz,d=AM broadcast band|BCB (EU & J)
|
||||
a=530000,b=1710000,m=AM,bw=DSB 9k,s=5kHz,d=AM broadcast band|BCB (US)
|
||||
a=1800000,b=29700000,m=AM,bw=LSB-3k,d=Amateur_radio|Amateur
|
||||
a=26900000,b=27400000,m=AM,bw=DSB 9k,d=Citizens_band_radio|Citizens band
|
||||
a=28000000,b=30000000,m=AM,bw=USB+3k,d=Amateur_radio|Amateur
|
||||
a=29000000,b=54000000,m=AM,bw=DSB 9k,d=Land mobile
|
||||
a=50000000,b=54000000,m=NFM,bw=16k,d=Amateur_radio|Amateur
|
||||
a=65000000,b=85000000,m=NFM,bw=16k,d=Land mobile (EU)
|
||||
a=108000000,b=136000000,m=NFM,bw=16k,d=Aircraft
|
||||
a=120000000,b=160000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (EU)
|
||||
a=132000000,b=174000000,m=NFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=142000000,b=170000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=144000000,b=148000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=216000000,b=222000000,m=NFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=222000000,b=225000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=335000000,b=384000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=406000000,b=512000000,m=NFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=450000000,b=470000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J)
|
||||
a=430000000,b=450000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur
|
||||
a=806000000,b=947000000,m=NFM,bw=16k,s=50kHz,d=Land mobile
|
||||
a=1200000000,b=1600000000,m=NFM,bw=16k,s=50kHz,d=Amateur|Land mobile|GPS
|
||||
|
||||
Reference in New Issue
Block a user