Flipper sub (raw+binraw AND ONLY OOK) TX (#2361)

This commit is contained in:
Totoo 2024-11-16 18:03:53 +01:00 committed by GitHub
parent 31c53dc455
commit 59f72cbff1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 889 additions and 34 deletions

View File

@ -117,7 +117,12 @@ set(EXTCPPSRC
#cvs_spam
external/cvs_spam/main.cpp
external/cvs_spam/cvs_spam.cpp
external/cvs_spam/cvs_spam.cpp
#flippertx
external/flippertx/main.cpp
external/flippertx/ui_flippertx.cpp
)
set(EXTAPPLIST
@ -149,4 +154,5 @@ set(EXTAPPLIST
#acars_rx
ookbrute
shoppingcart_lock
flippertx
)

View File

@ -51,6 +51,7 @@ MEMORY
ram_external_app_shoppingcart_lock(rwx) : org = 0xADCA0000, len = 32k
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
}
SECTIONS
@ -224,4 +225,10 @@ SECTIONS
*(*ui*external_app*ookbrute*);
} > ram_external_app_ookbrute
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_flippertx.application_information));
*(*ui*external_app*flippertx*);
} > ram_external_app_flippertx
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* 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_flippertx.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::flippertx {
void initialize_app(ui::NavigationView& nav) {
nav.push<FlipperTxView>();
}
} // namespace ui::external_app::flippertx
extern "C" {
__attribute__((section(".external_app.app_flippertx.application_information"), used)) application_information_t _application_information_flippertx = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::flippertx::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "FlipperTx",
/*.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_ookstreaming */ {'P', 'O', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}

View File

@ -0,0 +1,285 @@
/*
* Copyright (C) 2024 HTotoo
*
* 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_flippertx.hpp"
#include "audio.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "buffer_exchange.hpp"
using namespace portapack;
using namespace ui;
namespace ui::external_app::flippertx {
void FlipperTxView::focus() {
button_browse.focus();
}
void FlipperTxView::set_ready() {
ready_signal = true;
}
FlipperTxView::FlipperTxView(NavigationView& nav)
: nav_{nav} {
add_children({&button_startstop,
&field_frequency,
&tx_view,
&field_filename,
&button_browse});
button_startstop.on_select = [this](Button&) {
if (is_running) {
stop();
} else {
start();
}
};
button_browse.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".sub");
open_view->push_dir(subghz_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
if (on_file_changed(new_file_path)) {
; // tif (button_startstop.parent()) button_startstop.focus(); parent_ is null error.....
}
};
};
}
bool FlipperTxView::on_file_changed(std::filesystem::path new_file_path) {
submeta = read_flippersub_file(new_file_path);
filename = "";
if (!submeta.is_valid()) {
field_filename.set_text("File: err, bad file");
return false;
}
proto = submeta.value().protocol;
if (proto != FLIPPER_PROTO_RAW && proto != FLIPPER_PROTO_BINRAW) { // temp disabled
field_filename.set_text("File: err, not supp. proto");
return false;
}
preset = submeta.value().preset;
if (preset != FLIPPER_PRESET_OOK) {
field_filename.set_text("File: err, not supp. preset");
return false;
}
te = submeta.value().te;
binraw_bit_count = submeta.value().binraw_bit_count;
/*if (binraw_bit_count >= 512 * 800) {
field_filename.set_text("File: err, too long"); // should stream, but not in this scope YET
return false;
}*/
field_filename.set_text("File: " + new_file_path.string());
filename = new_file_path;
return true;
}
void FlipperTxView::stop() {
if (is_running && replay_thread) replay_thread.reset();
is_running = false;
ready_signal = false;
transmitter_model.disable();
baseband::shutdown();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_START]);
}
bool FlipperTxView::start() {
if (filename.empty()) return false;
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
transmitter_model.enable();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_STOP]);
// start thread
replay_thread = std::make_unique<FlipperPlayThread>(
filename,
1024, 4,
&ready_signal,
submeta.value().protocol,
submeta.value().te,
[](uint32_t return_code) {
ReplayThreadDoneMessage message{return_code};
EventDispatcher::send_message(message);
});
is_running = true;
return true;
}
void FlipperTxView::on_tx_progress(const bool done) {
if (done) {
if (is_running) {
stop();
}
}
}
FlipperTxView::~FlipperTxView() {
stop();
}
FlipperPlayThread::FlipperPlayThread(
std::filesystem::path filename,
size_t read_size,
size_t buffer_count,
bool* ready_signal,
FlipperProto proto,
uint16_t te,
std::function<void(uint32_t return_code)> terminate_callback)
: config{read_size, buffer_count},
filename{filename},
ready_sig{ready_signal},
proto{proto},
te{te},
terminate_callback{std::move(terminate_callback)} {
thread = chThdCreateFromHeap(NULL, 6 * 1024, NORMALPRIO + 10, FlipperPlayThread::static_fn, this);
}
FlipperPlayThread::~FlipperPlayThread() {
if (thread) {
chThdTerminate(thread);
if (thread->p_refs) chThdWait(thread);
thread = nullptr;
}
}
msg_t FlipperPlayThread::static_fn(void* arg) {
auto obj = static_cast<FlipperPlayThread*>(arg);
const auto return_code = obj->run();
if (obj->terminate_callback) {
obj->terminate_callback(return_code);
}
chThdExit(0);
return 0;
}
uint32_t FlipperPlayThread::run() {
BasebandReplay replay{&config};
BufferExchange buffers{&config};
StreamBuffer* prefill_buffer{nullptr};
int32_t read_result = 0;
// assume it is ok, since prev we checked it.
// open the sub file
File f; // don't worry, destructor will close it.
auto error = f.open(filename);
if (error) return READ_ERROR;
// seek to the first data
if (proto == FLIPPER_PROTO_RAW)
seek_flipper_raw_first_data(f);
else {
seek_flipper_binraw_first_data(f);
}
// Wait for FIFOs to be allocated in baseband
// Wait for _view to tell us that the buffers are ready
while (!(*ready_sig) && !chThdShouldTerminate()) {
chThdSleep(100);
};
uint8_t readall = 0;
int32_t endsignals[3] = {0, 42069, 613379}; // unlikely a valid data
// While empty buffers fifo is not empty...
while (!buffers.empty() && !chThdShouldTerminate()) {
prefill_buffer = buffers.get_prefill();
if (prefill_buffer == nullptr) {
buffers.put_app(prefill_buffer);
} else {
size_t c = 0;
for (c = 0; c < config.read_size / 4;) {
read_result = 0;
if (0 == readall) {
if (proto == FLIPPER_PROTO_RAW) {
auto data = read_flipper_raw_next_data(f);
if (!data.is_valid()) {
((int32_t*)prefill_buffer->data())[c] = endsignals[++readall];
} else {
read_result = data.value();
((int32_t*)prefill_buffer->data())[c] = read_result;
}
c++;
} else { // BINRAW
auto data = read_flipper_binraw_next_data(f);
if (!data.is_valid())
readall = 1;
else {
read_result = data.value();
// add 8 data
for (uint8_t bit = 0; bit < 8; bit++) {
((int32_t*)prefill_buffer->data())[c + bit] = ((get_flipper_binraw_bitvalue(read_result, (7 - bit)) ? 1 : -1) * te);
c++;
}
}
}
} else {
((int32_t*)prefill_buffer->data())[c] = endsignals[readall];
if (readall == 1) readall++;
c++;
}
}
prefill_buffer->set_size(config.read_size);
buffers.put(prefill_buffer);
}
};
baseband::set_fifo_data(nullptr);
if (readall) return END_OF_FILE;
while (!chThdShouldTerminate()) {
auto buffer = buffers.get();
int32_t read_result = 0;
for (size_t d = 0; d < buffer->capacity() / 4; d++) {
read_result = -133469;
if (!readall) {
if (proto == FLIPPER_PROTO_RAW) {
auto data = read_flipper_raw_next_data(f);
if (!data.is_valid()) {
readall = 1;
} else {
read_result = data.value();
}
} else {
auto data = read_flipper_binraw_next_data(f);
if (!data.is_valid())
readall = 1;
else {
read_result = data.value();
// add 8 data
for (uint8_t bit = 0; bit < 8; bit++) {
((int32_t*)prefill_buffer->data())[d + bit] = ((get_flipper_binraw_bitvalue(read_result, (7 - bit)) ? 1 : -1) * te);
}
d += 7;
continue;
}
}
}
if (readall >= 1 && readall <= 2) {
read_result = endsignals[readall++];
}
((int32_t*)buffer->data())[d] = read_result;
}
buffer->set_size(buffer->capacity());
buffers.put(buffer);
if (readall == 3) return END_OF_FILE;
}
return TERMINATED;
}
} // namespace ui::external_app::flippertx

View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 2024 HTotoo
*
* This file is part of PortaPack.
*
*/
#ifndef __UI_flippertx_H__
#define __UI_flippertx_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
#include "ui_freq_field.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "metadata_file.hpp"
#include "flipper_subfile.hpp"
#include "ui_fileman.hpp"
#include "baseband_api.hpp"
using namespace ui;
namespace ui::external_app::flippertx {
#define OOK_SAMPLERATE 2280000U
class FlipperPlayThread;
class FlipperTxView : public View {
public:
FlipperTxView(NavigationView& nav);
~FlipperTxView();
void focus() override;
std::string title() const override {
return "FlipperTx";
};
private:
NavigationView& nav_;
TxRadioState radio_state_{
433920000 /* frequency */,
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
TxFrequencyField field_frequency{
{0 * 8, 0 * 16},
nav_};
TransmitterView2 tx_view{
{11 * 8, 0 * 16},
/*short_ui*/ true};
app_settings::SettingsManager settings_{
"tx_flippertx", app_settings::Mode::TX};
TextField field_filename{
{0, 2 * 16, 300, 1 * 8},
"File: -"};
Button button_startstop{
{1, 6 * 16, 96, 24},
LanguageHelper::currentMessages[LANG_START]};
Button button_browse{
{1, 3 * 16 + 3, 96, 24},
LanguageHelper::currentMessages[LANG_BROWSE]};
bool is_running{false};
bool start();
void stop();
void set_ready();
void on_tx_progress(const bool done);
bool on_file_changed(std::filesystem::path new_file_path);
std::filesystem::path filename = {};
FlipperProto proto = FLIPPER_PROTO_UNSUPPORTED;
FlipperPreset preset = FLIPPER_PRESET_UNK;
uint16_t te = 0; // for binraw
uint32_t binraw_bit_count = 0;
bool ready_signal = false;
std::unique_ptr<FlipperPlayThread> replay_thread{};
Optional<flippersub_metadata> submeta{};
const std::filesystem::path subghz_dir = u"subghz";
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.done);
}};
MessageHandlerRegistration message_handler_fifo_signal{
Message::ID::RequestSignal,
[this](const Message* const p) {
const auto message = static_cast<const RequestSignalMessage*>(p);
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
this->set_ready();
}
}};
MessageHandlerRegistration message_handler_replay_thread_done{
Message::ID::ReplayThreadDone,
[this](const Message* const p) {
// const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
(void)p;
// stop(); //don't stop for now, stop when i get the tx finished msg
}};
};
struct BasebandReplay {
BasebandReplay(ReplayConfig* const config) {
baseband::replay_start(config);
}
~BasebandReplay() {
// baseband::replay_stop(); // wont, since we need to send out that is in the buffer
}
};
class FlipperPlayThread {
public:
FlipperPlayThread(
std::filesystem::path,
size_t read_size,
size_t buffer_count,
bool* ready_signal,
FlipperProto proto,
uint16_t te,
std::function<void(uint32_t return_code)> terminate_callback);
~FlipperPlayThread();
FlipperPlayThread(const FlipperPlayThread&) = delete;
FlipperPlayThread(FlipperPlayThread&&) = delete;
FlipperPlayThread& operator=(const FlipperPlayThread&) = delete;
FlipperPlayThread& operator=(FlipperPlayThread&&) = delete;
const ReplayConfig& state() const {
return config;
};
enum FlipperPlayThread_return {
READ_ERROR = 0,
END_OF_FILE,
TERMINATED
};
private:
ReplayConfig config;
std::filesystem::path filename;
bool* ready_sig;
FlipperProto proto;
uint16_t te;
std::function<void(uint32_t return_code)> terminate_callback;
Thread* thread{nullptr};
static msg_t static_fn(void* arg);
uint32_t run();
};
}; // namespace ui::external_app::flippertx
#endif /*__UI_flippertx_H__*/

View File

@ -29,15 +29,16 @@
namespace fs = std::filesystem;
using namespace std::literals;
const std::string_view filetype_name = "Filetype"sv;
const std::string_view frequency_name = "Frequency"sv;
const std::string_view latitude_name_old = "Latitute"sv;
const std::string_view longitude_name_old = "Longitude"sv;
const std::string_view latitude_name = "Lat"sv;
const std::string_view longitude_name = "Lon"sv;
const std::string_view protocol_name = "Protocol"sv;
const std::string_view preset_name = "Preset"sv;
const std::string_view te_name = "TE"sv; // only in BinRAW
const std::string filetype_name = "Filetype";
const std::string frequency_name = "Frequency";
const std::string latitude_name_old = "Latitute";
const std::string longitude_name_old = "Longitude";
const std::string latitude_name = "Lat";
const std::string longitude_name = "Lon";
const std::string protocol_name = "Protocol";
const std::string preset_name = "Preset";
const std::string te_name = "TE"; // only in BinRAW
const std::string bit_count_name = "Bit"; // for us, only in BinRAW
/*
Filetype: Flipper SubGhz Key File
@ -72,39 +73,54 @@ raw_data- positive: carrier for n time, negative: no carrier for n time. (us)
Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
File f;
auto error = f.open(path);
if (error)
return {};
flippersub_metadata metadata{};
auto reader = FileLineReader(f);
for (const auto& line : reader) {
auto cols = split_string(line, ':');
if (cols.size() != 2)
char ch = 0;
std::string line = "";
auto fr = f.read(&ch, 1);
while (!fr.is_error() && fr.value() > 0) {
if (line.length() < 130 && ch != '\n') line += ch;
if (ch != '\n') {
fr = f.read(&ch, 1);
continue;
}
auto it = line.find(':', 0);
if (it == std::string::npos) {
fr = f.read(&ch, 1);
continue; // Bad line.
if (cols[1].length() <= 1) continue;
std::string fixed = cols[1].data() + 1;
}
std::string fixed = line.data() + it + 1;
fixed = trim(fixed);
if (cols[0] == filetype_name) {
std::string head = line.substr(0, it);
line = "";
if (fixed.length() <= 1) {
fr = f.read(&ch, 1);
continue;
}
if (head == filetype_name) {
if (fixed != "Flipper SubGhz Key File" && fixed != "Flipper SubGhz RAW File") return {}; // not supported
} else if (cols[0] == frequency_name)
} else if (head == frequency_name)
parse_int(fixed, metadata.center_frequency);
else if (cols[0] == latitude_name)
else if (head == latitude_name)
parse_float_meta(fixed, metadata.latitude);
else if (cols[0] == longitude_name)
else if (head == longitude_name)
parse_float_meta(fixed, metadata.longitude);
else if (cols[0] == latitude_name_old)
else if (head == latitude_name_old)
parse_float_meta(fixed, metadata.latitude);
else if (cols[0] == longitude_name_old)
else if (head == longitude_name_old)
parse_float_meta(fixed, metadata.longitude);
else if (cols[0] == protocol_name) {
else if (head == protocol_name) {
if (fixed == "RAW") metadata.protocol = FLIPPER_PROTO_RAW;
if (fixed == "BinRAW") metadata.protocol = FLIPPER_PROTO_BINRAW;
} else if (cols[0] == te_name) {
} else if (head == te_name) {
metadata.te = atoi(fixed.c_str());
} else if (cols[0] == preset_name) {
} else if (head == bit_count_name) {
metadata.binraw_bit_count = atol(fixed.c_str());
} else if (head == preset_name) {
if (fixed.find("FSK") != std::string::npos) {
metadata.preset = FLIPPER_PRESET_2FSK;
} else if (fixed.find("Ook") != std::string::npos) {
@ -112,12 +128,92 @@ Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
} else if (fixed.find("Custom") != std::string::npos) {
metadata.preset = FLIPPER_PRESET_CUSTOM;
}
} else
continue;
}
fr = f.read(&ch, 1);
}
f.close();
if (metadata.center_frequency == 0) return {}; // Parse failed.
return metadata;
}
bool seek_flipper_raw_first_data(File& f) {
f.seek(0);
std::string chs = "";
char ch;
while (f.read(&ch, 1)) {
if (ch == '\r') continue;
if (ch == '\n') {
chs = "";
continue;
};
chs += ch;
if (ch == 0) break;
if (chs == "RAW_Data: ") {
return true;
}
}
return false;
}
bool seek_flipper_binraw_first_data(File& f, bool seekzero) {
if (seekzero) f.seek(0);
std::string chs = "";
char ch;
while (f.read(&ch, 1)) {
if (ch == '\r') continue;
if (ch == '\n') {
chs = "";
continue;
};
if (ch == 0) break;
chs += ch;
if (chs == "Data_RAW: ") {
return true;
}
}
return false;
}
Optional<int32_t> read_flipper_raw_next_data(File& f) {
// RAW_Data: 5832 -12188 130 -162
std::string chs = "";
char ch = 0;
while (f.read(&ch, 1).is_ok()) {
if (ch == '\r') continue; // should not present
if ((ch == ' ') || ch == '\n') {
if (chs == "RAW_Data:") {
chs = "";
continue;
}
break;
};
if (ch == 0) break;
chs += ch;
}
if (chs == "") return {};
return atol(chs.c_str());
}
Optional<uint8_t> read_flipper_binraw_next_data(File& f) {
// Data_RAW: 02 10 84 BUT THERE ARE Bit_RAW lines to skip!
std::string chs = "";
char ch = 0;
while (f.read(&ch, 1)) {
if (ch == '\r') continue; // should not present
if ((ch == ' ') || ch == '\n') {
if (chs == "RAW_Data:") {
chs = "";
continue;
}
break;
};
if (ch == 0) break;
chs += ch;
}
if (chs == "") return {};
return static_cast<uint8_t>(std::stoul(chs, nullptr, 16));
}
bool get_flipper_binraw_bitvalue(uint8_t byte, uint8_t nthBit) {
return (byte & (1 << nthBit)) != 0;
}

View File

@ -44,9 +44,15 @@ struct flippersub_metadata {
FlipperProto protocol = FLIPPER_PROTO_UNSUPPORTED;
FlipperPreset preset = FLIPPER_PRESET_UNK;
uint16_t te = 0;
uint32_t binraw_bit_count = 0;
};
Optional<flippersub_metadata> read_flippersub_file(const std::filesystem::path& path);
bool seek_flipper_raw_first_data(File& f);
bool seek_flipper_binraw_first_data(File& f, bool seekzero = true);
Optional<int32_t> read_flipper_raw_next_data(File& f);
Optional<uint8_t> read_flipper_binraw_next_data(File& f);
bool get_flipper_binraw_bitvalue(uint8_t byte, uint8_t nthBit);
// Maybe sometime there will be a data part reader / converter

View File

@ -656,6 +656,14 @@ set(MODE_CPPSRC
)
DeclareTargets(PADT adsbtx)
### OOKStream
set(MODE_CPPSRC
proc_ook_stream_tx.cpp
)
DeclareTargets(POSK ookstream)
### HackRF "factory" firmware

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2024 HTotoo
*
* 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 "proc_ook_stream_tx.hpp"
#include "sine_table_int8.hpp"
#include "portapack_shared_memory.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
OOKProcessorStreamed::OOKProcessorStreamed() {
configured = false;
baseband_thread.start();
}
inline void OOKProcessorStreamed::write_sample(const buffer_c8_t& buffer, bool bit_value, size_t i) {
int8_t re, im;
if (bit_value) {
phase = (phase + 200); // What ?
sphase = phase + (64 << 18);
re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
} else {
re = 0;
im = 0;
}
buffer.p[i] = {re, im};
}
void OOKProcessorStreamed::execute(const buffer_c8_t& buffer) {
if (!configured || !stream) return;
for (size_t i = 0; i < buffer.count; i++) {
if (rem_samples <= curr_samples) {
// get a new sample from stream
int32_t sample = -13346;
rem_samples = 0; // reset my pointer
curr_samples = 0;
size_t readed = 0;
if (configured) readed = stream->read(&sample, 4); // read from stream // todo htotoo error handling?!
if (readed == 0) {
txprogress_message.progress = -10;
shared_memory.application_queue.push(txprogress_message); // debug
} else {
if (sample == endsignals[readerrs + 1]) { // if no more samples, stop
readerrs++;
if (readerrs == 2) {
configured = false;
txprogress_message.done = true;
txprogress_message.progress = 100;
curr_hilow = false;
shared_memory.application_queue.push(txprogress_message);
}
} else {
if (sample < 0) {
rem_samples = OOK_SAMPLERATE * ((-1 * sample) / 1000000.0);
curr_hilow = false;
} else {
rem_samples = OOK_SAMPLERATE * (sample / 1000000.0);
curr_hilow = true;
}
}
}
}
++curr_samples;
write_sample(buffer, curr_hilow, i);
}
}
void OOKProcessorStreamed::on_message(const Message* const message) {
switch (message->id) {
case Message::ID::ReplayConfig:
configured = false;
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
break;
case Message::ID::FIFOData:
configured = true;
txprogress_message.progress = -4;
shared_memory.application_queue.push(txprogress_message);
break;
default:
break;
}
}
void OOKProcessorStreamed::replay_config(const ReplayConfigMessage& message) {
if (message.config) {
txprogress_message.progress = -2;
shared_memory.application_queue.push(txprogress_message);
stream = std::make_unique<StreamOutput>(message.config);
// Tell application that the buffers and FIFO pointers are ready, prefill
RequestSignalMessage sig_message{RequestSignalMessage::Signal::FillRequest};
shared_memory.application_queue.push(sig_message);
} else {
txprogress_message.progress = -3;
shared_memory.application_queue.push(txprogress_message);
stream.reset();
}
}
int main() {
EventDispatcher event_dispatcher{std::make_unique<OOKProcessorStreamed>()};
event_dispatcher.run();
return 0;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2024 HTotoo
*
* 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.
*/
/*
For usage check the FlipperTX app. Don't forget to "close" the tx by sending 42069, 613379 values at the end of the stream.
Only close baseband when you get the TX done msg, not on replay thread done, because, there can still data in the buffer.
*/
#ifndef __PROC_OOKSTREAMTX_HPP__
#define __PROC_OOKSTREAMTX_HPP__
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "stream_output.hpp"
#include <array>
#include <memory>
#define OOK_SAMPLERATE 2280000U
class OOKProcessorStreamed : public BasebandProcessor {
public:
OOKProcessorStreamed();
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const message) override;
private:
uint32_t rem_samples = 0;
uint32_t curr_samples = 0;
bool curr_hilow = false;
uint32_t phase{0}, sphase{0};
void write_sample(const buffer_c8_t& buffer, bool bit_value, size_t i);
std::unique_ptr<StreamOutput> stream{};
bool configured{false};
void replay_config(const ReplayConfigMessage& message);
int32_t endsignals[3] = {0, 42069, 613379}; // 0 is skipped, count from 1, don't ask...
uint8_t readerrs = 0; // to count in the array
TXProgressMessage txprogress_message{};
/* NB: Threads should be the last members in the class definition. */
BasebandThread baseband_thread{OOK_SAMPLERATE, this, baseband::Direction::Transmit};
};
#endif /*__PROC_OOKSTREAMTX_HPP__*/

View File

@ -104,6 +104,7 @@ constexpr image_tag_t image_tag_fskrx{'P', 'F', 'S', 'R'};
constexpr image_tag_t image_tag_jammer{'P', 'J', 'A', 'M'};
constexpr image_tag_t image_tag_mic_tx{'P', 'M', 'T', 'X'};
constexpr image_tag_t image_tag_ook{'P', 'O', 'O', 'K'};
constexpr image_tag_t image_tag_ookstream{'P', 'O', 'S', 'K'};
constexpr image_tag_t image_tag_rds{'P', 'R', 'D', 'S'};
constexpr image_tag_t image_tag_replay{'P', 'R', 'E', 'P'};
constexpr image_tag_t image_tag_gps{'P', 'G', 'P', 'S'};

View File

@ -1,7 +1,7 @@
#include "ui_language.hpp"
// use the exact position in this array! the enum's value is the identifier. Best to add to the end
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock"};
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock", "Browse"};
// multi language support will changes (not in use for now)
const char** LanguageHelper::currentMessages = englishMessages;

View File

@ -60,7 +60,8 @@ enum LangConsts {
LANG_SHOWQR,
LANG_SAVE,
LANG_LOCK,
LANG_UNLOCK
LANG_UNLOCK,
LANG_BROWSE
};
class LanguageHelper {