Compare commits

..

11 Commits

Author SHA1 Message Date
gullradriel fc08d4ead9 renaming Ook to OOK (#2379) 2024-11-21 21:24:40 +01:00
Totoo 07cae4a298 Remove warn text too from batt (#2377) 2024-11-20 15:02:02 +01:00
sommermorgentraum e88e0b5f8f splash fix and draw bmp fuc logic wrong (#2376)
* revert

* rename drawBMP to draw_bmp_from_bmp_hex_arr

* rename drawBMP2

* add comments

* rename BMPView class in child of nav into SplashView

* rename SplashView class in child of nav into SplashScreeView

* fix draw from wrong line

* comment

* comment

* comment
2024-11-20 17:35:40 +08:00
Totoo 131523d726 Csv from subghzd (#2375) 2024-11-20 09:22:55 +01:00
gullradriel 24d15c1643 Externalize Remote (#2370)
* externalize Remote app, disabling fileman integration (need workaround)

* regenerate bitmap.hpp

* added external HOME apps to HOME
2024-11-19 21:02:29 +01:00
Totoo 4a83118557 Weather csv log (#2369) 2024-11-19 17:39:30 +01:00
gullradriel ff54f59d38 Ook Editor adjustements (#2366)
* adding ook_file.cpp

* aligned GUI, change low_bit to pause, start to use ook_file API

* bit duration, pause, fields step, indent

* working OOK file loading

* revamped GUI with the decided names and units

* read, start tx, stop tx in ook_file API

* cleanings, using ook_file_data and API to load, save, send, stop tx

* renamed text widget

* moved set target frequency to start_ook_file_tx function

* comments, took out a function to put it in API

* removed non working Tesla OOK files

* changed space to tab

* set author information

* Renamed to OOKEditor
2024-11-19 17:16:37 +01:00
Erwin Ried 6b8274d792 Update README.md
Direct link to opensourcesdrlabs device
2024-11-19 15:49:38 +01:00
Totoo 1fc84e7eac Hide cycles until 0 error resolved (#2367) 2024-11-19 11:23:33 +01:00
gullradriel d31857c21e Ook remote adjustements (#2365)
* moved to ook_remote dir

* moved to new filenames / dir

* adjusted build files to new dir/filenames

* changed name of var / dirname

* deleted wrongly included swap files

* Added 'Set' 'Open File'

* Use language API, make it so TX can be started and also stopped

* added send, recv

* fixed the name which was too long

* renamed some fields, moved the ui, added some text informations, renames some variables

* changed to FrequencyField, allow on change, on edit, commented out button_save for a next pass

* added OOK files examples

* added button_save feature
2024-11-18 14:51:49 +01:00
Erwin Ried 52b2cb241a Grabifyed link to opensdrlabs h4m 2024-11-18 09:55:48 +01:00
36 changed files with 1667 additions and 1068 deletions
+2 -1
View File
@@ -27,7 +27,8 @@ This repository expands upon the previous work by many people and aims to consta
## What to buy?
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous [PortaPack H4M Mayhem](https://opensourcesdrlab.com/products/h4m-receiver-and-spectrum-analyzer), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://grabify.link/99SAMT). Join their giveaways on discord (check the badge on top).
<!---not direct to h4m but to opensourcesdrlab https://grabify.link/TUOLYI--->
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous [PortaPack H4M Mayhem](https://grabify.link/0STXCA), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://grabify.link/99SAMT). Join their giveaways on discord (check the badge on top).
:heavy_check_mark: A recommended one is this [PortaPack H2](https://grabify.link/P9CO0J), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/3d-printed-enclosure).
+1 -1
View File
@@ -244,6 +244,7 @@ set(CPPSRC
hw/si5351.cpp
hw/spi_pp.cpp
hw/touch_adc.cpp
ook_file.cpp
ui_baseband_stats_view.cpp
ui_navigation.cpp
ui_record_view.cpp
@@ -302,7 +303,6 @@ set(CPPSRC
apps/ui_rds.cpp
apps/ui_recon_settings.cpp
apps/ui_recon.cpp
apps/ui_remote.cpp
apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp
apps/ui_sd_wipe.cpp
+13 -13
View File
@@ -50,10 +50,10 @@ void BattinfoView::update_result() {
text_voltage.set("UNKNOWN");
text_current.set("-");
text_charge.set("-");
text_cycles.set("-");
// text_cycles.set("-");
text_ttef.set("-");
text_method.set("-");
text_warn.set("");
// text_warn.set("");
return;
}
bool uichg = false;
@@ -96,22 +96,22 @@ void BattinfoView::update_result() {
labels_opt.hidden(true);
text_current.hidden(true);
text_charge.hidden(true);
text_cycles.hidden(true);
// text_cycles.hidden(true);
text_ttef.hidden(true);
text_warn.set("");
// text_warn.set("");
}
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
text_cycles.hidden(false);
uint16_t cycles = battery::BatteryManagement::get_cycles();
/* if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
// text_cycles.hidden(false);
uint16_t cycles = 0; // battery::BatteryManagement::get_cycles();
if (cycles < 2)
text_warn.set("SoC improves after 2 cycles");
text_warn.set("SoC improves after each cycles");
else
text_warn.set("");
text_cycles.set(to_string_dec_uint(cycles));
// text_cycles.set(to_string_dec_uint(cycles));
} else {
text_cycles.hidden(true);
// text_cycles.hidden(true);
text_warn.set("");
}
} */
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
text_ttef.hidden(false);
float ttef = 0;
@@ -160,8 +160,8 @@ BattinfoView::BattinfoView(NavigationView& nav)
&text_method,
&button_mode,
&button_exit,
&text_cycles,
&text_warn,
// &text_cycles,
// &text_warn,
&text_ttef});
button_exit.on_select = [this, &nav](Button&) {
+4 -4
View File
@@ -63,7 +63,7 @@ class BattinfoView : public View {
{{2 * 8, 4 * 16}, "Current:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 6 * 16}, "TTF/E:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
// {{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 10 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground},
};
@@ -85,13 +85,13 @@ class BattinfoView : public View {
Text text_ttef{
{13 * 8, 6 * 16, 10 * 16, 16},
"-"};
Text text_cycles{
/* Text text_cycles{
{13 * 8, 7 * 16, 10 * 16, 16},
"-"};
Text text_warn{
{2 * 8, 8 * 16, 30 * 8, 2 * 16},
""};
{1 * 8, 8 * 16, 30 * 8, 2 * 16},
""}; */
Button button_mode{
{2 * 8, 11 * 16 + 5, 5 * 16, 32},
+3 -3
View File
@@ -27,7 +27,6 @@
#include <algorithm>
#include "ui_fileman.hpp"
#include "ui_playlist.hpp"
#include "ui_remote.hpp"
#include "ui_ss_viewer.hpp"
#include "ui_bmp_file_viewer.hpp"
#include "ui_text_editor.hpp"
@@ -704,10 +703,11 @@ bool FileManagerView::handle_file_open() {
reload_current(false);
return true;
} else if (path_iequal(rem_ext, ext)) {
}
/*else if (path_iequal(rem_ext, ext)) {
nav_.push<RemoteView>(path);
return true;
}
}*/
return false;
}
+1 -1
View File
@@ -56,7 +56,7 @@ SIGFRXView::~SIGFRXView() {
void SIGFRXView::paint(Painter& painter) {
uint8_t i, xp;
// portapack::display.drawBMP({0, 302-160}, fox_bmp);
// portapack::display.draw_bmp_from_bmp_hex_arr({0, 302-160}, fox_bmp);
portapack::display.fill_rectangle({0, 16, 240, 160 - 16}, Theme::getInstance()->bg_darkest->foreground);
for (i = 0; i < 6; i++) {
xp = sigfrx_marks[i * 3];
+1 -1
View File
@@ -119,7 +119,7 @@ bool SplashViewer::on_key(const KeyEvent key) {
void SplashViewer::paint(Painter& painter) {
painter.fill_rectangle({0, 0, screen_width, screen_height}, Color::black());
if (!portapack::display.drawBMP2({0, 0}, path_)) {
if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, path_)) {
painter.draw_string({10, 160}, *Theme::getInstance()->bg_darkest, "Not a valid splash image.");
return;
}
+26 -1
View File
@@ -24,6 +24,7 @@
#include "audio.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
@@ -31,6 +32,18 @@ using namespace ui;
namespace ui {
std::string SubGhzDRecentEntry::to_csv() {
std::string csv = ";";
csv += SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)sensorType);
csv += ";" + to_string_dec_uint(bits) + ";";
csv += to_string_hex(data, 64 / 4);
return csv;
}
void SubGhzDLogger::log_data(SubGhzDRecentEntry& data) {
log_file.write_entry(data.to_csv());
}
void SubGhzDRecentEntryDetailView::update_data() {
// process protocol data
parseProtocol();
@@ -76,16 +89,25 @@ SubGhzDView::SubGhzDView(NavigationView& nav)
&field_vga,
&field_frequency,
&button_clear_list,
&check_log,
&recent_entries_view});
baseband::run_image(portapack::spi_flash::image_tag_subghzd);
logger = std::make_unique<SubGhzDLogger>();
button_clear_list.on_select = [this](Button&) {
recent.clear();
recent_entries_view.set_dirty();
};
field_frequency.set_step(10000);
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
if (logger && logging) {
logger->append(logs_dir.string() + "/SUBGHZDLOG_" + to_string_timestamp(rtc_time::now()) + ".CSV");
logger->write_header();
}
};
check_log.set_value(logging);
const Rect content_rect{0, header_height, screen_width, screen_height - header_height};
recent_entries_view.set_parent_rect(content_rect);
recent_entries_view.on_select = [this](const SubGhzDRecentEntry& entry) {
@@ -107,6 +129,9 @@ void SubGhzDView::on_tick_second() {
void SubGhzDView::on_data(const SubGhzDDataMessage* data) {
SubGhzDRecentEntry key{data->sensorType, data->data, data->bits};
if (logger && logging) {
logger->log_data(key);
}
auto matching_recent = find(recent, key.key());
if (matching_recent != std::end(recent)) {
// Found within. Move to front of list, increment counter.
+30 -1
View File
@@ -34,6 +34,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "log_file.hpp"
#include "recent_entries.hpp"
#include "../baseband/fprotos/subghztypes.hpp"
@@ -68,6 +69,23 @@ struct SubGhzDRecentEntry {
void reset_age() {
age = 0;
}
std::string to_csv();
};
class SubGhzDLogger {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
void log_data(SubGhzDRecentEntry& data);
void write_header() {
log_file.write_entry(";Type; Bits; Data;");
}
private:
LogFile log_file{};
};
using SubGhzDRecentEntries = RecentEntries<SubGhzDRecentEntry>;
using SubGhzDRecentEntriesView = RecentEntriesView<SubGhzDRecentEntries>;
@@ -93,10 +111,13 @@ class SubGhzDView : public View {
1'750'000 /* bandwidth */,
4'000'000 /* sampling rate */,
ReceiverModel::Mode::AMAudio};
bool logging = false;
app_settings::SettingsManager settings_{
"rx_subghzd",
app_settings::Mode::RX,
{}};
{
{"log"sv, &logging},
}};
SubGhzDRecentEntries recent{};
@@ -118,8 +139,16 @@ class SubGhzDView : public View {
{0, 16, 7 * 8, 32},
"Clear"};
Checkbox check_log{
{10 * 8, 18},
3,
"Log",
true};
static constexpr auto header_height = 3 * 16;
std::unique_ptr<SubGhzDLogger> logger{};
const RecentEntriesColumns columns{{
{"Type", 19},
{"Bits", 4},
@@ -25,6 +25,7 @@
#include "audio.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "portapack_persistent_memory.hpp"
#include "../baseband/fprotos/fprotogeneral.hpp"
@@ -35,6 +36,21 @@ namespace pmem = portapack::persistent_memory;
namespace ui {
std::string WeatherRecentEntry::to_csv() {
std::string csv = ";";
csv += WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)sensorType);
csv += ";" + to_string_dec_uint(id) + ";";
csv += to_string_decimal(temp, 2) + ";";
csv += to_string_dec_uint(humidity) + ";";
csv += to_string_dec_uint(channel) + ";";
csv += to_string_dec_uint(battery_low);
return csv;
}
void WeatherLogger::log_data(WeatherRecentEntry& data) {
log_file.write_entry(data.to_csv());
}
void WeatherRecentEntryDetailView::update_data() {
// set text elements
text_type.set(WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)entry_.sensorType));
@@ -98,8 +114,11 @@ WeatherView::WeatherView(NavigationView& nav)
&field_frequency,
&options_temperature,
&button_clear_list,
&check_log,
&recent_entries_view});
logger = std::make_unique<WeatherLogger>();
baseband::run_image(portapack::spi_flash::image_tag_weather);
button_clear_list.on_select = [this](Button&) {
@@ -114,6 +133,15 @@ WeatherView::WeatherView(NavigationView& nav)
};
options_temperature.set_selected_index(weather_units_fahr, false);
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
if (logger && logging) {
logger->append(logs_dir.string() + "/WEATHERLOG_" + to_string_timestamp(rtc_time::now()) + ".CSV");
logger->write_header();
}
};
check_log.set_value(logging);
const Rect content_rect{0, header_height, screen_width, screen_height - header_height};
recent_entries_view.set_parent_rect(content_rect);
recent_entries_view.on_select = [this](const WeatherRecentEntry& entry) {
@@ -140,6 +168,9 @@ void WeatherView::on_tick_second() {
void WeatherView::on_data(const WeatherDataMessage* data) {
WeatherRecentEntry key = process_data(data);
if (logger && logging) {
logger->log_data(key);
}
// WeatherRecentEntry key{data->sensorType, data->id, data->temp, data->humidity, data->channel, data->battery_low};
auto matching_recent = find(recent, key.key());
if (matching_recent != std::end(recent)) {
@@ -30,6 +30,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "log_file.hpp"
#include "recent_entries.hpp"
#include "../baseband/fprotos/weathertypes.hpp"
@@ -78,7 +79,25 @@ struct WeatherRecentEntry {
void reset_age() {
age = 0;
}
std::string to_csv();
};
class WeatherLogger {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
void log_data(WeatherRecentEntry& data);
void write_header() {
log_file.write_entry(";Type; id; Temp; Hum; CH; Batt");
}
private:
LogFile log_file{};
};
using WeatherRecentEntries = RecentEntries<WeatherRecentEntry>;
using WeatherRecentEntriesView = RecentEntriesView<WeatherRecentEntries>;
@@ -103,11 +122,13 @@ class WeatherView : public View {
1'750'000 /* bandwidth */,
2'000'000 /* sampling rate */,
ReceiverModel::Mode::AMAudio};
bool logging = false;
app_settings::SettingsManager settings_{
"rx_weather",
app_settings::Mode::RX,
{
{"units_fahr"sv, &weather_units_fahr},
{"log"sv, &logging},
}};
WeatherRecentEntries recent{};
@@ -140,8 +161,16 @@ class WeatherView : public View {
{0, 16, 7 * 8, 32},
"Clear"};
Checkbox check_log{
{10 * 8, 18},
3,
"Log",
true};
static constexpr auto header_height = 3 * 16;
std::unique_ptr<WeatherLogger> logger{};
const RecentEntriesColumns columns{{
{"Type", 10},
{"Temp", 5},
File diff suppressed because it is too large Load Diff
+9 -5
View File
@@ -115,9 +115,9 @@ set(EXTCPPSRC
external/ookbrute/main.cpp
external/ookbrute/ui_ookbrute.cpp
#rook
external/rook/main.cpp
external/rook/ui_rook.cpp
#ook_editor
external/ook_editor/main.cpp
external/ook_editor/ui_ook_editor.cpp
#cvs_spam
external/cvs_spam/main.cpp
@@ -126,7 +126,10 @@ set(EXTCPPSRC
#flippertx
external/flippertx/main.cpp
external/flippertx/ui_flippertx.cpp
#remote
external/remote/main.cpp
external/remote/ui_remote.cpp
)
set(EXTAPPLIST
@@ -157,7 +160,8 @@ set(EXTAPPLIST
random_password
#acars_rx
ookbrute
rook
ook_editor
shoppingcart_lock
flippertx
remote
)
+11 -5
View File
@@ -52,7 +52,8 @@ MEMORY
ram_external_app_cvs_spam(rwx) : org = 0xADCB0000, len = 32k
ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k
ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k
ram_external_app_rook(rwx) : org = 0xADCE0000, len = 32k
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
ram_external_app_remote(rwx) : org = 0xADCF0000, len = 32k
}
SECTIONS
@@ -226,11 +227,11 @@ SECTIONS
*(*ui*external_app*ookbrute*);
} > ram_external_app_ookbrute
.external_app_rook : ALIGN(4) SUBALIGN(4)
.external_app_ook_editor : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_rook.application_information));
*(*ui*external_app*rook*);
} > ram_external_app_rook
KEEP(*(.external_app.app_ook_editor.application_information));
*(*ui*external_app*ook_editor*);
} > ram_external_app_ook_editor
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
{
@@ -238,4 +239,9 @@ SECTIONS
*(*ui*external_app*flippertx*);
} > ram_external_app_flippertx
.external_app_remote : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_remote.application_information));
*(*ui*external_app*remote*);
} > ram_external_app_remote
}
@@ -20,25 +20,25 @@
*/
#include "ui.hpp"
#include "ui_rook.hpp"
#include "ui_ook_editor.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::rook {
namespace ui::external_app::ook_editor {
void initialize_app(ui::NavigationView& nav) {
nav.push<ROOKAppView>();
nav.push<OOKEditorAppView>();
}
} // namespace ui::external_app::rook
} // namespace ui::external_app::ook_editor
extern "C" {
__attribute__((section(".external_app.app_rook.application_information"), used)) application_information_t _application_information_rook = {
__attribute__((section(".external_app.app_ook_editor.application_information"), used)) application_information_t _application_information_ook_editor = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::rook::initialize_app,
/*.externalAppEntry = */ ui::external_app::ook_editor::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "ROOK",
/*.app_name = */ "OOKEditor",
/*.bitmap_data = */ {
0x20,
0x00,
@@ -79,4 +79,4 @@ __attribute__((section(".external_app.app_rook.application_information"), used))
/*.m4_app_tag = portapack::spi_flash::image_tag_ook */ {'P', 'O', 'O', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
}
@@ -0,0 +1,282 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_ook_editor.hpp"
using namespace portapack;
using namespace ui;
namespace fs = std::filesystem;
namespace ui::external_app::ook_editor {
// give focus to set button
void OOKEditorAppView::focus() {
button_set.focus();
}
// update internal ook_data with GUI values
void OOKEditorAppView::update_ook_data_from_app() {
ook_data.frequency = field_frequency.value();
ook_data.sample_rate = field_sample_rate.selected_index_value();
ook_data.symbol_rate = field_symbol_rate.value();
ook_data.repeat = field_repeat.value();
ook_data.pause_symbol_duration = field_pause_symbol_duration.value();
}
// `start_tx` method: Configures and begins OOK data transmission with a specific message.
void OOKEditorAppView::start_tx() {
// check if there is a payload
if (ook_data.payload.length() < 1) {
text_app_status.set("Error: no payload to tx !!");
return;
}
progressbar.set_max(field_repeat.value()); // Size the progress bar accordingly to the number of repeat
is_transmitting = true; // set transmitting flag
button_send_stop.set_text(LanguageHelper::currentMessages[LANG_STOP]); // set button back to initial "start" state
start_ook_file_tx(ook_data); // start the transmission
}
// `stop_tx` method: Stops the transmission and resets the progress bar.
void OOKEditorAppView::stop_tx() {
is_transmitting = false; // set transmitting flag
stop_ook_file_tx(); // stop transmission
progressbar.set_value(0); // Reset progress bar to 0
button_send_stop.set_text(LanguageHelper::currentMessages[LANG_START]); // set button back to initial "start" state
}
// `on_file_changed` method: Called when a new file is loaded; parses file data into variables
void OOKEditorAppView::on_file_changed(const fs::path& new_file_path) {
ook_data.payload.clear(); // Clear previous payload content
if (!read_ook_file(new_file_path, ook_data)) {
text_app_status.set("Error loading " + new_file_path.filename().string());
return;
}
field_frequency.set_value(ook_data.frequency);
field_symbol_rate.set_value(ook_data.symbol_rate);
field_repeat.set_value(ook_data.repeat);
field_pause_symbol_duration.set_value(ook_data.pause_symbol_duration);
field_sample_rate.set_by_value(ook_data.sample_rate);
text_payload.set(ook_data.payload);
button_send_stop.focus();
text_app_status.set("Loaded: " + new_file_path.filename().string());
}
// `on_tx_progress` method: Updates the progress bar based on transmission progress.
void OOKEditorAppView::on_tx_progress(const uint32_t progress, const bool done) {
progressbar.set_value(progress); // Update progress bar value
if (done) {
stop_tx(); // Stop transmission when progress reaches maximum
}
}
// `draw_waveform` method: Draws the waveform on the UI based on the payload data
void OOKEditorAppView::draw_waveform() {
// Padding reason:
// In real-world scenarios, the signal would always start low and return low after turning off the radio.
// `waveform_buffer` only controls drawing; the actual send logic is handled by frame_fragments.
size_t length = ook_data.payload.length();
// Ensure waveform length does not exceed buffer size
if (length + (PADDING_LEFT + PADDING_RIGHT) >= WAVEFORM_BUFFER_SIZE) {
length = WAVEFORM_BUFFER_SIZE - (PADDING_LEFT + PADDING_RIGHT);
}
// Left padding
for (size_t i = 0; i < PADDING_LEFT; i++) {
waveform_buffer[i] = 0;
}
// Draw the actual waveform
for (size_t n = 0; n < length; n++) {
waveform_buffer[n + PADDING_LEFT] = (ook_data.payload[n] == '0') ? 0 : 1;
}
// Right padding
for (size_t i = length + PADDING_LEFT; i < WAVEFORM_BUFFER_SIZE; i++) {
waveform_buffer[i] = 0;
}
waveform.set_length(length + PADDING_LEFT + PADDING_RIGHT);
waveform.set_dirty();
}
// build a new path+file, make some tests, call save_ook_to_file
void OOKEditorAppView::on_save_file(const std::string value) {
// check if there is a payload, else Error
if (ook_data.payload.length() < 1) {
text_app_status.set("Err: can't save, no payload !");
return;
}
ensure_directory(ook_editor_dir);
auto new_path = ook_editor_dir / value + ".OOK";
if (save_ook_to_file(new_path)) {
text_app_status.set("Saved to " + new_path.string());
} else {
text_app_status.set("Error saving " + new_path.string());
}
}
// update ook_data from GUI and save
bool OOKEditorAppView::save_ook_to_file(const std::filesystem::path& path) {
update_ook_data_from_app();
return save_ook_file(ook_data, path);
}
// Destructor for `OOKEditorAppView`: Disables the transmitter and shuts down the baseband
OOKEditorAppView::~OOKEditorAppView() {
stop_ook_file_tx();
baseband::shutdown();
}
// Constructor for `OOKEditorAppView`: Sets up the app view and initializes UI elements
OOKEditorAppView::OOKEditorAppView(NavigationView& nav)
: nav_{nav} {
// load OOK baseband
baseband::run_image(portapack::spi_flash::image_tag_ook);
// add all the widgets
add_children({&field_frequency,
&tx_view,
&button_send_stop,
&label_step,
&field_step,
&label_sample_rate,
&field_sample_rate,
&label_symbol_rate,
&field_symbol_rate,
&label_symbol_rate_unit,
&text_payload,
&button_set,
&progressbar,
&label_repeat,
&field_repeat,
&label_pause_symbol_duration,
&field_pause_symbol_duration,
&label_pause_symbol_duration_unit,
&label_payload,
&text_app_status,
&label_waveform,
&waveform,
&button_open,
&button_save});
// Initialize default values for controls
field_symbol_rate.set_value(100);
field_pause_symbol_duration.set_value(100);
field_repeat.set_value(4);
// Configure open ook file button
button_open.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".OOK");
ensure_directory(ook_editor_dir);
open_view->push_dir(ook_editor_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
// Postpone `on_file_changed` call until `FileLoadView` is closed
nav_.set_on_pop([this, new_file_path]() {
on_file_changed(new_file_path);
button_send_stop.focus();
draw_waveform();
});
};
};
// Configure save to ook file button
button_save.on_select = [this, &nav](const ui::Button&) {
outputFileBuffer = "";
text_prompt(
nav,
outputFileBuffer,
64,
[this](std::string& buffer) {
on_save_file(buffer);
});
};
// clean out loaded file name if field is changed
field_symbol_rate.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_repeat.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_pause_symbol_duration.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_sample_rate.on_change = [this](size_t, int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// setting up FrequencyField
field_frequency.set_value(ook_editor_tx_freq);
// clean out loaded file name if field is changed, save ook_editor_tx_freq
field_frequency.on_change = [this](rf::Frequency f) {
ook_editor_tx_freq = f;
text_app_status.set(""); // Clear loaded file text field
};
// allow typing frequency number
field_frequency.on_edit = [this]() {
auto freq_view = nav_.push<FrequencyKeypadView>(field_frequency.value());
freq_view->on_changed = [this](rf::Frequency f) {
field_frequency.set_value(f);
text_app_status.set(""); // Clear loaded file text field
};
};
// allow different steps on symbol_rate and pause_symbol_duration
field_step.on_change = [this](size_t, int32_t value) {
text_app_status.set(""); // Clear loaded file text field
field_symbol_rate.set_step(value);
field_pause_symbol_duration.set_step(value);
};
// Configure button to manually set payload through text input
button_set.on_select = [this, &nav](Button&) {
text_prompt(
nav,
ook_data.payload,
100,
[this](std::string& s) {
text_payload.set(s);
draw_waveform();
text_app_status.set(""); // Clear loaded file text field
});
};
// Configure button to start or stop the transmission
button_send_stop.on_select = [this](Button&) {
if (!is_transmitting) {
update_ook_data_from_app();
start_tx(); // Begin transmission
} else {
stop_tx();
}
};
// initial waveform drawing (should be a single line)
draw_waveform();
}
} // namespace ui::external_app::ook_editor
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
*/
#ifndef __UI_OOK_EDITOR_H__
#define __UI_OOK_EDITOR_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_freq_field.hpp"
#include "ui_textentry.hpp"
#include "ui_fileman.hpp"
#include "ui_transmitter.hpp"
#include "radio_state.hpp"
#include "app_settings.hpp"
#include "file_path.hpp"
#include "ook_file.hpp"
using namespace ui;
namespace ui::external_app::ook_editor {
#define PADDING_LEFT 1 // waveform padding
#define PADDING_RIGHT 1 // waveform padding
#define OOK_SAMPLERATE_DEFAULT 2280000U // Set the default Sample Rate
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U // Sets the default transmission frequency (27 MHz).
#define WAVEFORM_BUFFER_SIZE 550
class OOKEditorAppView : public View {
public:
void focus() override;
OOKEditorAppView(NavigationView& nav);
~OOKEditorAppView();
std::string title() const override {
return "OOKEditor";
};
private:
NavigationView& nav_; // Reference to the navigation system.
uint32_t progress = 0; // Stores the current transmission progress.
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE]; // Buffer for waveform data.
bool is_transmitting = false; // State of transmission.
rf::Frequency ook_editor_tx_freq{24000000}; // last used transmit frequency
std::string outputFileBuffer{}; // buffer for output file
ook_file_data ook_data = {0, 0, 0, 0, 0, ""}; // ook files handle
// draw current payload waveform
void draw_waveform();
// update ook_data from GUI selection
void update_ook_data_from_app();
// start transmission
void start_tx();
// stop transmission
void stop_tx();
// Updates the transmission progress on the progress bar.
void on_tx_progress(const uint32_t progress, const bool done);
// Updates data when a new file is loaded.
void on_file_changed(const std::filesystem::path& new_file_path);
// Prepare a new std::filesystem::path from string value and call saveFile
void on_save_file(const std::string value);
// Called by on_save_file to save the current OOK parameters to the file
bool save_ook_to_file(const std::filesystem::path& path);
// Registers a message handler for transmission progress updates.
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress, // Transmission progress message ID.
[this](const Message* const p) { // Callback to handle the message.
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.progress, message.done);
}};
// Sets transmission frequency, bandwidth, and default sample rate for OOK.
TxRadioState radio_state_{TRANSMISSION_FREQUENCY_DEFAULT, 1750000, OOK_SAMPLERATE_DEFAULT};
// Settings manager for app configuration.
app_settings::SettingsManager settings_{
"ook_editor",
app_settings::Mode::TX,
{{"ook_editor_tx_freq"sv, &ook_editor_tx_freq}}};
// UI components for frequency and transmitter view.
FrequencyField field_frequency{{0 * 8, 0 * 16}};
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
// Labels for various fields such as sample rate and repeat count.
Labels label_step{{{170, 20}, "Step:", Theme::getInstance()->fg_light->foreground}};
Labels label_sample_rate{{{0, 20}, "SampleRate:", Theme::getInstance()->fg_light->foreground}};
Labels label_symbol_rate{{{0, 40}, "SymbolRate:", Theme::getInstance()->fg_light->foreground}};
Labels label_symbol_rate_unit{{{132, 40}, "/s", Theme::getInstance()->fg_light->foreground}};
Labels label_repeat{{{154, 40}, "Repeat:", Theme::getInstance()->fg_light->foreground}};
Labels label_pause_symbol_duration{{{0, 60}, "PauseSymbol:", Theme::getInstance()->fg_light->foreground}};
Labels label_pause_symbol_duration_unit{{{132, 60}, "us", Theme::getInstance()->fg_light->foreground}};
Labels label_payload{{{0, 80}, "Payload:", Theme::getInstance()->fg_light->foreground}};
Labels label_waveform{{{0, 188}, "Waveform:", Theme::getInstance()->fg_light->foreground}};
// Text field to display the various status message of the app
Text text_app_status{{0, 160, 30 * 8, 16}, ""};
// OptionsField for selectable sample rates.
OptionsField field_sample_rate{{96, 20}, 7, {{"250k", 250000U}, {"1M", 1000000U}, {"2M", 2000000U}, {"5M", 5000000U}, {"10M", 10000000U}, {"20M", 20000000U}}};
// OptionsField for step symbol rates.
OptionsField field_step{{210, 20}, 7, {{"1", 1}, {"10", 10}, {"100", 100}}};
// Number fields for symbols, pause_symbol between repeat, and repeat count.
NumberField field_symbol_rate{{96, 40}, 4, {0, 9999}, 1, '0', false};
NumberField field_pause_symbol_duration{{96, 60}, 4, {0, 9999}, 1, '0', false};
NumberField field_repeat{{210, 40}, 3, {1, 999}, 1, '0', false};
// Text field to display the payload data.
Text text_payload{{0 * 8, 100, 30 * 8, 16}, ""};
// Buttons for setting configurations, opening files, and starting transmission.
Button button_set{{0, 125, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
Button button_open{{68, 125, 80, 28}, LanguageHelper::currentMessages[LANG_OPEN_FILE]};
Button button_save{{154, 125, 80, 28}, LanguageHelper::currentMessages[LANG_SAVE_FILE]};
Button button_send_stop{{80, 273, 80, 32}, LanguageHelper::currentMessages[LANG_SEND]};
// Progress bar to display transmission progress.
ProgressBar progressbar{{2 * 8, 250, 208, 16}};
// Waveform display using waveform buffer and yellow theme color.
Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
};
}; // namespace ui::external_app::ook_editor
#endif /*__UI_OOK_EDITOR_H__*/
+2 -2
View File
@@ -26,7 +26,7 @@
namespace ui::external_app::ookbrute {
void initialize_app(ui::NavigationView& nav) {
nav.push<OokBruteView>();
nav.push<OOKBruteView>();
}
} // namespace ui::external_app::ookbrute
@@ -38,7 +38,7 @@ __attribute__((section(".external_app.app_ookbrute.application_information"), us
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "OokBrute",
/*.app_name = */ "OOKBrute",
/*.bitmap_data = */ {
0x20,
0x00,
+10 -10
View File
@@ -31,11 +31,11 @@ using namespace ui;
namespace ui::external_app::ookbrute {
void OokBruteView::focus() {
void OOKBruteView::focus() {
button_startstop.focus();
}
OokBruteView::OokBruteView(NavigationView& nav)
OOKBruteView::OOKBruteView(NavigationView& nav)
: nav_{nav} {
add_children({
&button_startstop,
@@ -69,7 +69,7 @@ OokBruteView::OokBruteView(NavigationView& nav)
update_start_stop(0);
}
void OokBruteView::update_start_stop(uint32_t proto) {
void OOKBruteView::update_start_stop(uint32_t proto) {
uint8_t bits = 12;
switch (proto) {
default:
@@ -91,7 +91,7 @@ void OokBruteView::update_start_stop(uint32_t proto) {
field_stop.set_value(max);
}
void OokBruteView::validate_start_stop() {
void OOKBruteView::validate_start_stop() {
if (field_start.value() > field_stop.value()) {
field_start.set_value(field_stop.value());
}
@@ -100,7 +100,7 @@ void OokBruteView::validate_start_stop() {
}
}
void OokBruteView::generate_packet() {
void OOKBruteView::generate_packet() {
uint32_t protocol = options_atkmode.selected_index_value();
uint8_t byte = 0;
size_t bitstream_length = 0;
@@ -210,13 +210,13 @@ void OokBruteView::generate_packet() {
0);
}
void OokBruteView::stop() {
void OOKBruteView::stop() {
transmitter_model.disable();
baseband::shutdown();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_START]);
}
void OokBruteView::start() {
void OOKBruteView::start() {
counter = field_start.value();
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
transmitter_model.enable();
@@ -224,7 +224,7 @@ void OokBruteView::start() {
generate_packet();
}
void OokBruteView::on_tx_progress(const bool done) {
void OOKBruteView::on_tx_progress(const bool done) {
if (done) {
if (is_running) {
counter++;
@@ -238,7 +238,7 @@ void OokBruteView::on_tx_progress(const bool done) {
}
}
OokBruteView::~OokBruteView() {
OOKBruteView::~OOKBruteView() {
is_running = false;
stop();
}
@@ -250,4 +250,4 @@ OokBruteView::~OokBruteView() {
https://web.archive.org/web/20230331125843/https://phreakerclub.com/447
*/
*/
+4 -4
View File
@@ -24,15 +24,15 @@ namespace ui::external_app::ookbrute {
#define OOK_SAMPLERATE 2280000U
class OokBruteView : public View {
class OOKBruteView : public View {
public:
OokBruteView(NavigationView& nav);
~OokBruteView();
OOKBruteView(NavigationView& nav);
~OOKBruteView();
void focus() override;
std::string title() const override {
return "OokBrute";
return "OOKBrute";
};
private:
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 gullradriel
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_remote.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::remote {
void initialize_app(ui::NavigationView& nav) {
nav.push<RemoteAppView>();
}
} // namespace ui::external_app::remote
extern "C" {
__attribute__((section(".external_app.app_remote.application_information"), used)) application_information_t _application_information_remote = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::remote::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Remote",
/*.bitmap_data = */ {
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0xE0,
0x07,
0xF0,
0x0F,
0x30,
0x0C,
0x30,
0x0C,
0xF0,
0x0F,
0xF0,
0x0F,
0x70,
0x0D,
0xB0,
0x0E,
0x70,
0x0D,
0xB0,
0x0E,
0xF0,
0x0F,
0xE0,
0x07,
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::HOME,
/*.m4_app_tag = portapack::spi_flash::image_tag_replay */ {'P', 'R', 'E', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -20,7 +20,6 @@
*/
#include "ui_remote.hpp"
#include "binder.hpp"
#include "convert.hpp"
#include "file_reader.hpp"
@@ -34,11 +33,11 @@
#include "utility.hpp"
#include "file_path.hpp"
namespace ui::external_app::remote {
using namespace portapack;
namespace fs = std::filesystem;
namespace ui {
static constexpr uint8_t text_edit_max = 30;
/* RemoteEntryModel **************************************/
@@ -309,9 +308,9 @@ void RemoteEntryEditView::load_path(std::filesystem::path&& path) {
entry_.metadata = {transmitter_model.target_frequency(), 500'000};
}
/* RemoteView ********************************************/
/* RemoteAppView ********************************************/
RemoteView::RemoteView(
RemoteAppView::RemoteAppView(
NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_replay);
@@ -365,27 +364,27 @@ RemoteView::RemoteView(
refresh_ui();
}
RemoteView::RemoteView(NavigationView& nav, fs::path path)
: RemoteView(nav) {
RemoteAppView::RemoteAppView(NavigationView& nav, fs::path path)
: RemoteAppView(nav) {
load_remote(std::move(path));
refresh_ui();
}
RemoteView::~RemoteView() {
RemoteAppView::~RemoteAppView() {
stop();
baseband::shutdown();
save_remote(/*show_error*/ false);
}
void RemoteView::focus() {
void RemoteAppView::focus() {
if (model_.entries.empty())
button_add.focus();
else
buttons_[0]->focus();
}
void RemoteView::create_buttons() {
void RemoteAppView::create_buttons() {
// Handler callbacks.
auto handle_send = [this](RemoteButton& btn) {
if (btn.entry()->path.empty())
@@ -420,7 +419,7 @@ void RemoteView::create_buttons() {
}
}
void RemoteView::reset_buttons() {
void RemoteAppView::reset_buttons() {
// Whever the model's entries instance is invalidated,
// all the pointers in the buttons will end up dangling.
// TODO: This is pretty lame. Could maybe static alloc?
@@ -428,7 +427,7 @@ void RemoteView::reset_buttons() {
btn->set_entry(nullptr);
}
void RemoteView::refresh_ui() {
void RemoteAppView::refresh_ui() {
field_title.set_text(model_.name);
field_filename.set_text(remote_path_.stem().string());
@@ -441,7 +440,7 @@ void RemoteView::refresh_ui() {
}
}
void RemoteView::add_button() {
void RemoteAppView::add_button() {
if (model_.entries.size() >= max_buttons)
return;
@@ -454,7 +453,7 @@ void RemoteView::add_button() {
set_needs_save();
}
void RemoteView::edit_button(RemoteButton& btn) {
void RemoteAppView::edit_button(RemoteButton& btn) {
// Don't let replay thread read the model while editing.
stop();
@@ -471,7 +470,7 @@ void RemoteView::edit_button(RemoteButton& btn) {
};
}
void RemoteView::send_button(RemoteButton& btn) {
void RemoteAppView::send_button(RemoteButton& btn) {
// TODO: If this is called while is_sending() == true,
// it just stops and doesn't start the new button?
@@ -510,14 +509,14 @@ void RemoteView::send_button(RemoteButton& btn) {
});
}
void RemoteView::stop() {
void RemoteAppView::stop() {
// This terminates the underlying chThread.
replay_thread_.reset();
transmitter_model.disable();
ready_signal_ = false;
}
void RemoteView::new_remote() {
void RemoteAppView::new_remote() {
save_remote();
init_remote();
refresh_ui();
@@ -526,7 +525,7 @@ void RemoteView::new_remote() {
set_dirty();
}
void RemoteView::open_remote() {
void RemoteAppView::open_remote() {
auto open_view = nav_.push<FileLoadView>(".REM");
open_view->push_dir(remotes_dir);
open_view->on_changed = [this](fs::path path) {
@@ -536,7 +535,7 @@ void RemoteView::open_remote() {
};
}
void RemoteView::init_remote() {
void RemoteAppView::init_remote() {
model_ = {"<Unnamed Remote>", {}};
reset_buttons();
set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM"));
@@ -546,14 +545,14 @@ void RemoteView::init_remote() {
show_error("Couldn't make new remote file.");
}
bool RemoteView::load_remote(fs::path&& path) {
bool RemoteAppView::load_remote(fs::path&& path) {
set_remote_path(std::move(path));
set_needs_save(false);
reset_buttons();
return model_.load(remote_path_);
}
void RemoteView::save_remote(bool show_errors) {
void RemoteAppView::save_remote(bool show_errors) {
if (!needs_save_)
return;
@@ -564,7 +563,7 @@ void RemoteView::save_remote(bool show_errors) {
set_needs_save(false);
}
void RemoteView::rename_remote(const std::string& new_name) {
void RemoteAppView::rename_remote(const std::string& new_name) {
auto folder = remote_path_.parent_path();
auto ext = remote_path_.extension();
auto new_path = folder / new_name + ext;
@@ -581,7 +580,7 @@ void RemoteView::rename_remote(const std::string& new_name) {
set_remote_path(std::move(new_path));
}
void RemoteView::handle_replay_thread_done(uint32_t return_code) {
void RemoteAppView::handle_replay_thread_done(uint32_t return_code) {
if (return_code == ReplayThread::END_OF_FILE) {
if (check_loop.value() && current_btn_) {
send_button(*current_btn_);
@@ -598,15 +597,15 @@ void RemoteView::handle_replay_thread_done(uint32_t return_code) {
stop();
}
void RemoteView::set_remote_path(fs::path&& path) {
void RemoteAppView::set_remote_path(fs::path&& path) {
// Unfortunately, have to keep these two in sync because
// settings doesn't know about fs::path.
remote_path_ = std::move(path);
settings_.remote_path = remote_path_.string();
}
void RemoteView::show_error(const std::string& msg) const {
void RemoteAppView::show_error(const std::string& msg) const {
nav_.display_modal("Error", msg);
}
} /* namespace ui */
} // namespace ui::external_app::remote
@@ -41,7 +41,7 @@
#include <string_view>
#include <vector>
namespace ui {
namespace ui::external_app::remote {
/* Maps icon index to bitmap. */
class RemoteIcons {
@@ -257,14 +257,14 @@ class RemoteEntryEditView : public View {
};
/* App that allows for buttons to be bound to captures for playback. */
class RemoteView : public View {
class RemoteAppView : public View {
public:
RemoteView(NavigationView& nav);
RemoteView(NavigationView& nav, std::filesystem::path path);
~RemoteView();
RemoteAppView(NavigationView& nav);
RemoteAppView(NavigationView& nav, std::filesystem::path path);
~RemoteAppView();
RemoteView(const RemoteView&) = delete;
RemoteView& operator=(const RemoteView&) = delete;
RemoteAppView(const RemoteAppView&) = delete;
RemoteAppView& operator=(const RemoteAppView&) = delete;
std::string title() const override { return "Remote"; };
void focus() override;
@@ -385,4 +385,4 @@ class RemoteView : public View {
}};
};
} /* namespace ui */
} // namespace ui::external_app::remote
-275
View File
@@ -1,275 +0,0 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_rook.hpp"
#include "portapack.hpp"
#include "io_file.hpp"
#include "ui_fileman.hpp"
#include "file_path.hpp"
#include <cstring>
#include "baseband_api.hpp"
#include "ui_textentry.hpp"
#include "encoders.hpp" // Includes data encoding functions for transmission
#include "baseband_api.hpp" // Includes baseband API for handling transmission settings
#include "file_reader.hpp"
#define PADDING_LEFT 1
#define PADDING_RIGHT 1
using namespace portapack;
using namespace ui;
namespace fs = std::filesystem;
namespace ui::external_app::rook {
void ROOKAppView::focus() {
button_set.focus();
}
// `start_tx` method: Configures and begins OOK data transmission with a specific message.
void ROOKAppView::start_tx(const std::string& message) {
size_t bitstream_length = encoders::make_bitstream(const_cast<std::string&>(message)); // Convert the message into a bitstream
// Retrieve selected sample rate using selected_index_value()
int32_t SAMPLE_RATE_VALUE = field_sample_rate.selected_index_value();
int32_t SYMBOL_RATE_VALUE = cant_symbol_rate.value();
int32_t REPEAT = cant_repeat.value();
int32_t PAUSE_SYMBOL = cant_pause_symbol.value();
transmitter_model.set_sampling_rate(SAMPLE_RATE_VALUE); // Set the OOK sampling rate
transmitter_model.set_baseband_bandwidth(1750000); // Set the baseband bandwidth
transmitter_model.enable(); // Enable the transmitter
// Configure OOK data and transmission characteristics
baseband::set_ook_data(
bitstream_length, // Length of the bitstream to transmit
SAMPLE_RATE_VALUE / SYMBOL_RATE_VALUE, // Calculate symbol period based on repetition rate
REPEAT, // Set the number of repetitions per symbol
PAUSE_SYMBOL // Set the pause between symbols
);
}
// `stop_tx` method: Stops the transmission and resets the progress bar.
void ROOKAppView::stop_tx() {
transmitter_model.disable(); // Disable the transmitter
progressBar_progress.set_value(0); // Reset progress bar to 0
}
// `on_file_changed` method: Called when a new file is loaded; parses file data into variables
void ROOKAppView::on_file_changed(const fs::path& new_file_path) {
payload.clear(); // Clear previous payload content
File data_file;
auto open_result = data_file.open(new_file_path);
if (open_result) {
nav_.display_modal("Error", "Unable to open file.");
return;
}
FileLineReader reader(data_file);
for (const auto& line : reader) {
// Split the line into segments to extract each value
size_t first_space = line.find(' ');
size_t second_space = line.find(' ', first_space + 1);
size_t third_space = line.find(' ', second_space + 1);
size_t fourth_space = line.find(' ', third_space + 1);
size_t fifth_space = line.find(' ', fourth_space + 1);
// Extract each component of the line
std::string frequency_str = line.substr(0, first_space);
std::string sample_rate_str = line.substr(first_space + 1, second_space - first_space - 1);
std::string symbols_rate_str = line.substr(second_space + 1, third_space - second_space - 1);
std::string repeat_str = line.substr(third_space + 1, fourth_space - third_space - 1);
std::string pause_symbol_str = line.substr(fourth_space + 1, fifth_space - fourth_space - 1);
std::string payload_data = line.substr(fifth_space + 1); // Extract binary payload as final value
// Convert and assign frequency
unsigned long long frequency = std::stoull(frequency_str);
field_frequency.set_value(frequency);
transmitter_model.set_target_frequency(frequency);
// Convert and assign symbols rate
unsigned int symbols_rate = static_cast<unsigned int>(atoi(symbols_rate_str.c_str()));
cant_symbol_rate.set_value(symbols_rate);
// Convert and assign repeat count
unsigned int repeat = static_cast<unsigned int>(atoi(repeat_str.c_str()));
cant_repeat.set_value(repeat);
// Convert and assign pause per symbol
unsigned int pause_symbol = static_cast<unsigned int>(atoi(pause_symbol_str.c_str()));
cant_pause_symbol.set_value(pause_symbol);
// Select sample rate based on value read from file
if (sample_rate_str == "250k") {
field_sample_rate.set_by_value(250000U);
} else if (sample_rate_str == "1M") {
field_sample_rate.set_by_value(1000000U);
} else if (sample_rate_str == "2M") {
field_sample_rate.set_by_value(2000000U);
} else if (sample_rate_str == "5M") {
field_sample_rate.set_by_value(5000000U);
} else if (sample_rate_str == "10M") {
field_sample_rate.set_by_value(10000000U);
} else if (sample_rate_str == "20M") {
field_sample_rate.set_by_value(20000000U);
} else {
nav_.display_modal("Error", "Invalid sample rate.");
return;
}
// Update payload with binary data
payload = payload_data;
// Process only the first line
break;
}
// Ensure UI elements are initialized before use
if (parent()) {
text_payload.set(payload);
button_start.focus();
} else {
text_payload.set("parent not available");
}
}
// `on_tx_progress` method: Updates the progress bar based on transmission progress.
void ROOKAppView::on_tx_progress(const uint32_t progress, const bool done) {
progressBar_progress.set_value(progress); // Update progress bar value
if (done) {
stop_tx(); // Stop transmission when progress reaches maximum
}
}
// `draw_waveform` method: Draws the waveform on the UI based on the payload data
void ROOKAppView::draw_waveform() {
// Padding reason:
// In real-world scenarios, the signal would always start low and return low after turning off the radio.
// `waveform_buffer` only controls drawing; the actual send logic is handled by frame_fragments.
size_t length = payload.length();
// Ensure waveform length does not exceed buffer size
if (length + (PADDING_LEFT + PADDING_RIGHT) >= WAVEFORM_BUFFER_SIZE) {
length = WAVEFORM_BUFFER_SIZE - (PADDING_LEFT + PADDING_RIGHT);
}
// Left padding
for (size_t i = 0; i < PADDING_LEFT; i++) {
waveform_buffer[i] = 0;
}
// Draw the actual waveform
for (size_t n = 0; n < length; n++) {
waveform_buffer[n + PADDING_LEFT] = (payload[n] == '0') ? 0 : 1;
}
// Right padding
for (size_t i = length + PADDING_LEFT; i < WAVEFORM_BUFFER_SIZE; i++) {
waveform_buffer[i] = 0;
}
waveform.set_length(length + PADDING_LEFT + PADDING_RIGHT);
waveform.set_dirty();
}
// Destructor for `ROOKAppView`: Disables the transmitter and shuts down the baseband
ROOKAppView::~ROOKAppView() {
transmitter_model.disable();
baseband::shutdown();
}
// Constructor for `ROOKAppView`: Sets up the app view and initializes UI elements
ROOKAppView::ROOKAppView(NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_ook);
add_children({
&field_frequency,
&tx_view,
&button_start,
&sample_rate,
&step_symbol_rate,
&cant_step_symbol_rate,
&field_sample_rate,
&field_symbol_rate,
&field_symbol_us_rate,
&cant_symbol_rate,
&text_payload,
&button_set,
&progressBar_progress,
&repeat,
&cant_repeat,
&field_pause_symbol,
&cant_pause_symbol,
&label_waveform,
&waveform,
&button_open,
});
// Initialize default values for controls
cant_pause_symbol.set_value(100);
cant_repeat.set_value(4);
button_open.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".ROOK");
ensure_directory(rook_dir);
open_view->push_dir(rook_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
// Postpone `on_file_changed` call until `FileLoadView` is closed
nav_.set_on_pop([this, new_file_path]() {
on_file_changed(new_file_path);
button_start.focus();
draw_waveform();
});
};
};
// Set up changes for symbol rate and step
cant_symbol_rate.on_change = [this](int32_t value) {
if (value != cant_symbol_rate.value())
cant_symbol_rate.set_value(value);
};
cant_step_symbol_rate.on_change = [this](size_t, int32_t value) {
cant_symbol_rate.set_step(value);
};
// Configure button to manually set payload through text input
button_set.on_select = [this, &nav](Button&) {
text_prompt(
nav,
payload,
100,
[this](std::string& s) {
text_payload.set(s);
draw_waveform();
});
};
draw_waveform();
button_start.on_select = [this](Button&) {
start_tx(payload); // Begin transmission
};
}
} // namespace ui::external_app::rook
-119
View File
@@ -1,119 +0,0 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
*/
#ifndef __UI_ROOK_H__
#define __UI_ROOK_H__
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "string_format.hpp"
#include "radio_state.hpp"
#include "ui_freq_field.hpp"
#include "ui_transmitter.hpp"
#include "app_settings.hpp"
#include "transmitter_model.hpp"
#include <string>
using namespace ui;
namespace ui::external_app::rook {
#define PROGRESS_MAX 100
#define OOK_SAMPLERATE_DEFAULT 2280000U // Set the default Sample Rate
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U // Sets the default transmission frequency (27 MHz).
#define WAVEFORM_BUFFER_SIZE 550
class ROOKAppView : public View {
public:
void focus() override;
ROOKAppView(NavigationView& nav);
~ROOKAppView();
std::string title() const override {
return "RemoteOOK";
};
private:
NavigationView& nav_; // Reference to the navigation system.
std::string payload{""}; // Holds the data payload as a string.
uint32_t progress = 0; // Stores the current transmission progress.
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE]; // Buffer for waveform data.
void update();
void draw_waveform();
// Initiates data transmission with a specified message.
void start_tx(const std::string& message);
// Stops data transmission.
void stop_tx();
// Updates the transmission progress on the progress bar.
void on_tx_progress(const uint32_t progress, const bool done);
// Updates data when a new file is loaded.
void on_file_changed(const std::filesystem::path& new_file_path);
// Registers a message handler for transmission progress updates.
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress, // Transmission progress message ID.
[this](const Message* const p) { // Callback to handle the message.
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.progress, message.done);
}};
// Sets transmission frequency, bandwidth, and default sample rate for OOK.
TxRadioState radio_state_{TRANSMISSION_FREQUENCY_DEFAULT, 1750000, OOK_SAMPLERATE_DEFAULT};
// Settings manager for app configuration.
app_settings::SettingsManager settings_{"tx_rook", app_settings::Mode::TX};
// UI components for frequency and transmitter view.
TxFrequencyField field_frequency{{0 * 8, 0 * 16}, nav_};
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
// Labels for various fields such as sample rate and repeat count.
Labels sample_rate{{{0, 40}, "S/Rate: ", Theme::getInstance()->fg_light->foreground}};
// Labels step_symbol_rate {{{160, 0}, "Step/Sym: ",Theme::getInstance()->fg_light->foreground}};
Labels step_symbol_rate{{{0, 18}, "Step/Symbols: ", Theme::getInstance()->fg_light->foreground}};
Labels repeat{{{0, 60}, "Repeat: ", Theme::getInstance()->fg_light->foreground}};
Labels field_symbol_rate{{{111, 40}, "Symbols: ", Theme::getInstance()->fg_light->foreground}};
Labels field_pause_symbol{{{111, 60}, "Pause/Sym: ", Theme::getInstance()->fg_light->foreground}};
Labels field_symbol_us_rate{{{210, 40}, "us ", Theme::getInstance()->fg_light->foreground}};
Labels label_waveform{{{0, 140}, "Waveform:", Theme::getInstance()->fg_light->foreground}};
// OptionsField for selectable sample rates.
OptionsField field_sample_rate{{55, 40}, 7, {{"250k", 250000U}, {"1M", 1000000U}, {"2M", 2000000U}, {"5M", 5000000U}, {"10M", 10000000U}, {"20M", 20000000U}}};
// OptionsField for step symbol rates.
OptionsField cant_step_symbol_rate{{105, 18}, 7, {{"1", 1}, {"10", 10}, {"100", 100}}};
// Number fields for symbols, pause between symbols, and repeat count.
NumberField cant_symbol_rate{{176, 40}, 4, {0, 9999}, 1, '0', false};
NumberField cant_pause_symbol{{200, 60}, 4, {0, 200}, 1, '0', false};
NumberField cant_repeat{{55, 60}, 3, {0, 100}, 1, '0', false};
// Text field to display the payload data.
Text text_payload{{0 * 8, 90, 30 * 8, 16}, "Payload:"};
// Buttons for setting configurations, opening files, and starting transmission.
Button button_set{{0, 110, 60, 28}, "Set"};
Button button_open{{100, 110, 80, 28}, "Open file"};
Button button_start{{80, 273, 80, 32}, "Start"};
// Progress bar to display transmission progress.
ProgressBar progressBar_progress{{2 * 8, 250, 208, 16}};
// Waveform display using waveform buffer and yellow theme color.
Waveform waveform{{0, 165, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
};
}; // namespace ui::external_app::rook
#endif /*__UI_ROOK_H__*/
+1 -1
View File
@@ -48,4 +48,4 @@ const std::filesystem::path splash_dir = u"SPLASH";
const std::filesystem::path sstv_dir = u"SSTV";
const std::filesystem::path wav_dir = u"WAV";
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
const std::filesystem::path rook_dir = u"ROOK";
const std::filesystem::path ook_editor_dir = u"OOKFILES";
+1 -1
View File
@@ -50,6 +50,6 @@ extern const std::filesystem::path splash_dir;
extern const std::filesystem::path sstv_dir;
extern const std::filesystem::path wav_dir;
extern const std::filesystem::path whipcalc_dir;
extern const std::filesystem::path rook_dir;
extern const std::filesystem::path ook_editor_dir;
#endif /* __FILE_PATH_H__ */
+158
View File
@@ -0,0 +1,158 @@
/*
* Copyright (C) 2024 gullradriel
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ook_file.hpp"
using namespace portapack;
namespace fs = std::filesystem;
/*
struct of an OOK file:
Frequency SampleRate SymbolRate Repeat PauseSymbolDuration Payload
-Frequency is in hertz
-SampleRate is one of 250k, 1M, 2M, 5M , 10M ,20M
-SymbolRate is the number of symbols /s
-Repeat is the number of times we will repeat the payload
-PauseSymbolDuration is the duration of the pause between repeat, in usec
-Payload is the payload in form of a string of 0 and 1
*/
bool read_ook_file(const std::filesystem::path& path, ook_file_data& ook_data) {
File data_file;
auto open_result = data_file.open(path);
if (open_result) {
return false;
}
FileLineReader reader(data_file);
for (const auto& line : reader) {
// Split the line into segments to extract each value
size_t first_space = line.find(' ');
size_t second_space = line.find(' ', first_space + 1);
size_t third_space = line.find(' ', second_space + 1);
size_t fourth_space = line.find(' ', third_space + 1);
size_t fifth_space = line.find(' ', fourth_space + 1);
// Extract each component of the line
std::string frequency_str = line.substr(0, first_space);
std::string sample_rate_str = line.substr(first_space + 1, second_space - first_space - 1);
std::string symbol_rate_str = line.substr(second_space + 1, third_space - second_space - 1);
std::string repeat_str = line.substr(third_space + 1, fourth_space - third_space - 1);
std::string pause_symbol_duration_str = line.substr(fourth_space + 1, fifth_space - fourth_space - 1);
std::string payload_data = line.substr(fifth_space + 1); // Extract binary payload as final value
// Convert and assign frequency
ook_data.frequency = std::stoull(frequency_str);
// Convert and assign symbol_rate
ook_data.symbol_rate = static_cast<unsigned int>(atoi(symbol_rate_str.c_str()));
// Convert and assign repeat count
ook_data.repeat = static_cast<unsigned int>(atoi(repeat_str.c_str()));
// Convert and assign pause_symbol_duration
ook_data.pause_symbol_duration = static_cast<unsigned int>(atoi(pause_symbol_duration_str.c_str()));
// Select sample rate based on value read from file
if (sample_rate_str == "250k") {
ook_data.sample_rate = 250000U;
} else if (sample_rate_str == "1M") {
ook_data.sample_rate = 1000000U;
} else if (sample_rate_str == "2M") {
ook_data.sample_rate = 2000000U;
} else if (sample_rate_str == "5M") {
ook_data.sample_rate = 5000000U;
} else if (sample_rate_str == "10M") {
ook_data.sample_rate = 10000000U;
} else if (sample_rate_str == "20M") {
ook_data.sample_rate = 20000000U;
} else {
return false;
}
// Update payload with binary data
ook_data.payload = std::move(payload_data);
// Process only the first line
break;
}
return true;
}
bool save_ook_file(ook_file_data& ook_data, const std::filesystem::path& path) {
// delete file if it exists
delete_file(path);
// Attempt to open, if it can't be opened. Create new.
auto src = std::make_unique<File>();
auto error = src->open(path, false, true);
if (error) {
return false;
}
std::string sample_rate_str;
if (ook_data.sample_rate == 250000U) {
sample_rate_str = "250k";
} else if (ook_data.sample_rate == 1000000U) {
sample_rate_str = "1M";
} else if (ook_data.sample_rate == 2000000U) {
sample_rate_str = "2M";
} else if (ook_data.sample_rate == 5000000U) {
sample_rate_str = "5M";
} else if (ook_data.sample_rate == 10000000U) {
sample_rate_str = "10M";
} else if (ook_data.sample_rate == 20000000U) {
sample_rate_str = "20M";
} else {
return false;
}
// write informations
src->write_line(to_string_dec_uint(ook_data.frequency) + " " +
sample_rate_str + " " +
to_string_dec_uint(ook_data.symbol_rate) + " " +
to_string_dec_uint(ook_data.repeat) + " " +
to_string_dec_uint(ook_data.pause_symbol_duration) + " " +
ook_data.payload);
// Close files
src.reset();
return true;
}
void start_ook_file_tx(ook_file_data& ook_data) {
size_t bitstream_length = encoders::make_bitstream(const_cast<std::string&>(ook_data.payload)); // Convert the message into a bitstream
transmitter_model.set_target_frequency(ook_data.frequency); // Set target frequency
transmitter_model.set_sampling_rate(ook_data.sample_rate); // Set the OOK sampling rate
transmitter_model.set_baseband_bandwidth(1750000); // Set the baseband bandwidth
transmitter_model.enable(); // Enable the transmitter
// Configure OOK data and transmission characteristics
baseband::set_ook_data(
bitstream_length, // Length of the bitstream to transmit
ook_data.sample_rate / ook_data.symbol_rate, // Calculate symbol period based on repetition rate
ook_data.repeat, // Set the number of times the whole bitstream is repeated
ook_data.pause_symbol_duration // Set the pause_symbol between reps
);
}
void stop_ook_file_tx() {
transmitter_model.disable(); // Disable the transmitter
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 gullradriel
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __OOK_FILE_HPP__
#define __OOK_FILE_HPP__
#include "portapack.hpp"
#include "metadata_file.hpp"
#include "encoders.hpp" // Includes data encoding functions for transmission
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
#include <string_view>
#include "transmitter_model.hpp"
#include "baseband_api.hpp" // Includes baseband API for handling transmission settings
struct ook_file_data {
rf::Frequency frequency = rf::Frequency(0); // Default frequency
uint32_t sample_rate = 0; // Default sample rate
uint16_t symbol_rate = 0; // Default bit duration
uint16_t pause_symbol_duration = 0; // Default pause between repeat
uint16_t repeat = 0; // Default repeat
std::string payload = ""; // Default payload
};
bool read_ook_file(const std::filesystem::path& path, ook_file_data& ook_data);
bool save_ook_file(ook_file_data& data, const std::filesystem::path& path);
void start_ook_file_tx(ook_file_data& ook_data);
void stop_ook_file_tx();
#endif // __FLIPPER_SUBFILE_HPP__
+12 -11
View File
@@ -52,7 +52,6 @@
#include "ui_pocsag_tx.hpp"
#include "ui_rds.hpp"
#include "ui_recon.hpp"
#include "ui_remote.hpp"
#include "ui_scanner.hpp"
#include "ui_sd_over_usb.hpp"
#include "ui_sd_wipe.hpp"
@@ -126,7 +125,6 @@ const NavigationView::AppList NavigationView::appList = {
{nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory<TransmittersMenuView>()},
{"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory<CaptureAppView>()},
{"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, new ViewFactory<PlaylistView>()},
{"remote", "Remote", HOME, ui::Color::green(), &bitmap_icon_remote, new ViewFactory<RemoteView>()},
{"scanner", "Scanner", HOME, Color::green(), &bitmap_icon_scanner, new ViewFactory<ScannerView>()},
{"microphone", "Microphone", HOME, Color::green(), &bitmap_icon_microphone, new ViewFactory<MicTXView>()},
{"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, new ViewFactory<GlassView>()},
@@ -851,6 +849,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav)
void SystemMenuView::on_populate() {
add_apps(nav_, *this, HOME);
addExternalItems(nav_, app_location_t::HOME, *this);
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
}
@@ -902,7 +901,7 @@ SystemView::SystemView(
navigation_view.push<SystemMenuView>();
if (pmem::config_splash()) {
navigation_view.push<BMPView>();
navigation_view.push<SplashScreenView>();
}
status_view.set_back_enabled(false);
status_view.set_title_image_enabled(true);
@@ -971,11 +970,11 @@ void SystemView::set_app_fullscreen(bool fullscreen) {
/* ***********************************************************************/
void BMPView::focus() {
void SplashScreenView::focus() {
button_done.focus();
}
BMPView::BMPView(NavigationView& nav)
SplashScreenView::SplashScreenView(NavigationView& nav)
: nav_(nav) {
add_children({&button_done});
@@ -984,12 +983,14 @@ BMPView::BMPView(NavigationView& nav)
};
}
void BMPView::paint(Painter&) {
if (!portapack::display.drawBMP2({0, 0}, splash_dot_bmp))
portapack::display.drawBMP({0, 16}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
void SplashScreenView::paint(Painter&) {
if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, splash_dot_bmp))
// ^ try draw bmp file from sdcard at (0,0), and the (0,0) already bypassed the status bar, so actual pos is (0, STATUS_BAR_HEIGHT)
portapack::display.draw_bmp_from_bmp_hex_arr({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
// ^ draw BMP HEX arr in firmware, note that the BMP HEX arr only cover the image part (instead of fill the screen with background, this position is located it in the center)
}
bool BMPView::on_touch(const TouchEvent event) {
bool SplashScreenView::on_touch(const TouchEvent event) {
/* the event thing were resolved by HTotoo, talked here https://discord.com/channels/719669764804444213/956561375155589192/1287756910950486027
* the touch screen policy can be better, talked here https://discord.com/channels/719669764804444213/956561375155589192/1198926225897443328
* this workaround discussed here: https://discord.com/channels/719669764804444213/1170738202924044338/1295630640158478418
@@ -1011,7 +1012,7 @@ bool BMPView::on_touch(const TouchEvent event) {
return false;
}
void BMPView::handle_pop() {
void SplashScreenView::handle_pop() {
if (nav_.is_valid()) {
nav_.pop();
}
@@ -1080,7 +1081,7 @@ ModalMessageView::ModalMessageView(
}
void ModalMessageView::paint(Painter& painter) {
if (!compact) portapack::display.drawBMP({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
if (!compact) portapack::display.draw_bmp_from_bmp_hex_arr({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
// Break lines.
auto lines = split_string(message_, '\n');
+2 -2
View File
@@ -332,9 +332,9 @@ class InformationView : public View {
{86, 0, 19 * 8, 16}};
};
class BMPView : public View {
class SplashScreenView : public View {
public:
BMPView(NavigationView& nav);
SplashScreenView(NavigationView& nav);
void paint(Painter&) override;
void focus() override;
+9 -7
View File
@@ -345,19 +345,19 @@ void ILI9341::render_box(const ui::Point p, const ui::Size s, const ui::Color* l
// RLE_4 BMP loader (delta not implemented)
/* draw transparent, pass transparent color as arg, usage inline anonymous obj
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){41, 24, 22}); // dec, out of {255, 255, 255}
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){0x29, 0x18, 0x16}); //hex out of {0xFF, 0xFF, 0xFF}
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, (const uint8_t[]){41, 24, 22}); // dec, out of {255, 255, 255}
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, (const uint8_t[]){0x29, 0x18, 0x16}); //hex out of {0xFF, 0xFF, 0xFF}
*
* draw transparent, pass transparent color as arg, usage pass uint8_t[] obj
* const uint8_t c[] = {41, 24, 22}; or const uint8_t c[3] = {0x29, 0x18, 0x16};
* portapack::display.drawBMP({100, 100}, foo_bmp, c);
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, c);
*
* don't draw transparent, pass nullptr as arg, usage
* portapack::display.drawBMP({100, 100}, foo_bmp, nullptr);
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, nullptr);
*
* if your image use RLE compress as transparency methods, pass any valid color as arg, it doesn't matter (like the modal bmp. TODO: write RLE transparency generator)
* */
void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color) {
void ILI9341::draw_bmp_from_bmp_hex_arr(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color) {
const bmp_header_t* bmp_header = (const bmp_header_t*)bitmap;
uint32_t data_idx;
uint8_t by, c, count, transp_idx = 0;
@@ -463,7 +463,7 @@ void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* t
* 24bpp RGB
* 32bpp ARGB
*/
bool ILI9341::drawBMP2(const ui::Point p, const std::filesystem::path& file) {
bool ILI9341::draw_bmp_from_sdcard_file(const ui::Point p, const std::filesystem::path& file) {
File bmpimage;
size_t file_pos = 0;
uint16_t pointer = 0;
@@ -512,7 +512,9 @@ bool ILI9341::drawBMP2(const ui::Point p, const std::filesystem::path& file) {
file_pos = bmp_header.image_data;
py = height + 16;
py = height + 16 - 1;
/* ^ this is for to "start" AKA "image end" draw at the 17th line,
* because the render_line logic below is start with p.y() + py until "end" AKA "image start"*/
while (1) {
while (px < width) {
+2 -2
View File
@@ -62,8 +62,8 @@ class ILI9341 {
const ui::Color background);
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color);
bool drawBMP2(const ui::Point p, const std::filesystem::path& file);
void draw_bmp_from_bmp_hex_arr(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color);
bool draw_bmp_from_sdcard_file(const ui::Point p, const std::filesystem::path& file);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
+1 -1
View File
@@ -1,7 +1,7 @@
#include "ui_language.hpp"
// use the exact position in this array! the enum's value is the identifier. Best to add to the end
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock", "Browse"};
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock", "Browse", "Set", "Open File", "Save File", "Send", "Receive"};
// multi language support will changes (not in use for now)
const char** LanguageHelper::currentMessages = englishMessages;
+7 -2
View File
@@ -61,7 +61,12 @@ enum LangConsts {
LANG_SAVE,
LANG_LOCK,
LANG_UNLOCK,
LANG_BROWSE
LANG_BROWSE,
LANG_SET,
LANG_OPEN_FILE,
LANG_SAVE_FILE,
LANG_SEND,
LANG_RECV
};
class LanguageHelper {
@@ -74,4 +79,4 @@ class LanguageHelper {
static const char* englishMessages[];
};
#endif
#endif
+1
View File
@@ -0,0 +1 @@
27000000 1M 1076 4 100 01110111011101110101010101010101010101110111011101110101