Commit replay stuff before sync

This commit is contained in:
furrtek 2017-01-10 19:45:40 +00:00
parent 3ec725c172
commit 12aeae3a82
19 changed files with 1210 additions and 22 deletions

View File

@ -172,6 +172,7 @@ set(CPPSRC
ui_rds.cpp
ui_receiver.cpp
ui_record_view.cpp
ui_replay_view.cpp
ui_rssi.cpp
ui_sd_card_status_view.cpp
# ui_sd_card_debug.cpp
@ -198,6 +199,7 @@ set(CPPSRC
ert_app.cpp
${COMMON}/ert_packet.cpp
capture_app.cpp
replay_app.cpp
sd_card.cpp
time.cpp
file.cpp
@ -206,6 +208,7 @@ set(CPPSRC
log_file.cpp
${COMMON}/png_writer.cpp
capture_thread.cpp
replay_thread.cpp
${COMMON}/manchester.cpp
string_format.cpp
temperature_logger.cpp

View File

@ -3731,6 +3731,60 @@ recent_entries.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/recent_entries.cpp.s
.PHONY : recent_entries.cpp.s
replay_app.obj: replay_app.cpp.obj
.PHONY : replay_app.obj
# target to build an object file
replay_app.cpp.obj:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_app.cpp.obj
.PHONY : replay_app.cpp.obj
replay_app.i: replay_app.cpp.i
.PHONY : replay_app.i
# target to preprocess a source file
replay_app.cpp.i:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_app.cpp.i
.PHONY : replay_app.cpp.i
replay_app.s: replay_app.cpp.s
.PHONY : replay_app.s
# target to generate assembly for a file
replay_app.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_app.cpp.s
.PHONY : replay_app.cpp.s
replay_thread.obj: replay_thread.cpp.obj
.PHONY : replay_thread.obj
# target to build an object file
replay_thread.cpp.obj:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_thread.cpp.obj
.PHONY : replay_thread.cpp.obj
replay_thread.i: replay_thread.cpp.i
.PHONY : replay_thread.i
# target to preprocess a source file
replay_thread.cpp.i:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_thread.cpp.i
.PHONY : replay_thread.cpp.i
replay_thread.s: replay_thread.cpp.s
.PHONY : replay_thread.s
# target to generate assembly for a file
replay_thread.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/replay_thread.cpp.s
.PHONY : replay_thread.cpp.s
rf_path.obj: rf_path.cpp.obj
.PHONY : rf_path.obj
@ -4784,6 +4838,33 @@ ui_record_view.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_record_view.cpp.s
.PHONY : ui_record_view.cpp.s
ui_replay_view.obj: ui_replay_view.cpp.obj
.PHONY : ui_replay_view.obj
# target to build an object file
ui_replay_view.cpp.obj:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_replay_view.cpp.obj
.PHONY : ui_replay_view.cpp.obj
ui_replay_view.i: ui_replay_view.cpp.i
.PHONY : ui_replay_view.i
# target to preprocess a source file
ui_replay_view.cpp.i:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_replay_view.cpp.i
.PHONY : ui_replay_view.cpp.i
ui_replay_view.s: ui_replay_view.cpp.s
.PHONY : ui_replay_view.s
# target to generate assembly for a file
ui_replay_view.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_replay_view.cpp.s
.PHONY : ui_replay_view.cpp.s
ui_rssi.obj: ui_rssi.cpp.obj
.PHONY : ui_rssi.obj
@ -5463,6 +5544,12 @@ help:
@echo "... recent_entries.obj"
@echo "... recent_entries.i"
@echo "... recent_entries.s"
@echo "... replay_app.obj"
@echo "... replay_app.i"
@echo "... replay_app.s"
@echo "... replay_thread.obj"
@echo "... replay_thread.i"
@echo "... replay_thread.s"
@echo "... rf_path.obj"
@echo "... rf_path.i"
@echo "... rf_path.s"
@ -5580,6 +5667,9 @@ help:
@echo "... ui_record_view.obj"
@echo "... ui_record_view.i"
@echo "... ui_record_view.s"
@echo "... ui_replay_view.obj"
@echo "... ui_replay_view.i"
@echo "... ui_replay_view.s"
@echo "... ui_rssi.obj"
@echo "... ui_rssi.i"
@echo "... ui_rssi.s"

View File

@ -512,6 +512,29 @@ static constexpr Bitmap bitmap_icon_remote {
{ 16, 16 }, bitmap_icon_remote_data
};
static constexpr uint8_t bitmap_icon_replay_data[] = {
0x00, 0x00,
0xC0, 0x07,
0xF0, 0x1F,
0x79, 0x3C,
0x1D, 0x70,
0x0F, 0x60,
0x07, 0xE0,
0x1F, 0xC0,
0x00, 0xC0,
0x00, 0xE0,
0x00, 0x60,
0x00, 0x70,
0x30, 0x3C,
0xE0, 0x0F,
0x80, 0x03,
0x00, 0x00,
};
static constexpr Bitmap bitmap_icon_replay {
{ 16, 16 }, bitmap_icon_replay_data
};
static constexpr uint8_t bitmap_icon_soundboard_data[] = {
0x00, 0x00,
0xDE, 0x7B,

View File

@ -26,8 +26,8 @@
//TEST: Imperial in whipcalc
//TEST: Numbers
//TEST: Jammer
//TODO: Frequency manager auto-remove duplicates
//TODO: Frequency manager auto-remove duplicates
//TODO: "TX box" view or composite widget with frequency and bw settings, simple and advanced setup TX buttons...
//TODO: Morse coder for foxhunts
//TODO: Finish EPAR tx

View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 "replay_app.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace ui {
ReplayAppView::ReplayAppView(NavigationView& nav) {
baseband::run_image(portapack::spi_flash::image_tag_replay);
add_children({ {
&channel,
&field_frequency,
&field_frequency_step,
&field_rf_amp,
&field_lna,
&field_vga,
&replay_view,
&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_step.set_by_value(receiver_model.frequency_step());
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
receiver_model.set_frequency_step(v);
this->field_frequency.set_step(v);
};
radio::enable({
target_frequency(),
sampling_rate,
baseband_bandwidth,
rf::Direction::Transmit,
receiver_model.rf_amp(),
static_cast<int8_t>(receiver_model.lna()),
static_cast<int8_t>(receiver_model.vga()),
1,
});
replay_view.set_sampling_rate(sampling_rate / 8);
replay_view.on_error = [&nav](std::string message) {
nav.display_modal("Error", message);
};
}
ReplayAppView::~ReplayAppView() {
radio::disable();
baseband::shutdown();
}
void ReplayAppView::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 ReplayAppView::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(), static_cast<ui::Dim>(new_parent_rect.height() - header_height) };
waterfall.set_parent_rect(waterfall_rect);
}
void ReplayAppView::focus() {
field_frequency.focus();
}
void ReplayAppView::on_target_frequency_changed(rf::Frequency f) {
set_target_frequency(f);
}
void ReplayAppView::set_target_frequency(const rf::Frequency new_value) {
persistent_memory::set_tuned_frequency(new_value);;
}
rf::Frequency ReplayAppView::target_frequency() const {
return persistent_memory::tuned_frequency();
}
} /* namespace ui */

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 __REPLAY_APP_HPP__
#define __REPLAY_APP_HPP__
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_replay_view.hpp"
#include "ui_spectrum.hpp"
#include <string>
#include <memory>
namespace ui {
class ReplayAppView : public View {
public:
ReplayAppView(NavigationView& nav);
~ReplayAppView();
void on_hide() override;
void set_parent_rect(const Rect new_parent_rect) override;
void focus() override;
std::string title() const override { return "Capture"; };
private:
static constexpr ui::Dim header_height = 2 * 16;
static constexpr uint32_t sampling_rate = 4000000;
static constexpr uint32_t baseband_bandwidth = 2500000;
void on_target_frequency_changed(rf::Frequency f);
rf::Frequency target_frequency() const;
void set_target_frequency(const rf::Frequency new_value);
Channel channel {
{ 24 * 8, 5, 6 * 8, 4 },
};
FrequencyField field_frequency {
{ 0 * 8, 0 * 16 },
};
FrequencyStepView field_frequency_step {
{ 10 * 8, 0 * 16 },
};
RFAmpField field_rf_amp {
{ 16 * 8, 0 * 16 }
};
LNAGainField field_lna {
{ 18 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 21 * 8, 0 * 16 }
};
ReplayView replay_view {
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
"BBD_????", ReplayView::FileType::RawS16, 16384, 3
};
spectrum::WaterfallWidget waterfall;
};
} /* namespace ui */
#endif/*__REPLAY_APP_HPP__*/

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 "replay_thread.hpp"
#include "baseband_api.hpp"
// StreamOutput ///////////////////////////////////////////////////////////
class StreamOutput {
public:
StreamOutput(CaptureConfig* const config);
~StreamOutput();
size_t available() {
return fifo_buffers_full->len();
}
StreamBuffer* get_buffer() {
StreamBuffer* p { nullptr };
fifo_buffers_full->out(p);
return p;
}
bool release_buffer(StreamBuffer* const p) {
p->empty();
return fifo_buffers_empty->in(p);
}
static FIFO<StreamBuffer*>* fifo_buffers_empty;
static FIFO<StreamBuffer*>* fifo_buffers_full;
private:
CaptureConfig* const config;
};
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_empty = nullptr;
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_full = nullptr;
StreamOutput::StreamOutput(
CaptureConfig* const config
) : config { config }
{
baseband::capture_start(config);
fifo_buffers_empty = config->fifo_buffers_empty;
fifo_buffers_full = config->fifo_buffers_full;
}
StreamOutput::~StreamOutput() {
fifo_buffers_full = nullptr;
fifo_buffers_empty = nullptr;
baseband::capture_stop();
}
// CaptureThread //////////////////////////////////////////////////////////
Thread* ReplayThread::thread = nullptr;
ReplayThread::ReplayThread(
std::unique_ptr<Reader> reader,
size_t read_size,
size_t buffer_count,
std::function<void()> success_callback,
std::function<void(File::Error)> error_callback
) : config { read_size, buffer_count },
reader { std::move(reader) },
success_callback { std::move(success_callback) },
error_callback { std::move(error_callback) }
{
// Need significant stack for FATFS
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ReplayThread::static_fn, this);
}
ReplayThread::~ReplayThread() {
if( thread ) {
chThdTerminate(thread);
chEvtSignal(thread, event_mask_loop_wake);
chThdWait(thread);
thread = nullptr;
}
}
void ReplayThread::check_fifo_isr() {
// TODO: Prevent over-signalling by transmitting a set of
// flags from the baseband core.
const auto fifo = StreamOutput::fifo_buffers_full;
if( fifo ) {
if( !fifo->is_empty() ) {
chEvtSignalI(thread, event_mask_loop_wake);
}
}
}
msg_t ReplayThread::static_fn(void* arg) {
auto obj = static_cast<ReplayThread*>(arg);
const auto error = obj->run();
if( error.is_valid() && obj->error_callback ) {
obj->error_callback(error.value());
} else {
if( obj->success_callback ) {
obj->success_callback();
}
}
return 0;
}
Optional<File::Error> ReplayThread::run() {
StreamOutput stream { &config };
while( !chThdShouldTerminate() ) {
if( stream.available() ) {
auto buffer = stream.get_buffer();
auto read_result = reader->reader(buffer->data(), buffer->size());
if( read_result.is_error() ) {
return read_result.error();
}
stream.release_buffer(buffer);
} else {
chEvtWaitAny(event_mask_loop_wake);
}
}
return { };
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 __REPLAY_THREAD_H__
#define __REPLAY_THREAD_H__
#include "ch.h"
#include "event_m0.hpp"
#include "file.hpp"
#include "optional.hpp"
#include <cstdint>
#include <cstddef>
#include <utility>
class Reader {
public:
virtual File::Result<size_t> read(const void* const buffer, const size_t bytes) = 0;
virtual ~Reader() = default;
};
class ReplayThread {
public:
ReplayThread(
std::unique_ptr<Reader> reader,
size_t read_size,
size_t buffer_count,
std::function<void()> success_callback,
std::function<void(File::Error)> error_callback
);
~ReplayThread();
const ReplayConfig& state() const {
return config;
}
static void check_fifo_isr();
private:
static constexpr auto event_mask_loop_wake = EVENT_MASK(0);
ReplayConfig config;
std::unique_ptr<Reader> reader;
std::function<void()> success_callback;
std::function<void(File::Error)> error_callback;
static Thread* thread;
static msg_t static_fn(void* arg);
Optional<File::Error> run();
};
#endif/*__REPLAY_THREAD_H__*/

View File

@ -55,6 +55,7 @@
#include "tpms_app.hpp"
#include "pocsag_app.hpp"
#include "capture_app.hpp"
#include "replay_app.hpp"
#include "core_control.hpp"
@ -338,16 +339,16 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
}
SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<11>({ {
add_items<12>({ {
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receiver, [&nav](){ nav.push<ReceiverMenuView>(); } },
{ "Capture", ui::Color::cyan(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::blue(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
{ "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push<CloseCallView>(); } },
{ "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
{ "Utilities", ui::Color::purple(),nullptr, [&nav](){ nav.push<UtilitiesView>(); } },
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Setup", ui::Color::white(), nullptr, [&nav](){ nav.push<SetupMenuView>(); } },
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },

View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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_replay_view.hpp"
#include "portapack.hpp"
#include "message.hpp"
#include "portapack_shared_memory.hpp"
using namespace portapack;
#include "time.hpp"
#include "string_format.hpp"
#include "utility.hpp"
#include <cstdint>
namespace ui {
ReplayView::ReplayView(
const Rect parent_rect,
std::string filename_stem_pattern,
const FileType file_type,
const size_t read_size,
const size_t buffer_count
) : View { parent_rect },
filename_stem_pattern { filename_stem_pattern },
file_type { file_type },
read_size { read_size },
buffer_count { buffer_count }
{
add_children({ {
&rect_background,
&button_record,
&text_replay_filename,
&text_time_seek,
} });
rect_background.set_parent_rect({ { 0, 0 }, size() });
button_record.on_select = [this](ImageButton&) {
this->toggle();
};
signal_token_tick_second = time::signal_tick_second += [this]() {
this->on_tick_second();
};
}
ReplayView::~ReplayView() {
time::signal_tick_second -= signal_token_tick_second;
}
void ReplayView::focus() {
button_record.focus();
}
void ReplayView::set_sampling_rate(const size_t new_sampling_rate) {
if( new_sampling_rate != sampling_rate ) {
stop();
sampling_rate = new_sampling_rate;
button_record.hidden(sampling_rate == 0);
text_replay_filename.hidden(sampling_rate == 0);
text_time_seek.hidden(sampling_rate == 0);
rect_background.hidden(sampling_rate != 0);
update_status_display();
}
}
bool ReplayView::is_active() const {
return (bool)replay_thread;
}
void ReplayView::toggle() {
if( is_active() ) {
stop();
} else {
start();
}
}
void ReplayView::start() {
stop();
text_replay_filename.set("");
if( sampling_rate == 0 ) {
return;
}
const auto filename_stem = next_filename_stem_matching_pattern(filename_stem_pattern);
if( filename_stem.empty() ) {
return;
}
std::unique_ptr<Reader> reader;
auto p = std::make_unique<FileReader>();
auto create_error = p->create(
filename_stem + ".C16"
);
if( create_error.is_valid() ) {
handle_error(create_error.value());
} else {
reader = std::move(p);
}
if( reader ) {
text_replay_filename.set(filename_stem);
button_record.set_bitmap(&bitmap_stop);
replay_thread = std::make_unique<ReplayThread>(
std::move(reader),
read_size, buffer_count,
[]() {
ReplayThreadDoneMessage message { };
EventDispatcher::send_message(message);
},
[](File::Error error) {
ReplayThreadDoneMessage message { error.code() };
EventDispatcher::send_message(message);
}
);
}
update_status_display();
}
void ReplayView::stop() {
if( is_active() ) {
replay_thread.reset();
button_record.set_bitmap(&bitmap_record);
}
update_status_display();
}
void ReplayView::on_tick_second() {
update_status_display();
}
void ReplayView::update_status_display() {
/*if( sampling_rate ) {
const auto space_info = std::filesystem::space("");
const uint32_t bytes_per_second = file_type == FileType::WAV ? (sampling_rate * 2) : (sampling_rate * 4);
const uint32_t available_seconds = space_info.free / bytes_per_second;
const uint32_t seconds = available_seconds % 60;
const uint32_t available_minutes = available_seconds / 60;
const uint32_t minutes = available_minutes % 60;
const uint32_t hours = available_minutes / 60;
const std::string available_time =
to_string_dec_uint(hours, 3, ' ') + ":" +
to_string_dec_uint(minutes, 2, '0') + ":" +
to_string_dec_uint(seconds, 2, '0');
text_time_available.set(available_time);
}*/
}
void ReplayView::handle_replay_thread_done(const File::Error error) {
stop();
if( error.code() ) {
handle_error(error);
}
}
void ReplayView::handle_error(const File::Error error) {
if( on_error ) {
on_error(error.what());
}
}
} /* namespace ui */

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 __UI_REPLAY_VIEW_H__
#define __UI_REPLAY_VIEW_H__
#include "ui_widget.hpp"
#include "replay_thread.hpp"
#include "signal.hpp"
#include "bitmap.hpp"
#include <cstddef>
#include <string>
#include <memory>
namespace ui {
class ReplayView : public View {
public:
std::function<void(std::string)> on_error;
enum FileType {
RawS16 = 2,
WAV = 3,
};
ReplayView(
const Rect parent_rect,
std::string filename_stem_pattern,
FileType file_type,
const size_t read_size,
const size_t buffer_count
);
~ReplayView();
void focus() override;
void set_sampling_rate(const size_t new_sampling_rate);
void start();
void stop();
bool is_active() const;
private:
void toggle();
void on_tick_second();
void update_status_display();
void handle_replay_thread_done(const File::Error error);
void handle_error(const File::Error error);
bool pwmrssi_enabled = false;
const std::string filename_stem_pattern;
const FileType file_type;
const size_t read_size;
const size_t buffer_count;
size_t sampling_rate { 0 };
SignalToken signal_token_tick_second;
Rectangle rect_background {
Color::black()
};
ImageButton button_record {
{ 4 * 8, 0 * 16, 2 * 8, 1 * 16 },
&bitmap_record,
Color::red(),
Color::black()
};
Text text_replay_filename {
{ 7 * 8, 0 * 16, 8 * 8, 16 },
"",
};
Text text_time_seek {
{ 21 * 8, 0 * 16, 9 * 8, 16 },
"",
};
std::unique_ptr<ReplayThread> replay_thread;
MessageHandlerRegistration message_handler_capture_thread_error {
Message::ID::CaptureThreadDone,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
this->handle_replay_thread_done(message.error);
}
};
};
} /* namespace ui */
#endif/*__UI_REPLAY_VIEW_H__*/

View File

@ -114,6 +114,7 @@ set(CPPSRC
matched_filter.cpp
spectrum_collector.cpp
stream_input.cpp
stream_output.cpp
dsp_squelch.cpp
clock_recovery.cpp
packet_builder.cpp
@ -368,12 +369,12 @@ set(MODE_CPPSRC
)
DeclareTargets(PAFS afsk)
### Epar
### Replay
#set(MODE_CPPSRC
# proc_epar.cpp
#)
#DeclareTargets(PEPR epar)
set(MODE_CPPSRC
proc_replay.cpp
)
DeclareTargets(PREP replay)
### Tones

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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_replay.hpp"
//#include "dsp_fir_taps.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
ReplayProcessor::ReplayProcessor() {
}
void ReplayProcessor::execute(const buffer_c8_t& buffer) {
/* 2.4576MHz, 2048 samples */
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
const auto& decimator_out = decim_1_out;
const auto& channel = decimator_out;
if( stream ) {
const size_t bytes_to_write = sizeof(*decimator_out.p) * decimator_out.count;
const auto result = stream->write(decimator_out.p, bytes_to_write);
}
feed_channel_stats(channel);
/*spectrum_samples += channel.count;
if( spectrum_samples >= spectrum_interval_samples ) {
spectrum_samples -= spectrum_interval_samples;
channel_spectrum.feed(channel, channel_filter_pass_f, channel_filter_stop_f);
}*/
}
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::ReplayConfig:
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
break;
default:
break;
}
}
void ReplayProcessor::replay_config(const ReplayConfigMessage& message) {
if( message.config ) {
stream = std::make_unique<StreamOutput>(message.config);
} else {
stream.reset();
}
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<ReplayProcessor>() };
event_dispatcher.run();
return 0;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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_REPLAY_HPP__
#define __PROC_REPLAY_HPP__
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
//#include "rssi_thread.hpp"
//#include "dsp_decimate.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:
// TODO: Repeated value needs to be transmitted from application side.
static constexpr size_t baseband_fs = 4000000;
//static constexpr auto spectrum_rate_hz = 50.0f;
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
//RSSIThread rssi_thread { NORMALPRIO + 10 };
std::array<complex16_t, 512> dst;
const buffer_c16_t dst_buffer {
dst.data(),
dst.size()
};
std::unique_ptr<StreamOutput> stream;
/*SpectrumCollector channel_spectrum;
size_t spectrum_interval_samples = 0;
size_t spectrum_samples = 0;*/
void replay_config(const ReplayConfigMessage& message);
};
#endif/*__PROC_REPLAY_HPP__*/

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 "stream_output.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
StreamOutput::StreamOutput(ReplayConfig* const config) :
fifo_buffers_empty { buffers_empty.data(), buffer_count_max_log2 },
fifo_buffers_full { buffers_full.data(), buffer_count_max_log2 },
config { config },
data { std::make_unique<uint8_t[]>(config->read_size * config->buffer_count) }
{
config->fifo_buffers_empty = &fifo_buffers_empty;
config->fifo_buffers_full = &fifo_buffers_full;
for(size_t i=0; i<config->buffer_count; i++) {
buffers[i] = { &(data.get()[i * config->read_size]), config->read_size };
fifo_buffers_empty.in(&buffers[i]);
}
}
size_t StreamOutput::write(const void* const data, const size_t length) {
const uint8_t* p = static_cast<const uint8_t*>(data);
size_t written = 0;
while( written < length ) {
if( !active_buffer ) {
// We need an empty buffer...
if( !fifo_buffers_empty.out(active_buffer) ) {
// ...but none are available. Samples were dropped.
break;
}
}
const auto remaining = length - written;
written += active_buffer->write(&p[written], remaining);
if( active_buffer->is_full() ) {
if( !fifo_buffers_full.in(active_buffer) ) {
// FIFO is fuil of buffers, there's no place for this one.
// Bail out of the loop, and try submitting the buffer in the
// next pass.
// This should never happen if the number of buffers is less
// than the capacity of the FIFO.
break;
}
active_buffer = nullptr;
creg::m4txevent::assert();
}
}
config->baseband_bytes_sent += length;
return written;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* 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 __STREAM_OUTPUT_H__
#define __STREAM_OUTPUT_H__
#include "message.hpp"
#include "fifo.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
#include <memory>
class StreamOutput {
public:
StreamOutput(ReplayConfig* const config);
size_t write(const void* const data, const size_t length);
private:
static constexpr size_t buffer_count_max_log2 = 3;
static constexpr size_t buffer_count_max = 1U << buffer_count_max_log2;
FIFO<StreamBuffer*> fifo_buffers_empty;
FIFO<StreamBuffer*> fifo_buffers_full;
std::array<StreamBuffer, buffer_count_max> buffers;
std::array<StreamBuffer*, buffer_count_max> buffers_empty;
std::array<StreamBuffer*, buffer_count_max> buffers_full;
StreamBuffer* active_buffer { nullptr };
ReplayConfig* const config { nullptr };
std::unique_ptr<uint8_t[]> data;
};
#endif/*__STREAM_OUTPUT_H__*/

View File

@ -66,23 +66,25 @@ public:
DisplaySleep = 16,
CaptureConfig = 17,
CaptureThreadDone = 18,
ReplayConfig = 19,
ReplayThreadDone = 20,
TXDone = 20,
Retune = 21,
TonesConfigure = 22,
AFSKConfigure = 23,
PWMRSSIConfigure = 24,
OOKConfigure = 25,
RDSConfigure = 26,
AudioTXConfig = 27,
POCSAGConfigure = 28,
DTMFTXConfig = 29,
ADSBConfigure = 30,
TXDone = 30,
Retune = 31,
TonesConfigure = 32,
AFSKConfigure = 33,
PWMRSSIConfigure = 34,
OOKConfigure = 35,
RDSConfigure = 36,
AudioTXConfig = 37,
POCSAGConfigure = 38,
DTMFTXConfig = 39,
ADSBConfigure = 40,
POCSAGPacket = 31,
POCSAGPacket = 41,
FIFOSignal = 32,
FIFOData = 33,
FIFOSignal = 52,
FIFOData = 53,
MAX
};
@ -492,6 +494,37 @@ public:
CaptureConfig* const config;
};
struct ReplayConfig {
const size_t read_size;
const size_t buffer_count;
uint64_t baseband_bytes_sent;
FIFO<StreamBuffer*>* fifo_buffers_empty;
FIFO<StreamBuffer*>* fifo_buffers_full;
constexpr ReplayConfig(
const size_t read_size,
const size_t buffer_count
) : read_size { read_size },
buffer_count { buffer_count },
baseband_bytes_sent { 0 },
fifo_buffers_empty { nullptr },
fifo_buffers_full { nullptr }
{
}
};
class ReplayConfigMessage : public Message {
public:
constexpr ReplayConfigMessage(
ReplayConfig* const config
) : Message { ID::ReplayConfig },
config { config }
{
}
ReplayConfig* const config;
};
class TXDoneMessage : public Message {
public:
constexpr TXDoneMessage(
@ -715,4 +748,16 @@ public:
uint32_t error;
};
class ReplayThreadDoneMessage : public Message {
public:
constexpr ReplayThreadDoneMessage(
uint32_t error = 0
) : Message { ID::ReplayThreadDone },
error { error }
{
}
uint32_t error;
};
#endif/*__MESSAGE_H__*/

View File

@ -82,6 +82,7 @@ constexpr image_tag_t image_tag_tones { 'P', 'T', 'O', 'N' };
constexpr image_tag_t image_tag_rds { 'P', 'R', 'D', 'S' };
constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' };
constexpr image_tag_t image_tag_adsb_tx { 'P', 'A', 'D', 'S' };
constexpr image_tag_t image_tag_replay { 'P', 'R', 'E', 'P' };
constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' };

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B