POCSAG address filter now ignores alpha messages

Experimenting with FIFOs for replay...
This commit is contained in:
furrtek 2017-04-19 22:05:16 +01:00
parent a053c0e234
commit 40b49e2072
20 changed files with 120 additions and 69 deletions

View File

@ -281,13 +281,13 @@ void capture_stop() {
send_message(&message); send_message(&message);
} }
void replay_start(CaptureConfig* const config) { void replay_start(ReplayConfig* const config) {
CaptureConfigMessage message { config }; ReplayConfigMessage message { config };
send_message(&message); send_message(&message);
} }
void replay_stop() { void replay_stop() {
CaptureConfigMessage message { nullptr }; ReplayConfigMessage message { nullptr };
send_message(&message); send_message(&message);
} }

View File

@ -86,7 +86,7 @@ void spectrum_streaming_stop();
void capture_start(CaptureConfig* const config); void capture_start(CaptureConfig* const config);
void capture_stop(); void capture_stop();
void replay_start(CaptureConfig* const config); void replay_start(ReplayConfig* const config);
void replay_stop(); void replay_stop();
} /* namespace baseband */ } /* namespace baseband */

View File

@ -23,6 +23,7 @@
// Color bitmaps generated with: // Color bitmaps generated with:
// Gimp image > indexed colors (16), then "xxd -i *.bmp" // Gimp image > indexed colors (16), then "xxd -i *.bmp"
//BUG: Replay freezes when SD card not present
//TODO: CTCSS detector //TODO: CTCSS detector
//BUG: RDS doesn't stop baseband when stopping tx ? //BUG: RDS doesn't stop baseband when stopping tx ?
//BUG: Check AFSK transmit end, skips last bits ? //BUG: Check AFSK transmit end, skips last bits ?

View File

@ -147,10 +147,10 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
else { else {
pocsag_decode_batch(message->packet, &pocsag_state); pocsag_decode_batch(message->packet, &pocsag_state);
if ((ignore) && (pocsag_state.out_type == ADDRESS) && (pocsag_state.address == sym_ignore.value_dec_u32())) { if ((ignore) && (pocsag_state.address == sym_ignore.value_dec_u32())) {
// Ignore (inform, but no log) // Ignore (inform, but no log)
console.write("\n\x1B\x03" + to_string_time(message->packet.timestamp()) + //console.write("\n\x1B\x03" + to_string_time(message->packet.timestamp()) +
" Ignored address " + to_string_dec_uint(pocsag_state.address)); // " Ignored address " + to_string_dec_uint(pocsag_state.address));
return; return;
} }
@ -179,9 +179,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
} else if (pocsag_state.out_type == MESSAGE) { } else if (pocsag_state.out_type == MESSAGE) {
if (pocsag_state.address != last_address) { if (pocsag_state.address != last_address) {
// New message // New message
console.writeln(console_info); console.writeln(console_info);
console.write(pocsag_state.output); console.write(pocsag_state.output);
last_address = pocsag_state.address; last_address = pocsag_state.address;

View File

@ -29,7 +29,6 @@
using namespace portapack; using namespace portapack;
#include "portapack_persistent_memory.hpp" #include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace ui { namespace ui {
@ -46,14 +45,14 @@ ReplayAppView::ReplayAppView(
return; return;
} }
//baseband::run_image(portapack::spi_flash::image_tag_replay); baseband::run_image(portapack::spi_flash::image_tag_replay);
add_children({ add_children({
&field_frequency, &field_frequency,
&field_frequency_step, &field_frequency_step,
&field_rf_amp, &field_rf_amp,
&replay_view, &replay_view,
&waterfall, //&waterfall,
}); });
replay_view.set_file_list(file_list); replay_view.set_file_list(file_list);
@ -91,16 +90,17 @@ ReplayAppView::~ReplayAppView() {
void ReplayAppView::on_hide() { void ReplayAppView::on_hide() {
// TODO: Terrible kludge because widget system doesn't notify Waterfall that // TODO: Terrible kludge because widget system doesn't notify Waterfall that
// it's being shown or hidden. // it's being shown or hidden.
waterfall.on_hide();
//waterfall.on_hide();
View::on_hide(); View::on_hide();
} }
void ReplayAppView::set_parent_rect(const Rect new_parent_rect) { /*void ReplayAppView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_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) }; 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); waterfall.set_parent_rect(waterfall_rect);
} }*/
void ReplayAppView::focus() { void ReplayAppView::focus() {
field_frequency.focus(); field_frequency.focus();

View File

@ -41,11 +41,11 @@ public:
void on_hide() override; void on_hide() override;
void set_parent_rect(const Rect new_parent_rect) override; //void set_parent_rect(const Rect new_parent_rect) override;
void focus() override; void focus() override;
std::string title() const override { return "Replay (beta)"; }; std::string title() const override { return "Replay (broken)"; };
private: private:
NavigationView& nav_; NavigationView& nav_;
@ -79,7 +79,7 @@ private:
16384, 3 16384, 3
}; };
spectrum::WaterfallWidget waterfall { }; //spectrum::WaterfallWidget waterfall { };
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -25,8 +25,12 @@
#include "baseband_api.hpp" #include "baseband_api.hpp"
#include "buffer_exchange.hpp" #include "buffer_exchange.hpp"
// DEBUG:
#include "hackrf_gpio.hpp"
using namespace hackrf::one;
struct BasebandReplay { struct BasebandReplay {
BasebandReplay(CaptureConfig* const config) { BasebandReplay(ReplayConfig* const config) {
baseband::replay_start(config); baseband::replay_start(config);
} }
@ -63,13 +67,13 @@ ReplayThread::~ReplayThread() {
msg_t ReplayThread::static_fn(void* arg) { msg_t ReplayThread::static_fn(void* arg) {
auto obj = static_cast<ReplayThread*>(arg); auto obj = static_cast<ReplayThread*>(arg);
const auto error = obj->run(); const auto error = obj->run();
if( error.is_valid() && obj->error_callback ) { /*if( error.is_valid() && obj->error_callback ) {
obj->error_callback(error.value()); obj->error_callback(error.value());
} else { } else {
if( obj->success_callback ) { if( obj->success_callback ) {
obj->success_callback(); obj->success_callback();
} }
} }*/
return 0; return 0;
} }
@ -78,12 +82,15 @@ Optional<File::Error> ReplayThread::run() {
BufferExchange buffers { &config }; BufferExchange buffers { &config };
while( !chThdShouldTerminate() ) { while( !chThdShouldTerminate() ) {
auto buffer = buffers.get(); //auto buffer = buffers.get();
auto read_result = reader->read(buffer->data(), buffer->size()); buffers.get();
/*auto read_result = reader->read(buffer->data(), buffer->size());
if( read_result.is_error() ) { if( read_result.is_error() ) {
return read_result.error(); return read_result.error();
} }
buffers.put(buffer); buffers.put(buffer);*/
chThdSleep(50);
//led_tx.toggle();
} }
return { }; return { };

View File

@ -50,12 +50,12 @@ public:
ReplayThread& operator=(const ReplayThread&) = delete; ReplayThread& operator=(const ReplayThread&) = delete;
ReplayThread& operator=(ReplayThread&&) = delete; ReplayThread& operator=(ReplayThread&&) = delete;
const CaptureConfig& state() const { const ReplayConfig& state() const {
return config; return config;
} }
private: private:
CaptureConfig config; ReplayConfig config;
std::unique_ptr<stream::Reader> reader; std::unique_ptr<stream::Reader> reader;
std::function<void()> success_callback; std::function<void()> success_callback;
std::function<void(File::Error)> error_callback; std::function<void(File::Error)> error_callback;

View File

@ -360,7 +360,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
{ "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_receivers, [&nav](){ nav.push<ReceiverMenuView>(); } }, { "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiverMenuView>(); } },
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } }, { "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<NotImplementedView>(); } }, // ReplayAppView { "Replay", ui::Color::blue(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } }, // ReplayAppView
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } }, { "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } }, { "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
{ "SSTV transmitter", ui::Color::dark_green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } }, { "SSTV transmitter", ui::Color::dark_green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },

View File

@ -72,13 +72,13 @@ ReplayView::ReplayView(
this->toggle(); this->toggle();
}; };
signal_token_tick_second = rtc_time::signal_tick_second += [this]() { /*signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
this->on_tick_second(); this->on_tick_second();
}; };*/
} }
ReplayView::~ReplayView() { ReplayView::~ReplayView() {
rtc_time::signal_tick_second -= signal_token_tick_second; //rtc_time::signal_tick_second -= signal_token_tick_second;
} }
void ReplayView::focus() { void ReplayView::focus() {
@ -97,7 +97,6 @@ void ReplayView::set_file_list(const std::vector<std::filesystem::path>& file_li
options_files.set_options(file_options); options_files.set_options(file_options);
options_files.set_selected_index(0); // First file options_files.set_selected_index(0); // First file
on_file_changed(file_options[0].second); on_file_changed(file_options[0].second);
} }
bool ReplayView::is_active() const { bool ReplayView::is_active() const {
@ -136,8 +135,8 @@ void ReplayView::start() {
update_status_display(); update_status_display();
radio::enable({ radio::enable({
460000000, //target_frequency(), 434000000, //target_frequency(),
4000000, //sampling_rate, sampling_rate,
2500000, //baseband_bandwidth, 2500000, //baseband_bandwidth,
rf::Direction::Transmit, rf::Direction::Transmit,
receiver_model.rf_amp(), receiver_model.rf_amp(),

View File

@ -59,7 +59,7 @@ private:
using option_t = std::pair<std::string, int32_t>; using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>; using options_t = std::vector<option_t>;
static constexpr uint32_t sampling_rate = 4000000; static constexpr uint32_t sampling_rate = 500000;
void toggle(); void toggle();
@ -72,7 +72,7 @@ private:
const size_t read_size; const size_t read_size;
const size_t buffer_count; const size_t buffer_count;
SignalToken signal_token_tick_second { }; //SignalToken signal_token_tick_second { };
options_t file_options { }; options_t file_options { };
Rectangle rect_background { Rectangle rect_background {

View File

@ -39,15 +39,21 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
//const auto& decimator_out = decim_1_out; //const auto& decimator_out = decim_1_out;
//const auto& channel = decimator_out; //const auto& channel = decimator_out;
size_t pos = 0;
for (size_t c = 0; c < 4; c++) {
if( stream ) { if( stream ) {
const size_t bytes_to_read = buffer.count; // ? const size_t bytes_to_read = sizeof(*buffer.p) * buffer.count / 4; // ?
const auto result = stream->read(iq_buffer.p, bytes_to_read); const auto result = stream->read(iq_buffer.p, bytes_to_read);
} }
//feed_channel_stats(channel); //feed_channel_stats(channel);
for (size_t i = 0; i < buffer.count; i++) { for (size_t i = 0; i < (buffer.count / 4); i++) {
buffer.p[i] = { iq_buffer.p[i].real() >> 8, iq_buffer.p[i].imag() >> 8}; buffer.p[pos] = { iq_buffer.p[i].real() >> 8, iq_buffer.p[i].imag() >> 8 };
pos++;
//buffer.p[i] = { iq_buffer.p[i].real(), iq_buffer.p[i].imag() };
}
} }
/*spectrum_samples += channel.count; /*spectrum_samples += channel.count;

View File

@ -46,13 +46,13 @@ public:
private: private:
// TODO: Repeated value needs to be transmitted from application side. // TODO: Repeated value needs to be transmitted from application side.
static constexpr size_t baseband_fs = 4000000; static constexpr size_t baseband_fs = 500000;
//static constexpr auto spectrum_rate_hz = 50.0f; //static constexpr auto spectrum_rate_hz = 50.0f;
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit }; BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
//RSSIThread rssi_thread { NORMALPRIO + 10 }; //RSSIThread rssi_thread { NORMALPRIO + 10 };
std::array<complex16_t, 2048> iq { }; std::array<complex16_t, 512> iq { }; // 2048
const buffer_c16_t iq_buffer { const buffer_c16_t iq_buffer {
iq.data(), iq.data(),
iq.size() iq.size()

View File

@ -57,7 +57,7 @@ size_t StreamInput::write(const void* const data, const size_t length) {
if( active_buffer->is_full() ) { if( active_buffer->is_full() ) {
if( !fifo_buffers_full.in(active_buffer) ) { if( !fifo_buffers_full.in(active_buffer) ) {
// FIFO is fuil of buffers, there's no place for this one. // FIFO is full of buffers, there's no place for this one.
// Bail out of the loop, and try submitting the buffer in the // Bail out of the loop, and try submitting the buffer in the
// next pass. // next pass.
// This should never happen if the number of buffers is less // This should never happen if the number of buffers is less

View File

@ -40,29 +40,30 @@ StreamOutput::StreamOutput(ReplayConfig* const config) :
} }
} }
size_t StreamOutput::read(const void* const data, const size_t length) { size_t StreamOutput::read(void* const data, const size_t length) {
const uint8_t* p = static_cast<const uint8_t*>(data); uint8_t* p = static_cast<uint8_t*>(data);
size_t written = 0; size_t read = 0;
while( written < length ) { while( read < length ) {
if( !active_buffer ) { if( !active_buffer ) {
// We need an empty buffer... // We need a full buffer...
if( !fifo_buffers_empty.out(active_buffer) ) { if( !fifo_buffers_full.out(active_buffer) ) {
// ...but none are available. Samples were dropped. // ...but none are available. Samples were dropped.
//active_buffer = nullptr; // Testing ! Jumpstart
creg::m4txevent::assert();
break; break;
} }
} }
const auto remaining = length - written; const auto remaining = length - read;
written += active_buffer->write(&p[written], remaining); read += active_buffer->read(&p[read], remaining);
//buffer->empty();
if( active_buffer->is_full() ) { if( active_buffer->is_empty() ) {
if( !fifo_buffers_full.in(active_buffer) ) { if( !fifo_buffers_empty.in(active_buffer) ) {
// FIFO is fuil of buffers, there's no place for this one. // FIFO is completly empty.
// Bail out of the loop, and try submitting the buffer in the // Bail out of the loop, and try retrieving the buffer in the
// next pass. // next pass.
// This should never happen if the number of buffers is less
// than the capacity of the FIFO.
break; break;
} }
active_buffer = nullptr; active_buffer = nullptr;
@ -70,7 +71,7 @@ size_t StreamOutput::read(const void* const data, const size_t length) {
} }
} }
config->baseband_bytes_sent += length; config->baseband_bytes_received += length;
return written; return read;
} }

View File

@ -40,7 +40,7 @@ public:
StreamOutput& operator=(const StreamOutput&) = delete; StreamOutput& operator=(const StreamOutput&) = delete;
StreamOutput& operator=(StreamOutput&&) = delete; StreamOutput& operator=(StreamOutput&&) = delete;
size_t read(const void* const data, const size_t length); size_t read(void* const data, const size_t length);
private: private:
static constexpr size_t buffer_count_max_log2 = 3; static constexpr size_t buffer_count_max_log2 = 3;

View File

@ -21,17 +21,32 @@
#include "buffer_exchange.hpp" #include "buffer_exchange.hpp"
// DEBUG:
#include "hackrf_gpio.hpp"
using namespace hackrf::one;
BufferExchange* BufferExchange::obj { nullptr }; BufferExchange* BufferExchange::obj { nullptr };
BufferExchange::BufferExchange( BufferExchange::BufferExchange(
CaptureConfig* const config CaptureConfig* const config
) : config { config } ) // : config_capture { config }
{ {
obj = this; obj = this;
direction = CAPTURE;
fifo_buffers_for_baseband = config->fifo_buffers_empty; fifo_buffers_for_baseband = config->fifo_buffers_empty;
fifo_buffers_for_application = config->fifo_buffers_full; fifo_buffers_for_application = config->fifo_buffers_full;
} }
BufferExchange::BufferExchange(
ReplayConfig* const config
) // : config_replay { config }
{
obj = this;
direction = REPLAY;
fifo_buffers_for_baseband = config->fifo_buffers_full;
fifo_buffers_for_application = config->fifo_buffers_empty;
}
BufferExchange::~BufferExchange() { BufferExchange::~BufferExchange() {
obj = nullptr; obj = nullptr;
fifo_buffers_for_baseband = nullptr; fifo_buffers_for_baseband = nullptr;
@ -42,6 +57,9 @@ StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
while(true) { while(true) {
StreamBuffer* p { nullptr }; StreamBuffer* p { nullptr };
fifo->out(p); fifo->out(p);
led_tx.on(); // DEBUG
if( p ) { if( p ) {
return p; return p;
} }

View File

@ -30,6 +30,7 @@
class BufferExchange { class BufferExchange {
public: public:
BufferExchange(CaptureConfig* const config); BufferExchange(CaptureConfig* const config);
BufferExchange(ReplayConfig* const config);
~BufferExchange(); ~BufferExchange();
BufferExchange(const BufferExchange&) = delete; BufferExchange(const BufferExchange&) = delete;
@ -72,16 +73,25 @@ public:
} }
private: private:
CaptureConfig* const config; //CaptureConfig* const config_capture;
//ReplayConfig* const config_replay;
FIFO<StreamBuffer*>* fifo_buffers_for_baseband { nullptr }; FIFO<StreamBuffer*>* fifo_buffers_for_baseband { nullptr };
FIFO<StreamBuffer*>* fifo_buffers_for_application { nullptr }; FIFO<StreamBuffer*>* fifo_buffers_for_application { nullptr };
Thread* thread { nullptr }; Thread* thread { nullptr };
static BufferExchange* obj; static BufferExchange* obj;
enum {
CAPTURE,
REPLAY
} direction { };
void check_fifo_isr() { void check_fifo_isr() {
if( !empty() ) { //if (!empty() && (direction == CAPTURE)) {
if (!empty())
wakeup_isr(); wakeup_isr();
} //} else if (!empty() && (direction == REPLAY)) {
// wakeup_isr();
//}
} }
void wakeup_isr() { void wakeup_isr() {

View File

@ -459,10 +459,21 @@ public:
return copy_size; return copy_size;
} }
size_t read(void* p, const size_t count) {
const auto copy_size = std::min(used_, count);
memcpy(p, &data_[used_ - copy_size], copy_size);
used_ -= copy_size;
return copy_size;
}
bool is_full() const { bool is_full() const {
return used_ >= capacity_; return used_ >= capacity_;
} }
bool is_empty() const {
return used_ == 0;
}
void* data() const { void* data() const {
return data_; return data_;
} }
@ -525,7 +536,7 @@ public:
struct ReplayConfig { struct ReplayConfig {
const size_t read_size; const size_t read_size;
const size_t buffer_count; const size_t buffer_count;
uint64_t baseband_bytes_sent; uint64_t baseband_bytes_received;
FIFO<StreamBuffer*>* fifo_buffers_empty; FIFO<StreamBuffer*>* fifo_buffers_empty;
FIFO<StreamBuffer*>* fifo_buffers_full; FIFO<StreamBuffer*>* fifo_buffers_full;
@ -534,7 +545,7 @@ struct ReplayConfig {
const size_t buffer_count const size_t buffer_count
) : read_size { read_size }, ) : read_size { read_size },
buffer_count { buffer_count }, buffer_count { buffer_count },
baseband_bytes_sent { 0 }, baseband_bytes_received { 0 },
fifo_buffers_empty { nullptr }, fifo_buffers_empty { nullptr },
fifo_buffers_full { nullptr } fifo_buffers_full { nullptr }
{ {

Binary file not shown.