mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-04-16 09:51:27 +00:00
Commit replay stuff before sync
This commit is contained in:
parent
3ec725c172
commit
12aeae3a82
@ -172,6 +172,7 @@ set(CPPSRC
|
|||||||
ui_rds.cpp
|
ui_rds.cpp
|
||||||
ui_receiver.cpp
|
ui_receiver.cpp
|
||||||
ui_record_view.cpp
|
ui_record_view.cpp
|
||||||
|
ui_replay_view.cpp
|
||||||
ui_rssi.cpp
|
ui_rssi.cpp
|
||||||
ui_sd_card_status_view.cpp
|
ui_sd_card_status_view.cpp
|
||||||
# ui_sd_card_debug.cpp
|
# ui_sd_card_debug.cpp
|
||||||
@ -198,6 +199,7 @@ set(CPPSRC
|
|||||||
ert_app.cpp
|
ert_app.cpp
|
||||||
${COMMON}/ert_packet.cpp
|
${COMMON}/ert_packet.cpp
|
||||||
capture_app.cpp
|
capture_app.cpp
|
||||||
|
replay_app.cpp
|
||||||
sd_card.cpp
|
sd_card.cpp
|
||||||
time.cpp
|
time.cpp
|
||||||
file.cpp
|
file.cpp
|
||||||
@ -206,6 +208,7 @@ set(CPPSRC
|
|||||||
log_file.cpp
|
log_file.cpp
|
||||||
${COMMON}/png_writer.cpp
|
${COMMON}/png_writer.cpp
|
||||||
capture_thread.cpp
|
capture_thread.cpp
|
||||||
|
replay_thread.cpp
|
||||||
${COMMON}/manchester.cpp
|
${COMMON}/manchester.cpp
|
||||||
string_format.cpp
|
string_format.cpp
|
||||||
temperature_logger.cpp
|
temperature_logger.cpp
|
||||||
|
@ -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
|
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
|
.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
|
rf_path.obj: rf_path.cpp.obj
|
||||||
|
|
||||||
.PHONY : rf_path.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
|
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
|
.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
|
ui_rssi.obj: ui_rssi.cpp.obj
|
||||||
|
|
||||||
.PHONY : ui_rssi.obj
|
.PHONY : ui_rssi.obj
|
||||||
@ -5463,6 +5544,12 @@ help:
|
|||||||
@echo "... recent_entries.obj"
|
@echo "... recent_entries.obj"
|
||||||
@echo "... recent_entries.i"
|
@echo "... recent_entries.i"
|
||||||
@echo "... recent_entries.s"
|
@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.obj"
|
||||||
@echo "... rf_path.i"
|
@echo "... rf_path.i"
|
||||||
@echo "... rf_path.s"
|
@echo "... rf_path.s"
|
||||||
@ -5580,6 +5667,9 @@ help:
|
|||||||
@echo "... ui_record_view.obj"
|
@echo "... ui_record_view.obj"
|
||||||
@echo "... ui_record_view.i"
|
@echo "... ui_record_view.i"
|
||||||
@echo "... ui_record_view.s"
|
@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.obj"
|
||||||
@echo "... ui_rssi.i"
|
@echo "... ui_rssi.i"
|
||||||
@echo "... ui_rssi.s"
|
@echo "... ui_rssi.s"
|
||||||
|
@ -512,6 +512,29 @@ static constexpr Bitmap bitmap_icon_remote {
|
|||||||
{ 16, 16 }, bitmap_icon_remote_data
|
{ 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[] = {
|
static constexpr uint8_t bitmap_icon_soundboard_data[] = {
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
0xDE, 0x7B,
|
0xDE, 0x7B,
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
//TEST: Imperial in whipcalc
|
//TEST: Imperial in whipcalc
|
||||||
//TEST: Numbers
|
//TEST: Numbers
|
||||||
//TEST: Jammer
|
//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: "TX box" view or composite widget with frequency and bw settings, simple and advanced setup TX buttons...
|
||||||
//TODO: Morse coder for foxhunts
|
//TODO: Morse coder for foxhunts
|
||||||
//TODO: Finish EPAR tx
|
//TODO: Finish EPAR tx
|
||||||
|
121
firmware/application/replay_app.cpp
Normal file
121
firmware/application/replay_app.cpp
Normal 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 */
|
95
firmware/application/replay_app.hpp
Normal file
95
firmware/application/replay_app.hpp
Normal 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__*/
|
143
firmware/application/replay_thread.cpp
Normal file
143
firmware/application/replay_thread.cpp
Normal 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 { };
|
||||||
|
}
|
74
firmware/application/replay_thread.hpp
Normal file
74
firmware/application/replay_thread.hpp
Normal 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__*/
|
@ -55,6 +55,7 @@
|
|||||||
#include "tpms_app.hpp"
|
#include "tpms_app.hpp"
|
||||||
#include "pocsag_app.hpp"
|
#include "pocsag_app.hpp"
|
||||||
#include "capture_app.hpp"
|
#include "capture_app.hpp"
|
||||||
|
#include "replay_app.hpp"
|
||||||
|
|
||||||
#include "core_control.hpp"
|
#include "core_control.hpp"
|
||||||
|
|
||||||
@ -338,16 +339,16 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||||
add_items<11>({ {
|
add_items<12>({ {
|
||||||
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
||||||
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receiver, [&nav](){ nav.push<ReceiverMenuView>(); } },
|
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receiver, [&nav](){ nav.push<ReceiverMenuView>(); } },
|
||||||
{ "Capture", ui::Color::cyan(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
{ "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>(); } },
|
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
|
||||||
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
|
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
|
||||||
{ "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push<CloseCallView>(); } },
|
{ "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push<CloseCallView>(); } },
|
||||||
{ "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
{ "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
||||||
{ "Utilities", ui::Color::purple(),nullptr, [&nav](){ nav.push<UtilitiesView>(); } },
|
{ "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>(); } },
|
{ "Setup", ui::Color::white(), nullptr, [&nav](){ nav.push<SetupMenuView>(); } },
|
||||||
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
||||||
{ "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },
|
{ "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },
|
||||||
|
191
firmware/application/ui_replay_view.cpp
Normal file
191
firmware/application/ui_replay_view.cpp
Normal 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 */
|
116
firmware/application/ui_replay_view.hpp
Normal file
116
firmware/application/ui_replay_view.hpp
Normal 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__*/
|
@ -114,6 +114,7 @@ set(CPPSRC
|
|||||||
matched_filter.cpp
|
matched_filter.cpp
|
||||||
spectrum_collector.cpp
|
spectrum_collector.cpp
|
||||||
stream_input.cpp
|
stream_input.cpp
|
||||||
|
stream_output.cpp
|
||||||
dsp_squelch.cpp
|
dsp_squelch.cpp
|
||||||
clock_recovery.cpp
|
clock_recovery.cpp
|
||||||
packet_builder.cpp
|
packet_builder.cpp
|
||||||
@ -368,12 +369,12 @@ set(MODE_CPPSRC
|
|||||||
)
|
)
|
||||||
DeclareTargets(PAFS afsk)
|
DeclareTargets(PAFS afsk)
|
||||||
|
|
||||||
### Epar
|
### Replay
|
||||||
|
|
||||||
#set(MODE_CPPSRC
|
set(MODE_CPPSRC
|
||||||
# proc_epar.cpp
|
proc_replay.cpp
|
||||||
#)
|
)
|
||||||
#DeclareTargets(PEPR epar)
|
DeclareTargets(PREP replay)
|
||||||
|
|
||||||
### Tones
|
### Tones
|
||||||
|
|
||||||
|
84
firmware/baseband/proc_replay.cpp
Normal file
84
firmware/baseband/proc_replay.cpp
Normal 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;
|
||||||
|
}
|
70
firmware/baseband/proc_replay.hpp
Normal file
70
firmware/baseband/proc_replay.hpp
Normal 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__*/
|
76
firmware/baseband/stream_output.cpp
Normal file
76
firmware/baseband/stream_output.cpp
Normal 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;
|
||||||
|
}
|
54
firmware/baseband/stream_output.hpp
Normal file
54
firmware/baseband/stream_output.hpp
Normal 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__*/
|
@ -66,23 +66,25 @@ public:
|
|||||||
DisplaySleep = 16,
|
DisplaySleep = 16,
|
||||||
CaptureConfig = 17,
|
CaptureConfig = 17,
|
||||||
CaptureThreadDone = 18,
|
CaptureThreadDone = 18,
|
||||||
|
ReplayConfig = 19,
|
||||||
|
ReplayThreadDone = 20,
|
||||||
|
|
||||||
TXDone = 20,
|
TXDone = 30,
|
||||||
Retune = 21,
|
Retune = 31,
|
||||||
TonesConfigure = 22,
|
TonesConfigure = 32,
|
||||||
AFSKConfigure = 23,
|
AFSKConfigure = 33,
|
||||||
PWMRSSIConfigure = 24,
|
PWMRSSIConfigure = 34,
|
||||||
OOKConfigure = 25,
|
OOKConfigure = 35,
|
||||||
RDSConfigure = 26,
|
RDSConfigure = 36,
|
||||||
AudioTXConfig = 27,
|
AudioTXConfig = 37,
|
||||||
POCSAGConfigure = 28,
|
POCSAGConfigure = 38,
|
||||||
DTMFTXConfig = 29,
|
DTMFTXConfig = 39,
|
||||||
ADSBConfigure = 30,
|
ADSBConfigure = 40,
|
||||||
|
|
||||||
POCSAGPacket = 31,
|
POCSAGPacket = 41,
|
||||||
|
|
||||||
FIFOSignal = 32,
|
FIFOSignal = 52,
|
||||||
FIFOData = 33,
|
FIFOData = 53,
|
||||||
MAX
|
MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -492,6 +494,37 @@ public:
|
|||||||
CaptureConfig* const config;
|
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 {
|
class TXDoneMessage : public Message {
|
||||||
public:
|
public:
|
||||||
constexpr TXDoneMessage(
|
constexpr TXDoneMessage(
|
||||||
@ -715,4 +748,16 @@ public:
|
|||||||
uint32_t error;
|
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__*/
|
#endif/*__MESSAGE_H__*/
|
||||||
|
@ -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_rds { 'P', 'R', 'D', 'S' };
|
||||||
constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' };
|
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_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' };
|
constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' };
|
||||||
|
|
||||||
|
BIN
firmware/graphics/PP_REPLAY.png
Normal file
BIN
firmware/graphics/PP_REPLAY.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 145 B |
Loading…
x
Reference in New Issue
Block a user