mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-04 15:35:32 +00:00
External App ROOK(Remote On-Off Keying) (#2363)
This commit is contained in:
parent
59f72cbff1
commit
64f8158134
5
firmware/application/external/external.cmake
vendored
5
firmware/application/external/external.cmake
vendored
@ -115,6 +115,10 @@ set(EXTCPPSRC
|
||||
external/ookbrute/main.cpp
|
||||
external/ookbrute/ui_ookbrute.cpp
|
||||
|
||||
#rook
|
||||
external/rook/main.cpp
|
||||
external/rook/ui_rook.cpp
|
||||
|
||||
#cvs_spam
|
||||
external/cvs_spam/main.cpp
|
||||
external/cvs_spam/cvs_spam.cpp
|
||||
@ -153,6 +157,7 @@ set(EXTAPPLIST
|
||||
random_password
|
||||
#acars_rx
|
||||
ookbrute
|
||||
rook
|
||||
shoppingcart_lock
|
||||
flippertx
|
||||
)
|
||||
|
7
firmware/application/external/external.ld
vendored
7
firmware/application/external/external.ld
vendored
@ -52,6 +52,7 @@ 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
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@ -225,6 +226,12 @@ SECTIONS
|
||||
*(*ui*external_app*ookbrute*);
|
||||
} > ram_external_app_ookbrute
|
||||
|
||||
.external_app_rook : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_rook.application_information));
|
||||
*(*ui*external_app*rook*);
|
||||
} > ram_external_app_rook
|
||||
|
||||
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_flippertx.application_information));
|
||||
|
82
firmware/application/external/rook/main.cpp
vendored
Normal file
82
firmware/application/external/rook/main.cpp
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.hpp"
|
||||
#include "ui_rook.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::rook {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<ROOKAppView>();
|
||||
}
|
||||
} // namespace ui::external_app::rook
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_rook.application_information"), used)) application_information_t _application_information_rook = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::rook::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "ROOK",
|
||||
/*.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::orange().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_ook */ {'P', 'O', 'O', 'K'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
275
firmware/application/external/rook/ui_rook.cpp
vendored
Normal file
275
firmware/application/external/rook/ui_rook.cpp
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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
firmware/application/external/rook/ui_rook.hpp
vendored
Normal file
119
firmware/application/external/rook/ui_rook.hpp
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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__*/
|
@ -48,3 +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";
|
||||
|
@ -50,5 +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;
|
||||
|
||||
#endif /* __FILE_PATH_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user