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
[![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)
[![Discord Chat](https://img.shields.io/discord/719669764804444213.svg)](https://discord.gg/fU9PsKW)
[![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)
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)
*[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
@ -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?
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).
@ -46,16 +45,21 @@ This fork (**Mayhem**) uses *major.minor.release* [semantic versioning](https://
## 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.
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:
[![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?
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?
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_textentry.cpp
ui/ui_transmitter.cpp
apps/ui_about.cpp
apps/ui_about_simple.cpp
apps/ui_adsb_rx.cpp
apps/ui_adsb_tx.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),
extension_filter { filter }
{
load_directory_contents(current_path);
if (!entry_list.size())
empty_root = true;
add_children({
&labels,
&text_current,
&button_exit
});
menu_view.on_left = [&nav, this]() {
load_directory_contents(get_parent_dir());
refresh_list();
};
button_exit.on_select = [this, &nav](Button&) {
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() {
if (empty_root) {
button_exit.focus();
nav_.display_modal("Error", "No files in root.", ABORT, nullptr);
} else {
menu_view.focus();
}
@ -190,7 +196,6 @@ void FileManBaseView::refresh_list() {
nav_.pop();
});
}
FileSaveView::FileSaveView(
NavigationView& nav
) : FileManBaseView(nav)
@ -244,7 +249,11 @@ FileLoadView::FileLoadView(
void FileManagerView::on_rename(NavigationView& nav) {
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);
refresh_list();
});
@ -271,57 +280,59 @@ FileManagerView::FileManagerView(
NavigationView& nav
) : FileManBaseView(nav, "")
{
on_refresh_widgets = [this](bool v) {
refresh_widgets(v);
};
add_children({
&menu_view,
&labels,
&text_date,
&button_rename,
&button_new_dir,
&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();
if (!empty_root) {
on_refresh_widgets = [this](bool v) {
refresh_widgets(v);
};
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();
add_children({
&menu_view,
&labels,
&text_date,
&button_rename,
&button_new_dir,
&button_delete
});
};
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();
}
);
};
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&) {
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_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) {
set_target_frequency(f);
field_frequency.set_value(f);
@ -86,11 +86,11 @@ SondeView::SondeView(NavigationView& nav) {
button_see_map.on_select = [this, &nav](Button&) {
nav.push<GeoMapView>(
"",
altitude,
sonde_id,
gps_info.alt,
GeoPos::alt_unit::METERS,
latitude,
longitude,
gps_info.lat,
gps_info.lon,
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();
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");
gps_info = packet.get_GPS_data();
altitude = packet.GPS_altitude();
latitude = packet.GPS_latitude();
longitude = packet.GPS_longitude();
geopos.set_altitude(altitude);
geopos.set_lat(latitude);
geopos.set_lon(longitude);
geopos.set_altitude(gps_info.alt);
geopos.set_lat(gps_info.lat);
geopos.set_lon(gps_info.lon);
if (logger && logging) {
logger->on_packet(packet);

View File

@ -65,11 +65,10 @@ public:
private:
std::unique_ptr<SondeLogger> logger { };
uint32_t target_frequency_ { 402000000 };
uint32_t target_frequency_ { 402700000 };
bool logging { false };
int32_t altitude { 0 };
float latitude { 0 };
float longitude { 0 };
sonde::GPS_data gps_info;
std::string sonde_id;
Labels labels {
{ { 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();
}
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() {
if (more && blink)
arrow_more.set_foreground(Color::white());

View File

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

View File

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

View File

@ -30,7 +30,7 @@
#include "bmp_modal_warning.hpp"
#include "portapack_persistent_memory.hpp"
#include "ui_about.hpp"
#include "ui_about_simple.hpp"
#include "ui_adsb_rx.hpp"
#include "ui_adsb_tx.hpp"
#include "ui_afsk_rx.hpp"
@ -106,6 +106,7 @@ SystemStatusView::SystemStatusView(
&backdrop,
&button_back,
&title,
&button_title,
&button_speaker,
&button_stealth,
//&button_textentry,
@ -138,6 +139,10 @@ SystemStatusView::SystemStatusView(
if (this->on_back)
this->on_back();
};
button_title.on_select = [this](ImageButton&) {
this->on_title();
};
button_speaker.on_select = [this](ImageButton&) {
this->on_speaker();
@ -194,8 +199,23 @@ void SystemStatusView::refresh() {
}
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) {
@ -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 ************************************************************/
bool NavigationView::is_top() const {
@ -383,7 +436,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
add_items({
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
{ "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>(); } },
{ "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } },
{ "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>(); } },
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
{ "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>(); } },
/*{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&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>(); } }
});
set_max_rows(2); // allow wider buttons
set_arrow_enabled(false);
//set_highlighted(1); // Startup selection
}
@ -498,6 +552,7 @@ SystemView::SystemView(
set_style(&style_default);
constexpr ui::Dim status_view_height = 16;
constexpr ui::Dim info_view_height = 16;
add_child(&status_view);
status_view.set_parent_rect({
@ -513,11 +568,30 @@ SystemView::SystemView(
{ 0, 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) {
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_title_image_enabled(this->navigation_view.is_top());
this->status_view.set_title(new_view.title());
this->status_view.set_dirty();
};
// portapack::persistent_memory::set_playdead_sequence(0x8D1);
// Initial view
@ -530,6 +604,9 @@ SystemView::SystemView(
if (portapack::persistent_memory::config_splash())
navigation_view.push<BMPView>();
status_view.set_back_enabled(false);
status_view.set_title_image_enabled(true);
status_view.set_dirty();
//else
// navigation_view.push<SystemMenuView>();

View File

@ -106,10 +106,11 @@ public:
SystemStatusView(NavigationView& nav);
void set_back_enabled(bool new_value);
void set_title_image_enabled(bool new_value);
void set_title(const std::string new_value);
private:
static constexpr auto default_title = "MAYHEM v1.1.1"; // TODO: Move the version somewhere
static constexpr auto default_title = "";
NavigationView& nav_;
@ -130,6 +131,13 @@ private:
default_title,
};
ImageButton button_title {
{2, 0, 80, 16},
&bitmap_titlebar_image,
Color::white(),
Color::dark_grey()
};
ImageButton button_speaker {
{ 17 * 8, 0, 2 * 8, 1 * 16 },
&bitmap_icon_speaker_mute,
@ -188,6 +196,7 @@ private:
void on_bias_tee();
//void on_textentry();
void on_camera();
void on_title();
void 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 {
public:
BMPView(NavigationView& nav);
@ -253,6 +285,7 @@ public:
private:
SystemStatusView status_view { navigation_view };
InformationView info_view { navigation_view };
NavigationView navigation_view { };
Context& context_;
};

View File

@ -140,7 +140,8 @@ private:
}
};
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 },
[this](const baseband::Packet& packet) {

View File

@ -22,9 +22,25 @@
#include "sonde_packet.hpp"
#include "string_format.hpp"
#include <cstring>
//#include <complex>
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(
const baseband::Packet& packet,
const Type type
@ -60,37 +76,65 @@ Packet::Type Packet::type() const {
return type_;
}
/*uint8_t Packet::vaisala_descramble(const uint32_t pos) {
return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];
};*/
//euquiq here:
//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 {
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
return reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
//else if (type_ == Type::Vaisala_RS41_SG)
// return vaisala_descramble();
else
return 0; // Unknown
}
uint8_t Packet::vaisala_descramble(const uint32_t pos) const {
//return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];
// packet_[i]; its a bit; packet_.size the total (should be 2560 bits)
uint8_t value = 0;
for (uint8_t i = 0; i < 8; i++)
value = (value << 1) | packet_[(pos * 8) + (7 -i)]; //get the byte from the bits collection
float Packet::GPS_longitude() const {
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
return reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
else
return 0; // Unknown
//packetReader reader { packet_ }; //This works just as above.
//value = reader.read(pos * 8,8);
//shift pos because first 4 bytes are consumed by proc_sonde in finding the vaisala signature
uint32_t mask_pos = pos + 4;
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 {
@ -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;
else if (type_ == Type::Meteomodem_M2K2)
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
}
}
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 + 27, 13), 4, '0');
} else
} 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
return "?";
}
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 {

View File

@ -32,6 +32,12 @@
namespace sonde {
struct GPS_data {
uint32_t alt { 0 };
float lat { 0 };
float lon { 0 };
};
class Packet {
public:
enum class Type : uint32_t {
@ -41,7 +47,7 @@ public:
Meteomodem_M2K2 = 3,
Vaisala_RS41_SG = 4,
};
Packet(const baseband::Packet& packet, const Type type);
size_t length() const;
@ -56,9 +62,7 @@ public:
std::string serial_number() const;
uint32_t battery_voltage() const;
uint32_t GPS_altitude() const;
float GPS_latitude() const;
float GPS_longitude() const;
GPS_data get_GPS_data() const;
FormattedSymbols symbols_formatted() const;
@ -75,17 +79,20 @@ private:
0xD0, 0xBC, 0xB4, 0xB6, 0x06, 0xAA, 0xF4, 0x23,
0x78, 0x6E, 0x3B, 0xAE, 0xBF, 0x7B, 0x4C, 0xC1
};
GPS_data ecef_to_gps() const;
//uint8_t vaisala_descramble(const uint32_t pos);
uint8_t vaisala_descramble(uint32_t pos) const;
const baseband::Packet packet_;
const BiphaseMDecoder decoder_;
const FieldReader<BiphaseMDecoder, BitRemapNone> reader_bi_m;
Type type_;
using packetReader = FieldReader<baseband::Packet, BitRemapByteReverse>; //baseband::Packet instead of BiphaseMDecoder
bool crc_ok_M10() const;
};
} /* namespace sonde */
#endif/*__SONDE_PACKET_H__*/
#endif/*__SONDE_PACKET_H__*/

View File

@ -409,10 +409,26 @@ void Labels::paint(Painter& painter) {
void LiveDateTime::on_tick_second() {
rtcGetTime(&RTCD1, &datetime);
text = "";
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " +
to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
if(date_enabled){
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();
}
@ -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(
@ -625,7 +649,8 @@ void Console::write(std::string message) {
void Console::writeln(std::string message) {
write(message);
crlf();
write("\n");
//crlf();
}
void Console::paint(Painter&) {

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB