mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Merge branch 'v1.2' into add-heading-to-geomap
This commit is contained in:
commit
5a3da3bd6a
16
README.md
16
README.md
@ -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).
|
||||
|
@ -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
|
||||
|
75
firmware/application/apps/ui_about_simple.cpp
Normal file
75
firmware/application/apps/ui_about_simple.cpp
Normal 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 */
|
40
firmware/application/apps/ui_about_simple.hpp
Normal file
40
firmware/application/apps/ui_about_simple.hpp
Normal 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__*/
|
@ -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();
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
<ime
|
||||
});
|
||||
|
||||
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>();
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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__*/
|
@ -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&) {
|
||||
|
@ -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 { };
|
||||
|
BIN
firmware/graphics/titlebar_image.png
Normal file
BIN
firmware/graphics/titlebar_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
Loading…
Reference in New Issue
Block a user