Merge branch 'v1.2' into add-heading-to-geomap

This commit is contained in:
Erwin Ried 2020-08-15 15:52:53 +02:00 committed by GitHub
commit 5a3da3bd6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 2499 additions and 2119 deletions

View File

@ -1,13 +1,12 @@
# PortaPack Mayhem # PortaPack Mayhem
[![Build Status](https://travis-ci.com/eried/portapack-mayhem.svg?branch=master)](https://travis-ci.com/eried/portapack-mayhem) [![buddy pipeline](https://app.buddy.works/eried/portapack/pipelines/pipeline/252276/badge.svg?token=48cd59d53de0589a8fbe26bc751d77a59a011cf72581da049343879402991c34 "buddy pipeline")](https://app.buddy.works/eried/portapack/pipelines/pipeline/252276) [![CodeScene Code Health](https://codescene.io/projects/8381/status-badges/code-health)](https://codescene.io/projects/8381) [![Docker Hub Pulls](https://img.shields.io/docker/pulls/eried/portapack.svg)](https://hub.docker.com/r/eried/portapack) [![Build Status](https://travis-ci.com/eried/portapack-mayhem.svg?branch=master)](https://travis-ci.com/eried/portapack-mayhem) [![buddy pipeline](https://app.buddy.works/eried/portapack/pipelines/pipeline/252276/badge.svg?token=48cd59d53de0589a8fbe26bc751d77a59a011cf72581da049343879402991c34 "buddy pipeline")](https://app.buddy.works/eried/portapack/pipelines/pipeline/252276) [![CodeScene Code Health](https://codescene.io/projects/8381/status-badges/code-health)](https://codescene.io/projects/8381) [![GitHub All Releases](https://img.shields.io/github/downloads/eried/portapack-mayhem/total)](https://github.com/eried/portapack-mayhem/releases) [![GitHub Releases](https://img.shields.io/github/downloads/eried/portapack-mayhem/latest/total)](https://github.com/eried/portapack-mayhem/releases/latest) [![Docker Hub Pulls](https://img.shields.io/docker/pulls/eried/portapack.svg)](https://hub.docker.com/r/eried/portapack) [![Discord Chat](https://img.shields.io/discord/719669764804444213.svg)](https://discord.gg/tuwVMv3) [![Check bounties!](https://img.shields.io/bountysource/team/portapack-mayhem/activity?color=%2333ccff&label=bountysource%20%28USD%29&style=plastic)](https://www.bountysource.com/teams/portapack-mayhem/issues)
[![Discord Chat](https://img.shields.io/discord/719669764804444213.svg)](https://discord.gg/fU9PsKW)
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. 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/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)
*[PortaPack H2](https://s.click.aliexpress.com/e/_dSMPvNo) (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/_dZ7lA96) (clone) with a custom [3d printed case](https://github.com/eried/portapack-mayhem/wiki/H2-Enclosure)*
# Quick overview # Quick overview
@ -21,7 +20,7 @@ This repository expands upon the previous work by many people and aims to consta
## Does it work on H1/H2 PortaPack? ## Does it work on H1/H2 PortaPack?
Yes, both devices are the [same](https://github.com/eried/portapack-mayhem/wiki/First-steps). The one I am using to test all changes is this [PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_dSMPvNo), which is a kit that includes everything you need. Sadly, the people making the H2 never made the updated schematics available, which is not ideal (and goes against the terms of the license). Yes, both devices are the [same](https://github.com/eried/portapack-mayhem/wiki/First-steps). The one I am using to test all changes is this [PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_dZ7lA96), which is a kit that includes everything you need. Sadly, the people making the H2 never made the updated schematics available, which is not ideal (and goes against the terms of the license). Most members of the community are using a clone of the [PortaPack H1+HackRF+metal case](https://s.click.aliexpress.com/e/_dS6liw4), which does not include any battery functionality, but it is a cheaper alternative.
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). 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).
@ -46,16 +45,21 @@ This fork (**Mayhem**) uses *major.minor.release* [semantic versioning](https://
## How can I collaborate ## 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/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.
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 colaborating your time and effort first. For coding related questions, if something does not fit as an issue, please join our [Channel in Discord](https://discord.gg/fU9PsKW). 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 colaborating 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).
As a last option, if you want to send money directly to me for getting more boards, antennas and such: As a last option, if you want to send money directly to me for getting more boards, antennas and such:
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CBPQA4HRRPJQ6&source=url) [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CBPQA4HRRPJQ6&source=url)
## What if I really want to pay for something?
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).
Promote your bounty over our Discord by clicking the chat badge on [top](#portapack-mayhem).
## What if I need help? ## 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/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).
You can reach the [official community](https://www.facebook.com/groups/177623356165819) in Facebook. 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).
## What if I find incongruencies, or grammatical errors in the text? ## What if I find incongruencies, or grammatical errors in the text?
If is on the [Wiki](https://github.com/eried/portapack-mayhem/wiki), you can modify it directly. If is on files of the repository, you can send corrections as [pull requests](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate#coding-new-stuff-or-fixing-bugs). As a last resource, open an [issue](https://github.com/eried/portapack-mayhem/issues/new/choose). If is on the [Wiki](https://github.com/eried/portapack-mayhem/wiki), you can modify it directly. If is on files of the repository, you can send corrections as [pull requests](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate#coding-new-stuff-or-fixing-bugs). As a last resource, open an [issue](https://github.com/eried/portapack-mayhem/issues/new/choose).

View File

@ -214,7 +214,7 @@ set(CPPSRC
ui/ui_tabview.cpp ui/ui_tabview.cpp
ui/ui_textentry.cpp ui/ui_textentry.cpp
ui/ui_transmitter.cpp ui/ui_transmitter.cpp
apps/ui_about.cpp apps/ui_about_simple.cpp
apps/ui_adsb_rx.cpp apps/ui_adsb_rx.cpp
apps/ui_adsb_tx.cpp apps/ui_adsb_tx.cpp
apps/ui_afsk_rx.cpp apps/ui_afsk_rx.cpp

View File

@ -0,0 +1,75 @@
#include "ui_about_simple.hpp"
namespace ui
{
AboutView::AboutView(NavigationView &nav)
{
add_children({&console, &button_ok});
button_ok.on_select = [&nav](Button &) {
nav.pop();
};
console.writeln("\x1B\x07List of contributors:\x1B\x10");
console.writeln("");
}
void AboutView::update()
{
if (++timer > 200)
{
timer = 0;
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
console.writeln("\x1B\x06Mayhem:\x1B\x10");
console.writeln("eried,euquiq,gregoryfenton");
console.writeln("johnelder,jwetzell,nnemanjan00");
console.writeln("N0vaPixel,klockee,jamesshao8");
console.writeln("");
break;
case 2:
// https://github.com/eried/portapack-mayhem/graphs/contributors?to=2020-04-12&from=2015-07-31&type=c
console.writeln("\x1B\x06Havoc:\x1B\x10");
console.writeln("furrtek,mrmookie,notpike");
console.writeln("mjwaxios,ImDroided,Giorgiofox");
console.writeln("F4GEV,z4ziggy,xmycroftx");
console.writeln("troussos,silascutler");
console.writeln("nickbouwhuis,msoose,leres");
console.writeln("joakar,dhoetger,clem-42");
console.writeln("brianlechthaler,ZeroChaos-...");
console.writeln("");
break;
case 3:
// https://github.com/eried/portapack-mayhem/graphs/contributors?from=2014-07-05&to=2015-07-31&type=c
console.writeln("\x1B\x06PortaPack:\x1B\x10");
console.writeln("jboone,argilo");
console.writeln("");
break;
case 4:
// https://github.com/mossmann/hackrf/graphs/contributors
console.writeln("\x1B\x06HackRF:\x1B\x10");
console.writeln("mossmann,dominicgs,bvernoux");
console.writeln("bgamari,schneider42,miek");
console.writeln("willcode,hessu,Sec42");
console.writeln("yhetti,ckuethe,smunaut");
console.writeln("wishi,mrbubble62,scateu...");
console.writeln("");
frame = 0; // Loop
break;
}
}
}
void AboutView::focus()
{
button_ok.focus();
}
} /* namespace ui */

View File

@ -0,0 +1,40 @@
#ifndef __UI_ABOUT_SIMPLE_H__
#define __UI_ABOUT_SIMPLE_H__
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include <cstdint>
namespace ui
{
class AboutView : public View
{
public:
AboutView(NavigationView &nav);
void focus() override;
std::string title() const override { return "About"; };
int32_t timer{180};
short frame{0};
private:
void update();
Console console{
{0, 10, 240, 240}};
Button button_ok{
{240/3, 270, 240/3, 24},
"OK",
};
MessageHandlerRegistration message_handler_update{
Message::ID::DisplayFrameSync,
[this](const Message *const) {
this->update();
}};
};
} // namespace ui
#endif /*__UI_ABOUT_SIMPLE_H__*/

View File

@ -92,31 +92,37 @@ FileManBaseView::FileManBaseView(
) : nav_ (nav), ) : nav_ (nav),
extension_filter { filter } extension_filter { filter }
{ {
load_directory_contents(current_path);
if (!entry_list.size())
empty_root = true;
add_children({ add_children({
&labels, &labels,
&text_current, &text_current,
&button_exit &button_exit
}); });
menu_view.on_left = [&nav, this]() {
load_directory_contents(get_parent_dir());
refresh_list();
};
button_exit.on_select = [this, &nav](Button&) { button_exit.on_select = [this, &nav](Button&) {
nav.pop(); nav.pop();
}; };
};
if (!sdcIsCardInserted(&SDCD1)) {
empty_root=true;
text_current.set("NO SD CARD!");
} else {
load_directory_contents(current_path);
if (!entry_list.size())
{
empty_root = true;
text_current.set("EMPTY SD CARD!");
} else {
menu_view.on_left = [&nav, this]() {
load_directory_contents(get_parent_dir());
refresh_list();
};
}
}
}
void FileManBaseView::focus() { void FileManBaseView::focus() {
if (empty_root) { if (empty_root) {
button_exit.focus(); button_exit.focus();
nav_.display_modal("Error", "No files in root.", ABORT, nullptr);
} else { } else {
menu_view.focus(); menu_view.focus();
} }
@ -190,7 +196,6 @@ void FileManBaseView::refresh_list() {
nav_.pop(); nav_.pop();
}); });
} }
FileSaveView::FileSaveView( FileSaveView::FileSaveView(
NavigationView& nav NavigationView& nav
) : FileManBaseView(nav) ) : FileManBaseView(nav)
@ -244,7 +249,11 @@ FileLoadView::FileLoadView(
void FileManagerView::on_rename(NavigationView& nav) { void FileManagerView::on_rename(NavigationView& nav) {
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) { text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
rename_file(get_selected_path(), buffer); std::string destination_path = current_path.string();
if (destination_path.back() != '/')
destination_path += '/';
destination_path = destination_path + buffer;
rename_file(get_selected_path(), destination_path);
load_directory_contents(current_path); load_directory_contents(current_path);
refresh_list(); refresh_list();
}); });
@ -271,57 +280,59 @@ FileManagerView::FileManagerView(
NavigationView& nav NavigationView& nav
) : FileManBaseView(nav, "") ) : FileManBaseView(nav, "")
{ {
on_refresh_widgets = [this](bool v) { if (!empty_root) {
refresh_widgets(v); on_refresh_widgets = [this](bool v) {
}; refresh_widgets(v);
};
add_children({ add_children({
&menu_view, &menu_view,
&labels, &labels,
&text_date, &text_date,
&button_rename, &button_rename,
&button_new_dir, &button_new_dir,
&button_delete &button_delete
});
menu_view.on_highlight = [this]() {
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_path())));
};
refresh_list();
on_select_entry = [this]() {
if (entry_list[menu_view.highlighted_index()].is_directory) {
load_directory_contents(get_selected_path());
refresh_list();
} else
button_rename.focus();
};
button_new_dir.on_select = [this, &nav](Button&) {
name_buffer.clear();
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
make_new_directory(current_path.string() + '/' + buffer);
load_directory_contents(current_path);
refresh_list();
}); });
};
button_rename.on_select = [this, &nav](Button&) { menu_view.on_highlight = [this]() {
name_buffer = entry_list[menu_view.highlighted_index()].entry_path.filename().string().substr(0, max_filename_length); text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_path())));
on_rename(nav); };
};
button_delete.on_select = [this, &nav](Button&) { refresh_list();
// Use display_modal ?
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted_index()].entry_path.filename().string() + "\nAre you sure?", YESNO, on_select_entry = [this]() {
[this](bool choice) { if (entry_list[menu_view.highlighted_index()].is_directory) {
if (choice) load_directory_contents(get_selected_path());
on_delete(); refresh_list();
} } else
); button_rename.focus();
}; };
button_new_dir.on_select = [this, &nav](Button&) {
name_buffer.clear();
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
make_new_directory(current_path.string() + '/' + buffer);
load_directory_contents(current_path);
refresh_list();
});
};
button_rename.on_select = [this, &nav](Button&) {
name_buffer = entry_list[menu_view.highlighted_index()].entry_path.filename().string().substr(0, max_filename_length);
on_rename(nav);
};
button_delete.on_select = [this, &nav](Button&) {
// Use display_modal ?
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted_index()].entry_path.filename().string() + "\nAre you sure?", YESNO,
[this](bool choice) {
if (choice)
on_delete();
}
);
};
}
} }
} }

View File

@ -54,7 +54,7 @@ SondeView::SondeView(NavigationView& nav) {
}); });
field_frequency.set_value(target_frequency_); field_frequency.set_value(target_frequency_);
field_frequency.set_step(10000); field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning
field_frequency.on_change = [this](rf::Frequency f) { field_frequency.on_change = [this](rf::Frequency f) {
set_target_frequency(f); set_target_frequency(f);
field_frequency.set_value(f); field_frequency.set_value(f);
@ -86,11 +86,11 @@ SondeView::SondeView(NavigationView& nav) {
button_see_map.on_select = [this, &nav](Button&) { button_see_map.on_select = [this, &nav](Button&) {
nav.push<GeoMapView>( nav.push<GeoMapView>(
"", sonde_id,
altitude, gps_info.alt,
GeoPos::alt_unit::METERS, GeoPos::alt_unit::METERS,
latitude, gps_info.lat,
longitude, gps_info.lon,
999); //set a dummy heading out of range to draw a cross...probably not ideal? 999); //set a dummy heading out of range to draw a cross...probably not ideal?
}; };
@ -113,16 +113,15 @@ void SondeView::on_packet(const sonde::Packet& packet) {
//const auto hex_formatted = packet.symbols_formatted(); //const auto hex_formatted = packet.symbols_formatted();
text_signature.set(packet.type_string()); text_signature.set(packet.type_string());
text_serial.set(packet.serial_number()); sonde_id = packet.serial_number(); //used also as tag on the geomap
text_serial.set(sonde_id);
text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V"); text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V");
altitude = packet.GPS_altitude(); gps_info = packet.get_GPS_data();
latitude = packet.GPS_latitude();
longitude = packet.GPS_longitude();
geopos.set_altitude(altitude); geopos.set_altitude(gps_info.alt);
geopos.set_lat(latitude); geopos.set_lat(gps_info.lat);
geopos.set_lon(longitude); geopos.set_lon(gps_info.lon);
if (logger && logging) { if (logger && logging) {
logger->on_packet(packet); logger->on_packet(packet);

View File

@ -65,11 +65,10 @@ public:
private: private:
std::unique_ptr<SondeLogger> logger { }; std::unique_ptr<SondeLogger> logger { };
uint32_t target_frequency_ { 402000000 }; uint32_t target_frequency_ { 402700000 };
bool logging { false }; bool logging { false };
int32_t altitude { 0 }; sonde::GPS_data gps_info;
float latitude { 0 }; std::string sonde_id;
float longitude { 0 };
Labels labels { Labels labels {
{ { 0 * 8, 2 * 16 }, "Signature:", Color::light_grey() }, { { 0 * 8, 2 * 16 }, "Signature:", Color::light_grey() },

File diff suppressed because it is too large Load Diff

View File

@ -95,6 +95,15 @@ void BtnGridView::set_parent_rect(const Rect new_parent_rect) {
update_items(); update_items();
} }
void BtnGridView::set_arrow_enabled(bool new_value) {
if(new_value){
add_child(&arrow_more);
}
else{
remove_child(&arrow_more);
}
};
void BtnGridView::on_tick_second() { void BtnGridView::on_tick_second() {
if (more && blink) if (more && blink)
arrow_more.set_foreground(Color::white()); arrow_more.set_foreground(Color::white());

View File

@ -62,6 +62,7 @@ public:
uint32_t highlighted_index(); uint32_t highlighted_index();
void set_parent_rect(const Rect new_parent_rect) override; void set_parent_rect(const Rect new_parent_rect) override;
void set_arrow_enabled(bool new_value);
void on_focus() override; void on_focus() override;
void on_blur() override; void on_blur() override;
bool on_key(const KeyEvent event) override; bool on_key(const KeyEvent event) override;

View File

@ -120,8 +120,8 @@ void FrequencyScale::paint(Painter& painter) {
if (_blink) { if (_blink) {
const Rect r_cursor { const Rect r_cursor {
120 + cursor_position, r.bottom() - filter_band_height, 118 + cursor_position, r.bottom() - filter_band_height,
2, filter_band_height 5, filter_band_height
}; };
painter.fill_rectangle( painter.fill_rectangle(
r_cursor, r_cursor,

View File

@ -30,7 +30,7 @@
#include "bmp_modal_warning.hpp" #include "bmp_modal_warning.hpp"
#include "portapack_persistent_memory.hpp" #include "portapack_persistent_memory.hpp"
#include "ui_about.hpp" #include "ui_about_simple.hpp"
#include "ui_adsb_rx.hpp" #include "ui_adsb_rx.hpp"
#include "ui_adsb_tx.hpp" #include "ui_adsb_tx.hpp"
#include "ui_afsk_rx.hpp" #include "ui_afsk_rx.hpp"
@ -106,6 +106,7 @@ SystemStatusView::SystemStatusView(
&backdrop, &backdrop,
&button_back, &button_back,
&title, &title,
&button_title,
&button_speaker, &button_speaker,
&button_stealth, &button_stealth,
//&button_textentry, //&button_textentry,
@ -139,6 +140,10 @@ SystemStatusView::SystemStatusView(
this->on_back(); this->on_back();
}; };
button_title.on_select = [this](ImageButton&) {
this->on_title();
};
button_speaker.on_select = [this](ImageButton&) { button_speaker.on_select = [this](ImageButton&) {
this->on_speaker(); this->on_speaker();
}; };
@ -194,8 +199,23 @@ void SystemStatusView::refresh() {
} }
void SystemStatusView::set_back_enabled(bool new_value) { void SystemStatusView::set_back_enabled(bool new_value) {
button_back.set_foreground(new_value ? Color::white() : Color::dark_grey());
button_back.set_focusable(new_value); if(new_value){
add_child(&button_back);
}
else{
remove_child(&button_back);
}
}
void SystemStatusView::set_title_image_enabled(bool new_value) {
if(new_value){
add_child(&button_title);
}
else{
remove_child(&button_title);
}
} }
void SystemStatusView::set_title(const std::string new_value) { void SystemStatusView::set_title(const std::string new_value) {
@ -282,6 +302,39 @@ void SystemStatusView::on_camera() {
} }
} }
void SystemStatusView::on_title() {
if(nav_.is_top())
nav_.push<AboutView>();
else
nav_.pop();
}
/* Information View *****************************************************/
InformationView::InformationView(
NavigationView& nav
) : nav_ (nav)
{
static constexpr Style style_infobar {
.font = font::fixed_8x16,
.background = {33, 33, 33},
.foreground = Color::white(),
};
add_children({
&backdrop,
&version,
&ltime
});
version.set_style(&style_infobar);
ltime.set_style(&style_infobar);
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(false);
set_dirty();
}
/* Navigation ************************************************************/ /* Navigation ************************************************************/
bool NavigationView::is_top() const { bool NavigationView::is_top() const {
@ -383,7 +436,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
add_items({ add_items({
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
{ "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, }, { "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, }, //{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
{ "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } }, { "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
{ "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } }, { "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } },
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } }, { "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
@ -392,7 +445,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } }, { "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } }, { "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
{ "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } }, { "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } }, { "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
/*{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } }, /*{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
{ "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } }, { "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
@ -478,6 +531,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
//{ "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push<AboutView>(); } } //{ "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push<AboutView>(); } }
}); });
set_max_rows(2); // allow wider buttons set_max_rows(2); // allow wider buttons
set_arrow_enabled(false);
//set_highlighted(1); // Startup selection //set_highlighted(1); // Startup selection
} }
@ -498,6 +552,7 @@ SystemView::SystemView(
set_style(&style_default); set_style(&style_default);
constexpr ui::Dim status_view_height = 16; constexpr ui::Dim status_view_height = 16;
constexpr ui::Dim info_view_height = 16;
add_child(&status_view); add_child(&status_view);
status_view.set_parent_rect({ status_view.set_parent_rect({
@ -513,11 +568,30 @@ SystemView::SystemView(
{ 0, status_view_height }, { 0, status_view_height },
{ parent_rect.width(), static_cast<ui::Dim>(parent_rect.height() - status_view_height) } { parent_rect.width(), static_cast<ui::Dim>(parent_rect.height() - status_view_height) }
}); });
add_child(&info_view);
info_view.set_parent_rect({
{0, 19 * 16},
{ parent_rect.width(), info_view_height }
});
navigation_view.on_view_changed = [this](const View& new_view) { navigation_view.on_view_changed = [this](const View& new_view) {
if(!this->navigation_view.is_top()){
remove_child(&info_view);
}
else{
add_child(&info_view);
}
this->status_view.set_back_enabled(!this->navigation_view.is_top()); this->status_view.set_back_enabled(!this->navigation_view.is_top());
this->status_view.set_title_image_enabled(this->navigation_view.is_top());
this->status_view.set_title(new_view.title()); this->status_view.set_title(new_view.title());
this->status_view.set_dirty();
}; };
// portapack::persistent_memory::set_playdead_sequence(0x8D1); // portapack::persistent_memory::set_playdead_sequence(0x8D1);
// Initial view // Initial view
@ -530,6 +604,9 @@ SystemView::SystemView(
if (portapack::persistent_memory::config_splash()) if (portapack::persistent_memory::config_splash())
navigation_view.push<BMPView>(); navigation_view.push<BMPView>();
status_view.set_back_enabled(false);
status_view.set_title_image_enabled(true);
status_view.set_dirty();
//else //else
// navigation_view.push<SystemMenuView>(); // navigation_view.push<SystemMenuView>();

View File

@ -106,10 +106,11 @@ public:
SystemStatusView(NavigationView& nav); SystemStatusView(NavigationView& nav);
void set_back_enabled(bool new_value); void set_back_enabled(bool new_value);
void set_title_image_enabled(bool new_value);
void set_title(const std::string new_value); void set_title(const std::string new_value);
private: private:
static constexpr auto default_title = "MAYHEM v1.1.1"; // TODO: Move the version somewhere static constexpr auto default_title = "";
NavigationView& nav_; NavigationView& nav_;
@ -130,6 +131,13 @@ private:
default_title, default_title,
}; };
ImageButton button_title {
{2, 0, 80, 16},
&bitmap_titlebar_image,
Color::white(),
Color::dark_grey()
};
ImageButton button_speaker { ImageButton button_speaker {
{ 17 * 8, 0, 2 * 8, 1 * 16 }, { 17 * 8, 0, 2 * 8, 1 * 16 },
&bitmap_icon_speaker_mute, &bitmap_icon_speaker_mute,
@ -188,6 +196,7 @@ private:
void on_bias_tee(); void on_bias_tee();
//void on_textentry(); //void on_textentry();
void on_camera(); void on_camera();
void on_title();
void refresh(); void refresh();
MessageHandlerRegistration message_handler_refresh { MessageHandlerRegistration message_handler_refresh {
@ -199,6 +208,29 @@ private:
}; };
}; };
class InformationView : public View {
public:
InformationView(NavigationView& nav);
private:
static constexpr auto version_string = "v1.1.1";
NavigationView& nav_;
Rectangle backdrop {
{ 0, 0 * 16, 240, 16 },
{33, 33, 33}
};
Text version {
{2, 0, 11 * 8, 16},
version_string
};
LiveDateTime ltime {
{174, 0, 8 * 8, 16}
};
};
class BMPView : public View { class BMPView : public View {
public: public:
BMPView(NavigationView& nav); BMPView(NavigationView& nav);
@ -253,6 +285,7 @@ public:
private: private:
SystemStatusView status_view { navigation_view }; SystemStatusView status_view { navigation_view };
InformationView info_view { navigation_view };
NavigationView navigation_view { }; NavigationView navigation_view { };
Context& context_; Context& context_;
}; };

View File

@ -140,7 +140,8 @@ private:
} }
}; };
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_fsk_4800_Vaisala { PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_fsk_4800_Vaisala {
{ 0b00001000011011010101001110001000, 32, 1 }, { 0b00001000011011010101001110001000, 32, 1 }, //euquiq Header detects 4 of 8 bytes 0x10B6CA11 /this is in raw format) (these bits are not passed at the beginning of packet)
//{ 0b0000100001101101010100111000100001000100011010010100100000011111, 64, 1 }, //euquiq whole header detection would be 8 bytes.
{ }, { },
{ 320 * 8 }, { 320 * 8 },
[this](const baseband::Packet& packet) { [this](const baseband::Packet& packet) {

View File

@ -22,9 +22,25 @@
#include "sonde_packet.hpp" #include "sonde_packet.hpp"
#include "string_format.hpp" #include "string_format.hpp"
#include <cstring>
//#include <complex>
namespace sonde { namespace sonde {
//Defines for Vaisala RS41, from https://github.com/rs1729/RS/blob/master/rs41/rs41sg.c
#define MASK_LEN 64
#define pos_FrameNb 0x37 //0x03B // 2 byte
#define pos_SondeID 0x39 //0x03D // 8 byte
#define pos_Voltage 0x041 //0x045 // 3 bytes (but first one is the important one) voltage x 10 ie: 26 = 2.6v
#define pos_CalData 0x04E //0x052 // 1 byte, counter 0x00..0x32
#define pos_GPSweek 0x091 //0x095 // 2 byte
#define pos_GPSTOW 0x093 //0x097 // 4 byte
#define pos_GPSecefX 0x110 //0x114 // 4 byte
#define pos_GPSecefY 0x114 //0x118 // 4 byte (not actually used since Y and Z are following X, and grabbed in that same loop)
#define pos_GPSecefZ 0x118 //0x11C // 4 byte (same as Y)
#define PI 3.1415926535897932384626433832795 //3.1416 //(3.1415926535897932384626433832795)
Packet::Packet( Packet::Packet(
const baseband::Packet& packet, const baseband::Packet& packet,
const Type type const Type type
@ -60,37 +76,65 @@ Packet::Type Packet::type() const {
return type_; return type_;
} }
/*uint8_t Packet::vaisala_descramble(const uint32_t pos) { //euquiq here:
return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63]; //RS41SG 320 bits header, 320bytes frame (or more if it is an "extended frame")
};*/ //The raw data is xor-scrambled with the values in the 64 bytes vaisala_mask (see.hpp)
uint32_t Packet::GPS_altitude() const {
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
return (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
else if (type_ == Type::Vaisala_RS41_SG) {
/*uint32_t altitude_ecef = 0;
for (uint32_t i = 0; i < 4; i++)
altitude_ecef = (altitude_ecef << 8) + vaisala_descramble(0x11C + i);*/
// TODO: and a bunch of maths (see ecef2elli() from RS1729)
return 0;
} else
return 0; // Unknown
}
float Packet::GPS_latitude() const { uint8_t Packet::vaisala_descramble(const uint32_t pos) const {
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2)) //return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];
return reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0); // packet_[i]; its a bit; packet_.size the total (should be 2560 bits)
//else if (type_ == Type::Vaisala_RS41_SG) uint8_t value = 0;
// return vaisala_descramble(); for (uint8_t i = 0; i < 8; i++)
else value = (value << 1) | packet_[(pos * 8) + (7 -i)]; //get the byte from the bits collection
return 0; // Unknown
}
float Packet::GPS_longitude() const { //packetReader reader { packet_ }; //This works just as above.
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2)) //value = reader.read(pos * 8,8);
return reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0); //shift pos because first 4 bytes are consumed by proc_sonde in finding the vaisala signature
else uint32_t mask_pos = pos + 4;
return 0; // Unknown value = value ^ vaisala_mask[mask_pos % MASK_LEN]; //descramble with the xor pseudorandom table
return value;
};
GPS_data Packet::get_GPS_data() const {
GPS_data result;
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2)) {
result.alt = (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
result.lat = reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
result.lon = reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
} else if (type_ == Type::Vaisala_RS41_SG) {
uint8_t XYZ_bytes[4];
int32_t XYZ; // 32bit
double_t X[3];
for (int32_t k = 0; k < 3; k++) { //Get X,Y,Z ECEF position from GPS
for (int32_t i = 0; i < 4; i++) //each one is 4 bytes (32 bits)
XYZ_bytes[i] = vaisala_descramble(pos_GPSecefX + (4*k) + i);
memcpy(&XYZ, XYZ_bytes, 4);
X[k] = XYZ / 100.0;
}
double_t a = 6378137.0;
double_t b = 6356752.31424518;
double_t e = sqrt( (a*a - b*b) / (a*a) );
double_t ee = sqrt( (a*a - b*b) / (b*b) );
double_t lam = atan2( X[1] , X[0] );
double_t p = sqrt( X[0]*X[0] + X[1]*X[1] );
double_t t = atan2( X[2]*a , p*b );
double_t phi = atan2( X[2] + ee*ee * b * sin(t)*sin(t)*sin(t) ,
p - e*e * a * cos(t)*cos(t)*cos(t) );
double_t R = a / sqrt( 1 - e*e*sin(phi)*sin(phi) );
result.alt = p / cos(phi) - R;
result.lat = phi*180/PI;
result.lon = lam*180/PI;
}
return result;
} }
uint32_t Packet::battery_voltage() const { uint32_t Packet::battery_voltage() const {
@ -98,8 +142,13 @@ uint32_t Packet::battery_voltage() const {
return (reader_bi_m.read(69 * 8, 8) + (reader_bi_m.read(70 * 8, 8) << 8)) * 1000 / 150; return (reader_bi_m.read(69 * 8, 8) + (reader_bi_m.read(70 * 8, 8) << 8)) * 1000 / 150;
else if (type_ == Type::Meteomodem_M2K2) else if (type_ == Type::Meteomodem_M2K2)
return reader_bi_m.read(69 * 8, 8) * 66; // Actually 65.8 return reader_bi_m.read(69 * 8, 8) * 66; // Actually 65.8
else else if (type_ == Type::Vaisala_RS41_SG) {
uint32_t voltage = vaisala_descramble(pos_Voltage) * 100; //byte 69 = voltage * 10 (check if this value needs to be multiplied)
return voltage;
}
else {
return 0; // Unknown return 0; // Unknown
}
} }
std::string Packet::type_string() const { std::string Packet::type_string() const {
@ -127,12 +176,33 @@ std::string Packet::serial_number() const {
to_string_dec_uint(reader_bi_m.read(93 * 8 + 24, 3), 1) + to_string_dec_uint(reader_bi_m.read(93 * 8 + 24, 3), 1) +
to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0'); to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0');
} else if(type() == Type::Vaisala_RS41_SG) {
std::string serial_id = "";
uint8_t achar;
for (uint8_t i=0; i<8; i++) { //euquiq: Serial ID is 8 bytes long, each byte a char
achar = vaisala_descramble(pos_SondeID + i);
if (achar < 32 || achar > 126) return "?"; //Maybe there are ids with less than 8 bytes and this is not OK.
serial_id += (char)achar;
}
return serial_id;
} else } else
return "?"; return "?";
} }
FormattedSymbols Packet::symbols_formatted() const { FormattedSymbols Packet::symbols_formatted() const {
return format_symbols(decoder_); if (type() == Type::Vaisala_RS41_SG) { //Euquiq: now we distinguish different types
uint32_t bytes = packet_.size() / 8; //Need the byte amount, which if full, it SHOULD be 320 size() should return 2560
std::string hex_data;
std::string hex_error;
hex_data.reserve(bytes * 2); //2 hexa chars per byte
hex_error.reserve(1);
for (uint32_t i=0; i < bytes; i++) //log will show the packet starting on the last 4 bytes from signature 93DF1A60
hex_data += to_string_hex(vaisala_descramble(i),2);
return { hex_data, hex_error };
} else {
return format_symbols(decoder_);
}
} }
bool Packet::crc_ok() const { bool Packet::crc_ok() const {

View File

@ -32,6 +32,12 @@
namespace sonde { namespace sonde {
struct GPS_data {
uint32_t alt { 0 };
float lat { 0 };
float lon { 0 };
};
class Packet { class Packet {
public: public:
enum class Type : uint32_t { enum class Type : uint32_t {
@ -56,9 +62,7 @@ public:
std::string serial_number() const; std::string serial_number() const;
uint32_t battery_voltage() const; uint32_t battery_voltage() const;
uint32_t GPS_altitude() const; GPS_data get_GPS_data() const;
float GPS_latitude() const;
float GPS_longitude() const;
FormattedSymbols symbols_formatted() const; FormattedSymbols symbols_formatted() const;
@ -76,13 +80,16 @@ private:
0x78, 0x6E, 0x3B, 0xAE, 0xBF, 0x7B, 0x4C, 0xC1 0x78, 0x6E, 0x3B, 0xAE, 0xBF, 0x7B, 0x4C, 0xC1
}; };
//uint8_t vaisala_descramble(const uint32_t pos); GPS_data ecef_to_gps() const;
uint8_t vaisala_descramble(uint32_t pos) const;
const baseband::Packet packet_; const baseband::Packet packet_;
const BiphaseMDecoder decoder_; const BiphaseMDecoder decoder_;
const FieldReader<BiphaseMDecoder, BitRemapNone> reader_bi_m; const FieldReader<BiphaseMDecoder, BitRemapNone> reader_bi_m;
Type type_; Type type_;
using packetReader = FieldReader<baseband::Packet, BitRemapByteReverse>; //baseband::Packet instead of BiphaseMDecoder
bool crc_ok_M10() const; bool crc_ok_M10() const;
}; };

View File

@ -409,10 +409,26 @@ void Labels::paint(Painter& painter) {
void LiveDateTime::on_tick_second() { void LiveDateTime::on_tick_second() {
rtcGetTime(&RTCD1, &datetime); rtcGetTime(&RTCD1, &datetime);
text = "";
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " + if(date_enabled){
to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'); text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " ";
}
text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
if(seconds_enabled){
text += ":";
if(init_delay==0)
text += to_string_dec_uint(datetime.second(), 2, '0');
else
{
// Placeholder while the seconds are not updated
text += "XX";
init_delay--;
}
}
set_dirty(); set_dirty();
} }
@ -444,6 +460,14 @@ void LiveDateTime::paint(Painter& painter) {
); );
} }
void LiveDateTime::set_date_enabled(bool new_value){
this->date_enabled = new_value;
}
void LiveDateTime::set_seconds_enabled(bool new_value) {
this->seconds_enabled = new_value;
}
/* BigFrequency **********************************************************/ /* BigFrequency **********************************************************/
BigFrequency::BigFrequency( BigFrequency::BigFrequency(
@ -625,7 +649,8 @@ void Console::write(std::string message) {
void Console::writeln(std::string message) { void Console::writeln(std::string message) {
write(message); write(message);
crlf(); write("\n");
//crlf();
} }
void Console::paint(Painter&) { void Console::paint(Painter&) {

View File

@ -244,6 +244,9 @@ public:
void paint(Painter& painter) override; void paint(Painter& painter) override;
void set_seconds_enabled(bool new_value);
void set_date_enabled(bool new_value);
std::string& string() { std::string& string() {
return text; return text;
} }
@ -251,6 +254,10 @@ public:
private: private:
void on_tick_second(); void on_tick_second();
uint16_t init_delay = 4;
bool date_enabled = true;
bool seconds_enabled = false;
rtc::RTC datetime { }; rtc::RTC datetime { };
SignalToken signal_token_tick_second { }; SignalToken signal_token_tick_second { };
std::string text { }; std::string text { };

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB