ROOK(Remote On-Off Keying) for to PortaPack HackRF

Recently I was thinking about how a hardware hacking professional could test his OOK(On-Off keying) signals demodulated at bit level, without the need of having to program any device, I wanted something that was within reach and that was only either modify parameters or load them from a file, So was born ROOK(Remote On-Off Keying) an external application for the HackRF PortaPack that allows you to adjust the parameters or load them from the PP of a signal that you have previously analyzed and demodulated, and then transmit it.

In order to achieve the construction of this application I first had to understand how I could create an external application for PP (PortaPack), in previous articles we had already built a basic application that transmitted the information for a specific device, and this was an internal application of the PP, but nothing that could be official for the project, so I went to the wiki where they talked a little about this situation.

The code

The first thing to start with is to create our folder called rook in the path of the firmware downloaded from the mayhem Portapack project in the path \firmware\application\external\rook
inside this folder we will create 3 files which are the following:

main.cpp
ui_rook.hpp
ui_rook.cpp

main.cpp

/*
 * 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
};
}

The main.cpp file in your project defines the basic information and entry point of the external application for PortaPack. Let’s look at the details and purpose of each part of the code:

  • Application initialization initialize_app:
void initialize_app(ui::NavigationView& nav) {
    nav.push<ROOKAppView>();
}

The initialize_app function configures the application. It uses nav.push() to add the main view (ROOKAppView) to the PortaPack navigation system.
This is the point where the application is displayed to the user, allowing ROOKAppView to handle the main GUI and logic.

  • Definition of the application_information_t Structure:
__attribute__((section(".external_app.app_rook.application_information"), used)) application_information_t _application_information_rook = { ... };

This structure provides the information necessary for PortaPack to recognize and integrate the application.
The attribute((section(…), used)) directive ensures that the application information is placed in a specific section of memory to be used by the PortaPack system.

  • Specific fields of application_information_t:
  • memory_location: Defines the initial memory address of the application, although here it is left at 0x00000000, probably so that the system fills it automatically.
  • externalAppEntry: Points to initialize_app, which means that when the application is executed, this function will be called to start ROOKAppView.
  • header_version and app_version: Defines header and app versions.
  • app_name: Defines the name of the application, in this case “ROOK”.
  • bitmap_data: Specifies an icon in hexadecimal format to represent the application in the menu.
  • icon_color: Specifies the color of the menu icon, here it is defined as ui::Color::orange().v.
  • menu_location: Defines the location of the application in the menu, assigned to app_location_t::TX.
  • m4_app_tag and m4_app_offset: m4_app_tag identifies the application with a tag ({‘P’, ‘O’, ‘O’, ‘K’}) in the flash memory of the M4 chip. m4_app_offset is defined as 0x00000000, indicating that it will be filled during compilation.

ui_rook.hpp

/*
 * 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 * 4, 0 * 16}, true};

        // Labels for various fields such as sample rate and repeat count.
        Labels sample_rate {{{0,30}, "S/Rate:     ",Theme::getInstance()->fg_light->foreground}};
        Labels repeat {{{0,50}, "Repeat:     ",Theme::getInstance()->fg_light->foreground}};
        Labels field_symbol_rate {{{111, 30}, "Symbols:     ",Theme::getInstance()->fg_light->foreground}};
        Labels field_pause_symbol {{{111, 50}, "Pause/Sym:     ",Theme::getInstance()->fg_light->foreground}};
        Labels field_symbol_us_rate {{{210, 30}, "us     ",Theme::getInstance()->fg_light->foreground}};
        Labels step_symbol_rate {{{165, 0}, "Step:    ",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, 30},7,{{"250k", 250000U},{"1M", 1000000U},{"2M", 2000000U},{"5M", 5000000U},{"10M", 10000000U},{"20M", 20000000U}}};
        
        // OptionsField for step symbol rates.
        OptionsField cant_step_symbol_rate{{210, 0},7,{{"1", 1},{"10", 10},{"100", 100}}};
        
        // Number fields for symbols, pause between symbols, and repeat count.
        NumberField cant_symbol_rate{{176, 30},4,{0, 9999},1,'0',false};
        NumberField cant_pause_symbol{{200, 50},4,{0, 200},1,'0',false};
        NumberField cant_repeat{{55, 50},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};
    };

};

#endif /*__UI_ROOK_H__*/

The ui_rook.hpp file is the header file for the ROOKAppView class, which defines the interface and logic of the ROOK application in the PortaPack system. This header includes the UI components and essential variables that will be used to handle data transmission, such as frequency, sample rate, symbol and waveform buffer.

Includes Necessary Dependencies:

#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"

These dependencies include the libraries needed to create and manage the graphical interface, navigation, radio transmission, and configuration of the ROOK application.

#define PROGRESS_MAX 100
#define OOK_SAMPLERATE_DEFAULT 2280000U
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U  // Frecuencia predeterminada de transmisión (433.92 MHz)
#define WAVEFORM_BUFFER_SIZE 550

Defines constants for the default transmission values, such as OOK_SAMPLERATE_DEFAULT and TRANSMISSION_FREQUENCY_DEFAULT.
WAVEFORM_BUFFER_SIZE defines the size of the waveform buffer.

ROOKAppView Class Declaration:

class ROOKAppView : public View {

The ROOKAppView class inherits from View and represents the main view of the application.

Public Class Methods:

void focus() override;
ROOKAppView(NavigationView &nav);
~ROOKAppView();
std::string title() const override { return "RemoteOOK"; };

focus(): Overwrites to handle the focus of the view.
ROOKAppView (constructor): Initializes the view and takes nav as reference for navigation.
title(): Returns the title of the application (“RemoteOOK”).

Private Attributes:

Status and Configuration Attributes:

NavigationView& nav_;
std::string payload{""};
uint32_t progress = 0;
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE];

nav_: Reference to navigation.
payload: String that stores the data content.
progress: Controls the progress of the transmission.
waveform_buffer: Waveform data buffer.

Private View Methods:

void update();
void draw_waveform();
void start_tx(const std::string& message);
void stop_tx();
void on_tx_progress(const uint32_t progress, const bool done);
void on_file_changed(const std::filesystem::path& new_file_path);

Methods to update the view, start and stop transmission, manage transmission progress, and update the uploaded file.

MessageHandlerRegistration message_handler_tx_progress{
    Message::ID::TXProgress,
    [this](const Message* const p) {
        const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
        this->on_tx_progress(message.progress, message.done);
    }
};

message_handler_tx_progress handles transmission progress messages via a callback.

Interface Components and Transmission Controls:

Transmission Configuration and States:

TxRadioState radio_state_{TRANSMISSION_FREQUENCY_DEFAULT, 1750000, OOK_SAMPLERATE_DEFAULT};
app_settings::SettingsManager settings_{"tx_rook", app_settings::Mode::TX};

radio_state_: Stores the frequency, bandwidth and sample rate of the transmission.
settings_: Settings manager.

UI components and Widgets:

TxFrequencyField field_frequency{{0 * 8, 0 * 16}, nav_};
TransmitterView2 tx_view{{20 * 4, 0 * 16}, true};
OptionsField field_sample_rate{{55, 30},7,{{"250k", 250000U},{"1M", 1000000U},{"2M", 2000000U},{"5M", 5000000U},{"10M", 10000000U},{"20M", 20000000U}}};
NumberField cant_symbol_rate{{176, 30},4,{0, 9999},1,'0',false};

field_frequency, field_sample_rate, cant_symbol_rate, etc., are UI components that allow the user to set frequency, sample rate, symbols rate, etc..
Each widget represents a setting that the user can adjust in the interface.

Labels and Buttons:

Definition of Labels:

Labels sample_rate {{{0,30}, "S/Rate:     ",Theme::getInstance()->fg_light->foreground}};
Labels repeat {{{0,50}, "Repeat:     ",Theme::getInstance()->fg_light->foreground}};

Labels display texts such as “S/Rate”, “Repeat”, “Symbols” on the interface.

Definition of Buttons:

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"};

Buttons for opening files, starting transmission (Start), and setting configurations (Set).

In summary:

This file defines the essential components, methods and configuration for ROOKAppView, which handles the main view and functionality of the ROOK application in the PortaPack system. The widgets, buttons, labels and methods needed to transmit data and set parameters from the interface are set here.

ui_rook.cpp

/*
 * 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 = std::stoi(symbols_rate_str);
            cant_symbol_rate.set_value(symbols_rate);

            // Convert and assign repeat count
            unsigned int repeat = std::stoi(repeat_str);
            cant_repeat.set_value(repeat);

            // Convert and assign pause per symbol
            unsigned int pause_symbol = std::stoi(pause_symbol_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>(".TXT");
            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
        };
    }
}

here I will detail the most important parts

start_tx

This function initiates the data transmission by configuring the transmitter’s settings, including sample rate, symbol rate, repeat count, and pause per symbol. It converts the input message into a bitstream, sets the transmission frequency, enables the transmitter, and sends the data.

stop_tx

Stops the ongoing data transmission by disabling the transmitter and resetting the progress bar to zero.

on_file_changed

Called when a new file is loaded. It reads and parses the data from the file, extracting frequency, sample rate, symbol rate, repeat count, pause per symbol, and binary payload. It updates the UI components with these values.

on_tx_progress

Updates the progress bar based on the current transmission progress. If the transmission is complete, it automatically stops it.

draw_waveform

Draws the waveform for the payload on the UI. It uses padding to create a realistic waveform display and updates the waveform buffer based on the binary payload.

ROOKAppView Constructor

Initializes the ROOKAppView by setting up the main UI components, registering buttons, and setting default values for transmission parameters. Configures button actions for setting payload and loading files.

These functions provide the core functionality for configuring, initiating, managing, and visualizing the transmission process in the ROOK application for PortaPack.

We already have part of the code ready now we need to adjust some changes in the compilation toolchain to make this work, so:

We are located in the file \firmware\application\external\external.cmake and we add the following line.

#rook
external/rook/main.cpp
external/rook/ui_rook.cpp

In the same file we add rook to the project

set(EXTAPPLIST
    ...
	rook
    ...
)

Now we go to the link file \firmware\application\external\external.ld

and in the MEMORY session we add the memory mapping that was mentioned here

MEMORY
{
    /*
     * External apps: regions can't overlap so addresses are corrected after build.
     * Picking uncommon address values for search & replace in binaries (no false positives) - 0xADB00000-0xADEF0000 seems to be good.
     * Also need to consider processor memory map - reading 0xADxxxxxx generates a fault which may be better than unexpected behavior.
     * External app address ranges below must match those in python file "external_app_info.py".
     */
    ...
    ram_external_app_rook(rwx) : org = 0xADCD0000, len = 32k 
}

Also in SECTIONS.

SECTIONS
{
  ....
  .external_app_rook : ALIGN(4) SUBALIGN(4)
    {
        KEEP(*(.external_app.app_rook.application_information));
        *(*ui*external_app*rook*);
    } > ram_external_app_rook
}

These are all the changes we need to make, we are now ready for the compilation process.

The compilation

Skipping the entire toolchain configuration process, run the compilation commands

cd /path_firmware/mayhem-firmware/
mkdir build && cd build
cmake ..
maje -j8

This generates our firmware and our app, which we must copy to our portapack SD in the APPS folder and we load the firmware to the portapack like this

hackrf_spiflash -w /path_firmware/build/firmware/portapack-h1_h2-mayhem.bin

With this we will have the application ready to use in our portapack

The application

The application can be found in the Transmission section.

Let’s look at the parameters that make it up

  1. Frequency: First we have the frequency section where we select the frequency we want to operate on.
  2. Transmission: Then we have the transmission section where we control gain and amplifier.
  3. Step: allows you to select the step for Symbols between 1, 10 or 100
  4. S/rate: Defines the sample rate of your signal analysis.
  5. Symbols: The number of symbols in the signal you analyzed and synthesized
  6. Repeat: The number of repetitions of the signal.
  7. Pause/Sym: Pause between symbols of the signal you analyzed and want to synthesize
  8. Set button: Opens a modal window to write your payload directly.
  9. Open file: load settings directly from a file
  10. Start: Start the transmission

Let’s see an example using the application by directly configuring the signal from the Set button.

Now let’s see an example using the Open File function.

In order to achieve this you must consider a structure in your file where you will store the information.

  1. The file must be on your PortaPack SD card and have the .TXT extension.
  2. The file must have the following structure, separated by spaces
    • Frequency SampleRate SymbolsRate Repeat Pause/Symbols SignalBinary
  3. Sample Rate supports the following arguments:
    • 250k, 1M, 2M, 5M, 10M, 20M
  4. Let’s see an example below
27000000 1M 1076 4 100 01110111011101110101010101010101010101110111011101110101

We set the frequency to 27 MHz sample rate to 1MHz Symbol Rate to 1076us repeat 4, Pause/symbols to 100 and the signal.

You can finally see it in action.

Thanks a lot.


Leave a Reply

Your email address will not be published. Required fields are marked *