mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-12 15:59:49 -05:00
commit
2b65f469ed
@ -260,6 +260,7 @@ set(CPPSRC
|
||||
apps/lge_app.cpp
|
||||
apps/pocsag_app.cpp
|
||||
apps/replay_app.cpp
|
||||
apps/gps_sim_app.cpp
|
||||
apps/soundboard_app.cpp
|
||||
apps/tpms_app.cpp
|
||||
protocols/aprs.cpp
|
||||
|
260
firmware/application/apps/gps_sim_app.cpp
Normal file
260
firmware/application/apps/gps_sim_app.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 "gps_sim_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void GpsSimAppView::set_ready() {
|
||||
ready_signal = true;
|
||||
}
|
||||
|
||||
void GpsSimAppView::on_file_changed(std::filesystem::path new_file_path) {
|
||||
File data_file, info_file;
|
||||
char file_data[257];
|
||||
|
||||
// Get file size
|
||||
auto data_open_error = data_file.open("/" + new_file_path.string());
|
||||
if (data_open_error.is_valid()) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
|
||||
file_path = new_file_path;
|
||||
|
||||
// Get original record frequency if available
|
||||
std::filesystem::path info_file_path = file_path;
|
||||
info_file_path.replace_extension(u".TXT");
|
||||
|
||||
sample_rate = 500000;
|
||||
|
||||
auto info_open_error = info_file.open("/" + info_file_path.string());
|
||||
if (!info_open_error.is_valid()) {
|
||||
memset(file_data, 0, 257);
|
||||
auto read_size = info_file.read(file_data, 256);
|
||||
if (!read_size.is_error()) {
|
||||
auto pos1 = strstr(file_data, "center_frequency=");
|
||||
if (pos1) {
|
||||
pos1 += 17;
|
||||
field_frequency.set_value(strtoll(pos1, nullptr, 10));
|
||||
}
|
||||
|
||||
auto pos2 = strstr(file_data, "sample_rate=");
|
||||
if (pos2) {
|
||||
pos2 += 12;
|
||||
sample_rate = strtoll(pos2, nullptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 1) + "Hz");
|
||||
|
||||
auto file_size = data_file.size();
|
||||
auto duration = (file_size * 1000) / (1 * 2 * sample_rate);
|
||||
|
||||
progressbar.set_max(file_size);
|
||||
text_filename.set(file_path.filename().string().substr(0, 12));
|
||||
text_duration.set(to_string_time_ms(duration));
|
||||
|
||||
button_play.focus();
|
||||
}
|
||||
|
||||
void GpsSimAppView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void GpsSimAppView::focus() {
|
||||
button_open.focus();
|
||||
}
|
||||
|
||||
void GpsSimAppView::file_error() {
|
||||
nav_.display_modal("Error", "File read error.");
|
||||
}
|
||||
|
||||
bool GpsSimAppView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
|
||||
void GpsSimAppView::toggle() {
|
||||
if( is_active() ) {
|
||||
stop(false);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void GpsSimAppView::start() {
|
||||
stop(false);
|
||||
|
||||
std::unique_ptr<stream::Reader> reader;
|
||||
|
||||
auto p = std::make_unique<FileReader>();
|
||||
auto open_error = p->open(file_path);
|
||||
if( open_error.is_valid() ) {
|
||||
file_error();
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
|
||||
if( reader ) {
|
||||
button_play.set_bitmap(&bitmap_stop);
|
||||
baseband::set_sample_rate(sample_rate );
|
||||
|
||||
replay_thread = std::make_unique<ReplayThread>(
|
||||
std::move(reader),
|
||||
read_size, buffer_count,
|
||||
&ready_signal,
|
||||
[](uint32_t return_code) {
|
||||
ReplayThreadDoneMessage message { return_code };
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
sample_rate ,
|
||||
baseband_bandwidth,
|
||||
rf::Direction::Transmit,
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
}
|
||||
|
||||
void GpsSimAppView::stop(const bool do_loop) {
|
||||
if( is_active() )
|
||||
replay_thread.reset();
|
||||
|
||||
if (do_loop && check_loop.value()) {
|
||||
start();
|
||||
} else {
|
||||
radio::disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void GpsSimAppView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
stop(true);
|
||||
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||
stop(false);
|
||||
file_error();
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
GpsSimAppView::GpsSimAppView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
baseband::run_image(portapack::spi_flash::image_tag_gps);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&button_open,
|
||||
&text_filename,
|
||||
&text_sample_rate,
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_rf_amp,
|
||||
&check_loop,
|
||||
&button_play,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
field_frequency.set_value(target_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_target_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_target_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
field_frequency.set_step(5000);
|
||||
|
||||
button_play.on_select = [this](ImageButton&) {
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
button_open.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".C8");
|
||||
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||
on_file_changed(new_file_path);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
GpsSimAppView::~GpsSimAppView() {
|
||||
radio::disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void GpsSimAppView::on_hide() {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void GpsSimAppView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
void GpsSimAppView::on_target_frequency_changed(rf::Frequency f) {
|
||||
set_target_frequency(f);
|
||||
}
|
||||
|
||||
void GpsSimAppView::set_target_frequency(const rf::Frequency new_value) {
|
||||
persistent_memory::set_tuned_frequency(new_value);;
|
||||
}
|
||||
|
||||
rf::Frequency GpsSimAppView::target_frequency() const {
|
||||
return persistent_memory::tuned_frequency();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
157
firmware/application/apps/gps_sim_app.hpp
Normal file
157
firmware/application/apps/gps_sim_app.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 __GPS_SIM_APP_HPP__
|
||||
#define __GPS_SIM_APP_HPP__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "replay_thread.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class GpsSimAppView : public View {
|
||||
public:
|
||||
GpsSimAppView(NavigationView& nav);
|
||||
~GpsSimAppView();
|
||||
|
||||
void on_hide() override;
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "GPS Simulator"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
uint32_t sample_rate = 0;
|
||||
static constexpr uint32_t baseband_bandwidth = 3000000; //filter bandwidth
|
||||
const size_t read_size { 16384 };
|
||||
const size_t buffer_count { 3 };
|
||||
|
||||
void on_file_changed(std::filesystem::path new_file_path);
|
||||
void on_target_frequency_changed(rf::Frequency f);
|
||||
void on_tx_progress(const uint32_t progress);
|
||||
|
||||
void set_target_frequency(const rf::Frequency new_value);
|
||||
rf::Frequency target_frequency() const;
|
||||
|
||||
void toggle();
|
||||
void start();
|
||||
void stop(const bool do_loop);
|
||||
bool is_active() const;
|
||||
void set_ready();
|
||||
void handle_replay_thread_done(const uint32_t return_code);
|
||||
void file_error();
|
||||
|
||||
std::filesystem::path file_path { };
|
||||
std::unique_ptr<ReplayThread> replay_thread { };
|
||||
bool ready_signal { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Button button_open {
|
||||
{ 0 * 8, 0 * 16, 10 * 8, 2 * 16 },
|
||||
"Open file"
|
||||
};
|
||||
|
||||
Text text_filename {
|
||||
{ 11 * 8, 0 * 16, 12 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_sample_rate {
|
||||
{ 24 * 8, 0 * 16, 6 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_duration {
|
||||
{ 11 * 8, 1 * 16, 6 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
ProgressBar progressbar {
|
||||
{ 18 * 8, 1 * 16, 12 * 8, 16 }
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 2 * 16 },
|
||||
};
|
||||
LNAGainField field_lna {
|
||||
{ 14 * 8, 2 * 16 }
|
||||
};
|
||||
RFAmpField field_rf_amp {
|
||||
{ 19 * 8, 2 * 16 }
|
||||
};
|
||||
Checkbox check_loop {
|
||||
{ 21 * 8, 2 * 16 },
|
||||
4,
|
||||
"Loop",
|
||||
true
|
||||
};
|
||||
ImageButton button_play {
|
||||
{ 28 * 8, 2 * 16, 2 * 8, 1 * 16 },
|
||||
&bitmap_play,
|
||||
Color::green(),
|
||||
Color::black()
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall { };
|
||||
|
||||
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||
Message::ID::ReplayThreadDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||
this->handle_replay_thread_done(message.return_code);
|
||||
}
|
||||
};
|
||||
|
||||
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_tx_progress {
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__GPS_SIM_APP_HPP__*/
|
@ -1503,6 +1503,28 @@ static constexpr Bitmap bitmap_icon_replay {
|
||||
{ 16, 16 }, bitmap_icon_replay_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_gps_sim_data[] = {
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0xF0, 0x0F,
|
||||
0x4C, 0x32,
|
||||
0xFE, 0x7F,
|
||||
0x25, 0xA4,
|
||||
0x25, 0xA4,
|
||||
0xFF, 0xFF,
|
||||
0x25, 0xA4,
|
||||
0x25, 0xA4,
|
||||
0xFE, 0x7F,
|
||||
0x4C, 0x32,
|
||||
0xF0, 0x0F,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
static constexpr Bitmap bitmap_gps_sim {
|
||||
{ 16, 16 }, bitmap_gps_sim_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_icon_btle_data[] = {
|
||||
0x00, 0x00,
|
||||
0x80, 0x00,
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "lge_app.hpp"
|
||||
#include "pocsag_app.hpp"
|
||||
#include "replay_app.hpp"
|
||||
#include "gps_sim_app.hpp"
|
||||
#include "soundboard_app.hpp"
|
||||
#include "tpms_app.hpp"
|
||||
|
||||
@ -377,6 +378,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
{ "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
|
||||
{ "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
|
||||
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
|
||||
{ "GPS Sim", ui::Color::yellow(), &bitmap_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
|
||||
{ "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
||||
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
|
||||
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
|
||||
|
@ -437,6 +437,13 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PREP replay)
|
||||
|
||||
### GPS Simulator
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_gps_sim.cpp
|
||||
)
|
||||
DeclareTargets(PGPS gps_sim)
|
||||
|
||||
### Signal generator
|
||||
|
||||
set(MODE_CPPSRC
|
||||
|
143
firmware/baseband/proc_gps_sim.cpp
Normal file
143
firmware/baseband/proc_gps_sim.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_gps_sim.hpp"
|
||||
#include "sine_table_int8.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
ReplayProcessor::ReplayProcessor() {
|
||||
channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * 1000000; // 162760.416666667
|
||||
channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * 1000000; // 337239.583333333
|
||||
|
||||
spectrum_samples = 0;
|
||||
|
||||
channel_spectrum.set_decimation_factor(1);
|
||||
|
||||
configured = false;
|
||||
}
|
||||
|
||||
void ReplayProcessor::execute(const buffer_c8_t& buffer) {
|
||||
/* 4MHz, 2048 samples */
|
||||
|
||||
if (!configured) return;
|
||||
|
||||
// File data is in C16 format, we need C8
|
||||
// File samplerate is 500kHz, we're at 4MHz
|
||||
// iq_buffer can only be 512 C16 samples (RAM limitation)
|
||||
// To fill up the 2048-sample C8 buffer, we need:
|
||||
// 2048 samples * 2 bytes per sample = 4096 bytes
|
||||
// Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file and duplicate them 8 times each
|
||||
// So 256 * 4 bytes per sample (C16) = 1024 bytes from the file
|
||||
if( stream ) { //sizeof(*buffer.p) = sizeof(C8) = 2*int8 = 2 bytes //buffer.count = 2048
|
||||
const size_t bytes_to_read = sizeof(*buffer.p) * 1 * (buffer.count ); // *2 (C16), /8 (oversampling) should be == 1024
|
||||
bytes_read += stream->read(iq_buffer.p, bytes_to_read);
|
||||
}
|
||||
|
||||
// Fill and "stretch"
|
||||
for (size_t i = 0; i < buffer.count; i++) {
|
||||
/*if (i & 3) {
|
||||
buffer.p[i] = buffer.p[i - 1];
|
||||
} else {
|
||||
auto re_out = iq_buffer.p[i >> 3].real() ;
|
||||
auto im_out = iq_buffer.p[i >> 3].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}*/
|
||||
/*
|
||||
if (i % 8 != 0) {
|
||||
buffer.p[i] = buffer.p[i - 1];
|
||||
} else {
|
||||
auto re_out = iq_buffer.p[i/8].real() ;
|
||||
auto im_out = iq_buffer.p[i/8].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}*/
|
||||
|
||||
auto re_out = iq_buffer.p[i].real() ;
|
||||
auto im_out = iq_buffer.p[i].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}
|
||||
|
||||
spectrum_samples += buffer.count;
|
||||
if( spectrum_samples >= spectrum_interval_samples ) {
|
||||
spectrum_samples -= spectrum_interval_samples;
|
||||
//channel_spectrum.feed(iq_buffer, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
txprogress_message.progress = bytes_read; // Inform UI about progress
|
||||
txprogress_message.done = false;
|
||||
shared_memory.application_queue.push(txprogress_message);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayProcessor::on_message(const Message* const message) {
|
||||
switch(message->id) {
|
||||
case Message::ID::UpdateSpectrum:
|
||||
case Message::ID::SpectrumStreamingConfig:
|
||||
channel_spectrum.on_message(message);
|
||||
break;
|
||||
|
||||
case Message::ID::SamplerateConfig:
|
||||
samplerate_config(*reinterpret_cast<const SamplerateConfigMessage*>(message));
|
||||
break;
|
||||
|
||||
case Message::ID::ReplayConfig:
|
||||
configured = false;
|
||||
bytes_read = 0;
|
||||
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
|
||||
break;
|
||||
|
||||
// App has prefilled the buffers, we're ready to go now
|
||||
case Message::ID::FIFOData:
|
||||
configured = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayProcessor::samplerate_config(const SamplerateConfigMessage& message) {
|
||||
baseband_fs = message.sample_rate;
|
||||
baseband_thread.set_sampling_rate(baseband_fs);
|
||||
spectrum_interval_samples = baseband_fs / spectrum_rate_hz;
|
||||
}
|
||||
|
||||
void ReplayProcessor::replay_config(const ReplayConfigMessage& message) {
|
||||
if( message.config ) {
|
||||
|
||||
stream = std::make_unique<StreamOutput>(message.config);
|
||||
|
||||
// Tell application that the buffers and FIFO pointers are ready, prefill
|
||||
shared_memory.application_queue.push(sig_message);
|
||||
} else {
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher { std::make_unique<ReplayProcessor>() };
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
77
firmware/baseband/proc_gps_sim.hpp
Normal file
77
firmware/baseband/proc_gps_sim.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 __PROC_GPS_SIM_HPP__
|
||||
#define __PROC_GPS_SIM_HPP__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
|
||||
#include "spectrum_collector.hpp"
|
||||
|
||||
#include "stream_output.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
class ReplayProcessor : public BasebandProcessor {
|
||||
public:
|
||||
ReplayProcessor();
|
||||
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
size_t baseband_fs = 0;
|
||||
static constexpr auto spectrum_rate_hz = 50.0f;
|
||||
|
||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
|
||||
|
||||
std::array<complex8_t, 2048> iq { };
|
||||
const buffer_c8_t iq_buffer {
|
||||
iq.data(),
|
||||
iq.size(),
|
||||
baseband_fs
|
||||
};
|
||||
|
||||
uint32_t channel_filter_pass_f = 0;
|
||||
uint32_t channel_filter_stop_f = 0;
|
||||
|
||||
std::unique_ptr<StreamOutput> stream { };
|
||||
|
||||
SpectrumCollector channel_spectrum { };
|
||||
size_t spectrum_interval_samples = 0;
|
||||
size_t spectrum_samples = 0;
|
||||
|
||||
bool configured { false };
|
||||
uint32_t bytes_read { 0 };
|
||||
|
||||
void samplerate_config(const SamplerateConfigMessage& message);
|
||||
void replay_config(const ReplayConfigMessage& message);
|
||||
|
||||
TXProgressMessage txprogress_message { };
|
||||
RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest };
|
||||
};
|
||||
|
||||
#endif/*__PROC_GPS_SIM_HPP__*/
|
@ -92,6 +92,7 @@ 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_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' };
|
||||
constexpr image_tag_t image_tag_siggen { 'P', 'S', 'I', 'G' };
|
||||
constexpr image_tag_t image_tag_sstv_tx { 'P', 'S', 'T', 'X' };
|
||||
constexpr image_tag_t image_tag_tones { 'P', 'T', 'O', 'N' };
|
||||
|
Loading…
Reference in New Issue
Block a user