mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-14 18:24:34 -05:00
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
This commit is contained in:
parent
6b8274d792
commit
ff54f59d38
@ -244,6 +244,7 @@ set(CPPSRC
|
|||||||
hw/si5351.cpp
|
hw/si5351.cpp
|
||||||
hw/spi_pp.cpp
|
hw/spi_pp.cpp
|
||||||
hw/touch_adc.cpp
|
hw/touch_adc.cpp
|
||||||
|
ook_file.cpp
|
||||||
ui_baseband_stats_view.cpp
|
ui_baseband_stats_view.cpp
|
||||||
ui_navigation.cpp
|
ui_navigation.cpp
|
||||||
ui_record_view.cpp
|
ui_record_view.cpp
|
||||||
|
8
firmware/application/external/external.cmake
vendored
8
firmware/application/external/external.cmake
vendored
@ -115,9 +115,9 @@ set(EXTCPPSRC
|
|||||||
external/ookbrute/main.cpp
|
external/ookbrute/main.cpp
|
||||||
external/ookbrute/ui_ookbrute.cpp
|
external/ookbrute/ui_ookbrute.cpp
|
||||||
|
|
||||||
#ook_remote
|
#ook_editor
|
||||||
external/ook_remote/main.cpp
|
external/ook_editor/main.cpp
|
||||||
external/ook_remote/ui_ook_remote.cpp
|
external/ook_editor/ui_ook_editor.cpp
|
||||||
|
|
||||||
#cvs_spam
|
#cvs_spam
|
||||||
external/cvs_spam/main.cpp
|
external/cvs_spam/main.cpp
|
||||||
@ -157,7 +157,7 @@ set(EXTAPPLIST
|
|||||||
random_password
|
random_password
|
||||||
#acars_rx
|
#acars_rx
|
||||||
ookbrute
|
ookbrute
|
||||||
ook_remote
|
ook_editor
|
||||||
shoppingcart_lock
|
shoppingcart_lock
|
||||||
flippertx
|
flippertx
|
||||||
)
|
)
|
||||||
|
10
firmware/application/external/external.ld
vendored
10
firmware/application/external/external.ld
vendored
@ -52,7 +52,7 @@ MEMORY
|
|||||||
ram_external_app_cvs_spam(rwx) : org = 0xADCB0000, len = 32k
|
ram_external_app_cvs_spam(rwx) : org = 0xADCB0000, len = 32k
|
||||||
ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k
|
ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k
|
||||||
ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k
|
ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k
|
||||||
ram_external_app_ook_remote(rwx) : org = 0xADCE0000, len = 32k
|
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
@ -226,11 +226,11 @@ SECTIONS
|
|||||||
*(*ui*external_app*ookbrute*);
|
*(*ui*external_app*ookbrute*);
|
||||||
} > ram_external_app_ookbrute
|
} > ram_external_app_ookbrute
|
||||||
|
|
||||||
.external_app_ook_remote : ALIGN(4) SUBALIGN(4)
|
.external_app_ook_editor : ALIGN(4) SUBALIGN(4)
|
||||||
{
|
{
|
||||||
KEEP(*(.external_app.app_ook_remote.application_information));
|
KEEP(*(.external_app.app_ook_editor.application_information));
|
||||||
*(*ui*external_app*ook_remote*);
|
*(*ui*external_app*ook_editor*);
|
||||||
} > ram_external_app_ook_remote
|
} > ram_external_app_ook_editor
|
||||||
|
|
||||||
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
|
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
|
||||||
{
|
{
|
||||||
|
@ -20,25 +20,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include "ui_ook_remote.hpp"
|
#include "ui_ook_editor.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "external_app.hpp"
|
#include "external_app.hpp"
|
||||||
|
|
||||||
namespace ui::external_app::ook_remote {
|
namespace ui::external_app::ook_editor {
|
||||||
void initialize_app(ui::NavigationView& nav) {
|
void initialize_app(ui::NavigationView& nav) {
|
||||||
nav.push<OOKRemoteAppView>();
|
nav.push<OOKEditorAppView>();
|
||||||
}
|
}
|
||||||
} // namespace ui::external_app::ook_remote
|
} // namespace ui::external_app::ook_editor
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
__attribute__((section(".external_app.app_ook_remote.application_information"), used)) application_information_t _application_information_ook_remote = {
|
__attribute__((section(".external_app.app_ook_editor.application_information"), used)) application_information_t _application_information_ook_editor = {
|
||||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||||
/*.externalAppEntry = */ ui::external_app::ook_remote::initialize_app,
|
/*.externalAppEntry = */ ui::external_app::ook_editor::initialize_app,
|
||||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||||
/*.app_version = */ VERSION_MD5,
|
/*.app_version = */ VERSION_MD5,
|
||||||
|
|
||||||
/*.app_name = */ "OOKRemote",
|
/*.app_name = */ "OOKEditor",
|
||||||
/*.bitmap_data = */ {
|
/*.bitmap_data = */ {
|
||||||
0x20,
|
0x20,
|
||||||
0x00,
|
0x00,
|
282
firmware/application/external/ook_editor/ui_ook_editor.cpp
vendored
Normal file
282
firmware/application/external/ook_editor/ui_ook_editor.cpp
vendored
Normal file
@ -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
|
@ -5,57 +5,59 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UI_OOK_REMOTE_H__
|
#ifndef __UI_OOK_EDITOR_H__
|
||||||
#define __UI_OOK_REMOTE_H__
|
#define __UI_OOK_EDITOR_H__
|
||||||
|
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include "ui_language.hpp"
|
#include "ui_language.hpp"
|
||||||
#include "ui_widget.hpp"
|
|
||||||
#include "ui_navigation.hpp"
|
|
||||||
#include "string_format.hpp"
|
|
||||||
#include "radio_state.hpp"
|
|
||||||
#include "ui_freq_field.hpp"
|
#include "ui_freq_field.hpp"
|
||||||
|
#include "ui_textentry.hpp"
|
||||||
|
#include "ui_fileman.hpp"
|
||||||
#include "ui_transmitter.hpp"
|
#include "ui_transmitter.hpp"
|
||||||
|
#include "radio_state.hpp"
|
||||||
#include "app_settings.hpp"
|
#include "app_settings.hpp"
|
||||||
#include "transmitter_model.hpp"
|
#include "file_path.hpp"
|
||||||
#include <string>
|
#include "ook_file.hpp"
|
||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
namespace ui::external_app::ook_remote {
|
namespace ui::external_app::ook_editor {
|
||||||
|
|
||||||
#define PROGRESS_MAX 100
|
#define PADDING_LEFT 1 // waveform padding
|
||||||
|
#define PADDING_RIGHT 1 // waveform padding
|
||||||
#define OOK_SAMPLERATE_DEFAULT 2280000U // Set the default Sample Rate
|
#define OOK_SAMPLERATE_DEFAULT 2280000U // Set the default Sample Rate
|
||||||
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U // Sets the default transmission frequency (27 MHz).
|
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U // Sets the default transmission frequency (27 MHz).
|
||||||
#define WAVEFORM_BUFFER_SIZE 550
|
#define WAVEFORM_BUFFER_SIZE 550
|
||||||
|
|
||||||
class OOKRemoteAppView : public View {
|
class OOKEditorAppView : public View {
|
||||||
public:
|
public:
|
||||||
void focus() override;
|
void focus() override;
|
||||||
OOKRemoteAppView(NavigationView& nav);
|
OOKEditorAppView(NavigationView& nav);
|
||||||
|
|
||||||
~OOKRemoteAppView();
|
~OOKEditorAppView();
|
||||||
|
|
||||||
std::string title() const override {
|
std::string title() const override {
|
||||||
return "OOKRemote";
|
return "OOKEditor";
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NavigationView& nav_; // Reference to the navigation system.
|
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.
|
uint32_t progress = 0; // Stores the current transmission progress.
|
||||||
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE]; // Buffer for waveform data.
|
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE]; // Buffer for waveform data.
|
||||||
bool is_transmitting = false; // State of transmission.
|
bool is_transmitting = false; // State of transmission.
|
||||||
rf::Frequency ook_remote_tx_freq{24000000}; // last used transmit frequency
|
rf::Frequency ook_editor_tx_freq{24000000}; // last used transmit frequency
|
||||||
std::string outputFileBuffer{}; // buffer for output file
|
std::string outputFileBuffer{}; // buffer for output file
|
||||||
|
ook_file_data ook_data = {0, 0, 0, 0, 0, ""}; // ook files handle
|
||||||
|
|
||||||
void update();
|
// draw current payload waveform
|
||||||
void draw_waveform();
|
void draw_waveform();
|
||||||
|
|
||||||
// Initiates data transmission with a specified message.
|
// update ook_data from GUI selection
|
||||||
void start_tx(const std::string& message);
|
void update_ook_data_from_app();
|
||||||
|
|
||||||
// Stops data transmission.
|
// start transmission
|
||||||
|
void start_tx();
|
||||||
|
// stop transmission
|
||||||
void stop_tx();
|
void stop_tx();
|
||||||
|
|
||||||
// Updates the transmission progress on the progress bar.
|
// Updates the transmission progress on the progress bar.
|
||||||
@ -83,45 +85,44 @@ class OOKRemoteAppView : public View {
|
|||||||
|
|
||||||
// Settings manager for app configuration.
|
// Settings manager for app configuration.
|
||||||
app_settings::SettingsManager settings_{
|
app_settings::SettingsManager settings_{
|
||||||
"ook_remote",
|
"ook_editor",
|
||||||
app_settings::Mode::TX,
|
app_settings::Mode::TX,
|
||||||
{{"ook_remote_tx_freq"sv, &ook_remote_tx_freq}}};
|
{{"ook_editor_tx_freq"sv, &ook_editor_tx_freq}}};
|
||||||
|
|
||||||
// UI components for frequency and transmitter view.
|
// UI components for frequency and transmitter view.
|
||||||
FrequencyField field_frequency{{0 * 8, 0 * 16}};
|
FrequencyField field_frequency{{0 * 8, 0 * 16}};
|
||||||
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
|
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
|
||||||
|
|
||||||
// Labels for various fields such as sample rate and repeat count.
|
// Labels for various fields such as sample rate and repeat count.
|
||||||
Labels label_bit_duration_step{{{111, 18}, "BitTimeStep:", Theme::getInstance()->fg_light->foreground}};
|
Labels label_step{{{170, 20}, "Step:", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_sample_rate{{{0, 18}, "S/Rate:", Theme::getInstance()->fg_light->foreground}};
|
Labels label_sample_rate{{{0, 20}, "SampleRate:", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_bit_duration{{{111, 40}, "BitTime:", Theme::getInstance()->fg_light->foreground}};
|
Labels label_symbol_rate{{{0, 40}, "SymbolRate:", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_bit_duration_unit{{{210, 40}, "us", Theme::getInstance()->fg_light->foreground}};
|
Labels label_symbol_rate_unit{{{132, 40}, "/s", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_repeat{{{0, 40}, "Repeat:", Theme::getInstance()->fg_light->foreground}};
|
Labels label_repeat{{{154, 40}, "Repeat:", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_pause_symbol{{{0, 60}, "Pause/Sym:", Theme::getInstance()->fg_light->foreground}};
|
Labels label_pause_symbol_duration{{{0, 60}, "PauseSymbol:", Theme::getInstance()->fg_light->foreground}};
|
||||||
Labels label_payload{{{0, 76}, "Payload:", 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}};
|
Labels label_waveform{{{0, 188}, "Waveform:", Theme::getInstance()->fg_light->foreground}};
|
||||||
|
|
||||||
// Text field to display the loaded file if any
|
// Text field to display the various status message of the app
|
||||||
Text text_loaded_file{{0, 140, 30 * 8, 16}, ""};
|
Text text_app_status{{0, 160, 30 * 8, 16}, ""};
|
||||||
|
|
||||||
// OptionsField for selectable sample rates.
|
// OptionsField for selectable sample rates.
|
||||||
OptionsField field_sample_rate{{55, 18}, 7, {{"250k", 250000U}, {"1M", 1000000U}, {"2M", 2000000U}, {"5M", 5000000U}, {"10M", 10000000U}, {"20M", 20000000U}}};
|
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 for step symbol rates.
|
||||||
OptionsField field_bit_duration_step{{210, 18}, 7, {{"1", 1}, {"10", 10}, {"100", 100}}};
|
OptionsField field_step{{210, 20}, 7, {{"1", 1}, {"10", 10}, {"100", 100}}};
|
||||||
|
// Number fields for symbols, pause_symbol between repeat, and repeat count.
|
||||||
// Number fields for symbols, pause between symbols, and repeat count.
|
NumberField field_symbol_rate{{96, 40}, 4, {0, 9999}, 1, '0', false};
|
||||||
NumberField field_bit_duration{{176, 40}, 4, {0, 9999}, 1, '0', false};
|
NumberField field_pause_symbol_duration{{96, 60}, 4, {0, 9999}, 1, '0', false};
|
||||||
NumberField field_pause_symbol{{78, 60}, 4, {0, 200}, 1, '0', false};
|
NumberField field_repeat{{210, 40}, 3, {1, 999}, 1, '0', false};
|
||||||
NumberField field_repeat{{55, 40}, 3, {0, 100}, 1, '0', false};
|
|
||||||
|
|
||||||
// Text field to display the payload data.
|
// Text field to display the payload data.
|
||||||
Text text_payload{{0 * 8, 90, 30 * 8, 16}, ""};
|
Text text_payload{{0 * 8, 100, 30 * 8, 16}, ""};
|
||||||
|
|
||||||
// Buttons for setting configurations, opening files, and starting transmission.
|
// Buttons for setting configurations, opening files, and starting transmission.
|
||||||
Button button_set{{0, 110, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
|
Button button_set{{0, 125, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
|
||||||
Button button_open{{68, 110, 80, 28}, LanguageHelper::currentMessages[LANG_OPEN_FILE]};
|
Button button_open{{68, 125, 80, 28}, LanguageHelper::currentMessages[LANG_OPEN_FILE]};
|
||||||
Button button_save{{154, 110, 80, 28}, LanguageHelper::currentMessages[LANG_SAVE_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]};
|
Button button_send_stop{{80, 273, 80, 32}, LanguageHelper::currentMessages[LANG_SEND]};
|
||||||
|
|
||||||
// Progress bar to display transmission progress.
|
// Progress bar to display transmission progress.
|
||||||
@ -131,6 +132,6 @@ class OOKRemoteAppView : public View {
|
|||||||
Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
|
Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace ui::external_app::ook_remote
|
}; // namespace ui::external_app::ook_editor
|
||||||
|
|
||||||
#endif /*__UI_OOK_REMOTE_H__*/
|
#endif /*__UI_OOK_EDITOR_H__*/
|
@ -1,369 +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_ook_remote.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::ook_remote {
|
|
||||||
|
|
||||||
void OOKRemoteAppView::focus() {
|
|
||||||
button_set.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// `start_tx` method: Configures and begins OOK data transmission with a specific message.
|
|
||||||
void OOKRemoteAppView::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_DURATION_VALUE = field_bit_duration.value();
|
|
||||||
int32_t REPEAT = field_repeat.value();
|
|
||||||
int32_t PAUSE_SYMBOL = field_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_DURATION_VALUE, // Calculate symbol period based on repetition rate
|
|
||||||
REPEAT, // Set the number of times the whole bitstream is repeated
|
|
||||||
PAUSE_SYMBOL // Set the pause between symbols
|
|
||||||
);
|
|
||||||
progressbar.set_max(REPEAT); // 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// `stop_tx` method: Stops the transmission and resets the progress bar.
|
|
||||||
void OOKRemoteAppView::stop_tx() {
|
|
||||||
is_transmitting = false;
|
|
||||||
transmitter_model.disable(); // Disable the transmitter
|
|
||||||
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 OOKRemoteAppView::on_file_changed(const fs::path& new_file_path) {
|
|
||||||
payload.clear(); // Clear previous payload content
|
|
||||||
text_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
|
|
||||||
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
|
|
||||||
rf::Frequency frequency = std::stoull(frequency_str);
|
|
||||||
field_frequency.set_value(frequency);
|
|
||||||
transmitter_model.set_target_frequency(frequency);
|
|
||||||
|
|
||||||
// Convert and assign symbols rate
|
|
||||||
unsigned int bit_duration_value = static_cast<unsigned int>(atoi(symbols_rate_str.c_str()));
|
|
||||||
|
|
||||||
field_bit_duration.set_value(bit_duration_value);
|
|
||||||
|
|
||||||
// Convert and assign repeat count
|
|
||||||
unsigned int repeat = static_cast<unsigned int>(atoi(repeat_str.c_str()));
|
|
||||||
|
|
||||||
field_repeat.set_value(repeat);
|
|
||||||
|
|
||||||
// Convert and assign pause per symbol
|
|
||||||
unsigned int pause_symbol = static_cast<unsigned int>(atoi(pause_symbol_str.c_str()));
|
|
||||||
|
|
||||||
field_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_send_stop.focus();
|
|
||||||
} else {
|
|
||||||
text_payload.set("parent not available");
|
|
||||||
}
|
|
||||||
text_loaded_file.set("Loaded: " + new_file_path.filename().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// `on_tx_progress` method: Updates the progress bar based on transmission progress.
|
|
||||||
void OOKRemoteAppView::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 OOKRemoteAppView::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();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OOKRemoteAppView::on_save_file(const std::string value) {
|
|
||||||
// check if there is a payload, else Error
|
|
||||||
if (payload.length() < 1) {
|
|
||||||
text_loaded_file.set("Error: no payload !!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_directory(ook_remote_dir);
|
|
||||||
auto new_path = ook_remote_dir / value + ".OOK";
|
|
||||||
if (save_ook_to_file(new_path)) {
|
|
||||||
text_loaded_file.set("Saved to " + new_path.string());
|
|
||||||
} else {
|
|
||||||
text_loaded_file.set("Error saving " + new_path.string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OOKRemoteAppView::save_ook_to_file(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write informations
|
|
||||||
src->write_line(to_string_dec_uint(field_frequency.value()) + " " +
|
|
||||||
field_sample_rate.selected_index_name() + " " +
|
|
||||||
to_string_dec_uint(field_bit_duration.value()) + " " +
|
|
||||||
to_string_dec_uint(field_repeat.value()) + " " +
|
|
||||||
to_string_dec_uint(field_pause_symbol.value()) + " " +
|
|
||||||
payload);
|
|
||||||
|
|
||||||
// Close files
|
|
||||||
src.reset();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor for `OOKRemoteAppView`: Disables the transmitter and shuts down the baseband
|
|
||||||
OOKRemoteAppView::~OOKRemoteAppView() {
|
|
||||||
transmitter_model.disable();
|
|
||||||
baseband::shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructor for `OOKRemoteAppView`: Sets up the app view and initializes UI elements
|
|
||||||
OOKRemoteAppView::OOKRemoteAppView(NavigationView& nav)
|
|
||||||
: nav_{nav} {
|
|
||||||
baseband::run_image(portapack::spi_flash::image_tag_ook);
|
|
||||||
|
|
||||||
add_children({&field_frequency,
|
|
||||||
&tx_view,
|
|
||||||
&button_send_stop,
|
|
||||||
&label_bit_duration_step,
|
|
||||||
&field_bit_duration_step,
|
|
||||||
&label_sample_rate,
|
|
||||||
&field_sample_rate,
|
|
||||||
&label_bit_duration,
|
|
||||||
&field_bit_duration,
|
|
||||||
&label_bit_duration_unit,
|
|
||||||
&text_payload,
|
|
||||||
&button_set,
|
|
||||||
&progressbar,
|
|
||||||
&label_repeat,
|
|
||||||
&field_repeat,
|
|
||||||
&label_pause_symbol,
|
|
||||||
&field_pause_symbol,
|
|
||||||
&label_payload,
|
|
||||||
&text_loaded_file,
|
|
||||||
&label_waveform,
|
|
||||||
&waveform,
|
|
||||||
&button_open,
|
|
||||||
&button_save});
|
|
||||||
|
|
||||||
// Initialize default values for controls
|
|
||||||
field_pause_symbol.set_value(100);
|
|
||||||
field_repeat.set_value(4);
|
|
||||||
|
|
||||||
button_open.on_select = [this](Button&) {
|
|
||||||
auto open_view = nav_.push<FileLoadView>(".OOK");
|
|
||||||
ensure_directory(ook_remote_dir);
|
|
||||||
open_view->push_dir(ook_remote_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();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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_bit_duration.on_change = [this](int32_t) {
|
|
||||||
text_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
};
|
|
||||||
// clean out loaded file name if field is changed
|
|
||||||
field_repeat.on_change = [this](int32_t) {
|
|
||||||
text_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
};
|
|
||||||
// clean out loaded file name if field is changed
|
|
||||||
field_pause_symbol.on_change = [this](int32_t) {
|
|
||||||
text_loaded_file.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_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
};
|
|
||||||
|
|
||||||
// setting up FrequencyField
|
|
||||||
field_frequency.set_value(ook_remote_tx_freq);
|
|
||||||
|
|
||||||
// clean out loaded file name if field is changed, save ook_remote_tx_freq
|
|
||||||
field_frequency.on_change = [this](rf::Frequency f) {
|
|
||||||
ook_remote_tx_freq = f;
|
|
||||||
text_loaded_file.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_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
field_bit_duration_step.on_change = [this](size_t, int32_t value) {
|
|
||||||
text_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
field_bit_duration.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();
|
|
||||||
text_loaded_file.set(""); // Clear loaded file text field
|
|
||||||
});
|
|
||||||
};
|
|
||||||
draw_waveform();
|
|
||||||
button_send_stop.on_select = [this](Button&) {
|
|
||||||
if (!is_transmitting) {
|
|
||||||
start_tx(payload); // Begin transmission
|
|
||||||
} else {
|
|
||||||
stop_tx();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} // namespace ui::external_app::ook_remote
|
|
@ -48,4 +48,4 @@ const std::filesystem::path splash_dir = u"SPLASH";
|
|||||||
const std::filesystem::path sstv_dir = u"SSTV";
|
const std::filesystem::path sstv_dir = u"SSTV";
|
||||||
const std::filesystem::path wav_dir = u"WAV";
|
const std::filesystem::path wav_dir = u"WAV";
|
||||||
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
|
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
|
||||||
const std::filesystem::path ook_remote_dir = u"OOKFILES";
|
const std::filesystem::path ook_editor_dir = u"OOKFILES";
|
||||||
|
@ -50,6 +50,6 @@ extern const std::filesystem::path splash_dir;
|
|||||||
extern const std::filesystem::path sstv_dir;
|
extern const std::filesystem::path sstv_dir;
|
||||||
extern const std::filesystem::path wav_dir;
|
extern const std::filesystem::path wav_dir;
|
||||||
extern const std::filesystem::path whipcalc_dir;
|
extern const std::filesystem::path whipcalc_dir;
|
||||||
extern const std::filesystem::path ook_remote_dir;
|
extern const std::filesystem::path ook_editor_dir;
|
||||||
|
|
||||||
#endif /* __FILE_PATH_H__ */
|
#endif /* __FILE_PATH_H__ */
|
||||||
|
158
firmware/application/ook_file.cpp
Normal file
158
firmware/application/ook_file.cpp
Normal 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
firmware/application/ook_file.hpp
Normal file
49
firmware/application/ook_file.hpp
Normal 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__
|
@ -1 +0,0 @@
|
|||||||
433920000 250k 2300 5 100 101010101010101010101010100010101100101100110010110011001100110011001011010011010010110101001010110100110100110010101011010010110001010110010110011001011001100110011001100101101001101001011010100101011010011010011001010101101001011000101011001011001100101100110011001100110010110100110100101101010010101101001101001100101010110100101
|
|
@ -1 +0,0 @@
|
|||||||
315000000 250k 2300 5 100 101010101010101010101010100010101100101100110010110011001100110011001011010011010010110101001010110100110100110010101011010010110001010110010110011001011001100110011001100101101001101001011010100101011010011010011001010101101001011000101011001011001100101100110011001100110010110100110100101101010010101101001101001100101010110100101
|
|
Loading…
Reference in New Issue
Block a user