mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-05-08 04:36:49 +00:00
Refactor of capture buffer management between cores.
Instead of copying data into and out of FIFO, passing buffer pointers between cores that are sized to match preferred/ideal SD card write size.
This commit is contained in:
parent
85a6ecd5dc
commit
b82eff51dd
@ -143,7 +143,7 @@ private:
|
|||||||
|
|
||||||
RecordView record_view {
|
RecordView record_view {
|
||||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||||
"AUD_????", RecordView::FileType::WAV, 12, 2,
|
"AUD_????", RecordView::FileType::WAV, 4096, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
spectrum::WaterfallWidget waterfall;
|
spectrum::WaterfallWidget waterfall;
|
||||||
|
@ -78,7 +78,7 @@ private:
|
|||||||
|
|
||||||
RecordView record_view {
|
RecordView record_view {
|
||||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||||
"BBD_????", RecordView::FileType::RawS16, 14, 1,
|
"BBD_????", RecordView::FileType::RawS16, 16384, 3
|
||||||
};
|
};
|
||||||
|
|
||||||
spectrum::WaterfallWidget waterfall;
|
spectrum::WaterfallWidget waterfall;
|
||||||
|
@ -31,20 +31,29 @@ public:
|
|||||||
~StreamOutput();
|
~StreamOutput();
|
||||||
|
|
||||||
size_t available() {
|
size_t available() {
|
||||||
return fifo->len();
|
return fifo_buffers_full->len();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t read(void* const data, const size_t length) {
|
StreamBuffer* get_buffer() {
|
||||||
return fifo->out(reinterpret_cast<uint8_t*>(data), length);
|
StreamBuffer* p { nullptr };
|
||||||
|
fifo_buffers_full->out(p);
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FIFO<uint8_t>* fifo;
|
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:
|
private:
|
||||||
CaptureConfig* const config;
|
CaptureConfig* const config;
|
||||||
};
|
};
|
||||||
|
|
||||||
FIFO<uint8_t>* StreamOutput::fifo = nullptr;
|
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_empty = nullptr;
|
||||||
|
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_full = nullptr;
|
||||||
|
|
||||||
StreamOutput::StreamOutput(
|
StreamOutput::StreamOutput(
|
||||||
CaptureConfig* const config
|
CaptureConfig* const config
|
||||||
@ -53,11 +62,13 @@ StreamOutput::StreamOutput(
|
|||||||
shared_memory.baseband_queue.push_and_wait(
|
shared_memory.baseband_queue.push_and_wait(
|
||||||
CaptureConfigMessage { config }
|
CaptureConfigMessage { config }
|
||||||
);
|
);
|
||||||
fifo = config->fifo;
|
fifo_buffers_empty = config->fifo_buffers_empty;
|
||||||
|
fifo_buffers_full = config->fifo_buffers_full;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamOutput::~StreamOutput() {
|
StreamOutput::~StreamOutput() {
|
||||||
fifo = nullptr;
|
fifo_buffers_full = nullptr;
|
||||||
|
fifo_buffers_empty = nullptr;
|
||||||
shared_memory.baseband_queue.push_and_wait(
|
shared_memory.baseband_queue.push_and_wait(
|
||||||
CaptureConfigMessage { nullptr }
|
CaptureConfigMessage { nullptr }
|
||||||
);
|
);
|
||||||
@ -69,9 +80,9 @@ Thread* CaptureThread::thread = nullptr;
|
|||||||
|
|
||||||
CaptureThread::CaptureThread(
|
CaptureThread::CaptureThread(
|
||||||
std::unique_ptr<Writer> writer,
|
std::unique_ptr<Writer> writer,
|
||||||
size_t write_size_log2,
|
size_t write_size,
|
||||||
size_t buffer_count_log2
|
size_t buffer_count
|
||||||
) : config { write_size_log2, buffer_count_log2 },
|
) : config { write_size, buffer_count },
|
||||||
writer { std::move(writer) }
|
writer { std::move(writer) }
|
||||||
{
|
{
|
||||||
// Need significant stack for FATFS
|
// Need significant stack for FATFS
|
||||||
@ -90,29 +101,22 @@ CaptureThread::~CaptureThread() {
|
|||||||
void CaptureThread::check_fifo_isr() {
|
void CaptureThread::check_fifo_isr() {
|
||||||
// TODO: Prevent over-signalling by transmitting a set of
|
// TODO: Prevent over-signalling by transmitting a set of
|
||||||
// flags from the baseband core.
|
// flags from the baseband core.
|
||||||
const auto fifo = StreamOutput::fifo;
|
const auto fifo = StreamOutput::fifo_buffers_full;
|
||||||
if( fifo ) {
|
if( fifo ) {
|
||||||
chEvtSignalI(thread, EVT_MASK_CAPTURE_THREAD);
|
chEvtSignalI(thread, EVT_MASK_CAPTURE_THREAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_t CaptureThread::run() {
|
msg_t CaptureThread::run() {
|
||||||
const size_t write_size = 1U << config.write_size_log2;
|
|
||||||
const auto write_buffer = std::make_unique<uint8_t[]>(write_size);
|
|
||||||
if( !write_buffer ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamOutput stream { &config };
|
StreamOutput stream { &config };
|
||||||
|
|
||||||
while( !chThdShouldTerminate() ) {
|
while( !chThdShouldTerminate() ) {
|
||||||
if( stream.available() >= write_size ) {
|
if( stream.available() ) {
|
||||||
if( stream.read(write_buffer.get(), write_size) != write_size ) {
|
auto buffer = stream.get_buffer();
|
||||||
return false;
|
if( !writer->write(buffer->data(), buffer->size()) ) {
|
||||||
}
|
|
||||||
if( !writer->write(write_buffer.get(), write_size) ) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
stream.release_buffer(buffer);
|
||||||
} else {
|
} else {
|
||||||
chEvtWaitAny(EVT_MASK_CAPTURE_THREAD);
|
chEvtWaitAny(EVT_MASK_CAPTURE_THREAD);
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ class CaptureThread {
|
|||||||
public:
|
public:
|
||||||
CaptureThread(
|
CaptureThread(
|
||||||
std::unique_ptr<Writer> writer,
|
std::unique_ptr<Writer> writer,
|
||||||
size_t write_size_log2,
|
size_t write_size,
|
||||||
size_t buffer_count_log2
|
size_t buffer_count
|
||||||
);
|
);
|
||||||
~CaptureThread();
|
~CaptureThread();
|
||||||
|
|
||||||
|
@ -139,13 +139,13 @@ RecordView::RecordView(
|
|||||||
const Rect parent_rect,
|
const Rect parent_rect,
|
||||||
std::string filename_stem_pattern,
|
std::string filename_stem_pattern,
|
||||||
const FileType file_type,
|
const FileType file_type,
|
||||||
const size_t buffer_size_k,
|
const size_t write_size,
|
||||||
const size_t buffer_count_k
|
const size_t buffer_count
|
||||||
) : View { parent_rect },
|
) : View { parent_rect },
|
||||||
filename_stem_pattern { filename_stem_pattern },
|
filename_stem_pattern { filename_stem_pattern },
|
||||||
file_type { file_type },
|
file_type { file_type },
|
||||||
buffer_size_k { buffer_size_k },
|
write_size { write_size },
|
||||||
buffer_count_k { buffer_count_k }
|
buffer_count { buffer_count }
|
||||||
{
|
{
|
||||||
add_children({ {
|
add_children({ {
|
||||||
&button_record,
|
&button_record,
|
||||||
@ -222,7 +222,7 @@ void RecordView::start() {
|
|||||||
button_record.set_bitmap(&bitmap_stop);
|
button_record.set_bitmap(&bitmap_stop);
|
||||||
capture_thread = std::make_unique<CaptureThread>(
|
capture_thread = std::make_unique<CaptureThread>(
|
||||||
std::move(writer),
|
std::move(writer),
|
||||||
buffer_size_k, buffer_count_k
|
write_size, buffer_count
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ public:
|
|||||||
const Rect parent_rect,
|
const Rect parent_rect,
|
||||||
std::string filename_stem_pattern,
|
std::string filename_stem_pattern,
|
||||||
FileType file_type,
|
FileType file_type,
|
||||||
const size_t buffer_size_k,
|
const size_t write_size,
|
||||||
const size_t buffer_count_k
|
const size_t buffer_count
|
||||||
);
|
);
|
||||||
~RecordView();
|
~RecordView();
|
||||||
|
|
||||||
@ -73,8 +73,8 @@ private:
|
|||||||
|
|
||||||
const std::string filename_stem_pattern;
|
const std::string filename_stem_pattern;
|
||||||
const FileType file_type;
|
const FileType file_type;
|
||||||
const size_t buffer_size_k;
|
const size_t write_size;
|
||||||
const size_t buffer_count_k;
|
const size_t buffer_count;
|
||||||
size_t sampling_rate { 0 };
|
size_t sampling_rate { 0 };
|
||||||
SignalToken signal_token_tick_second;
|
SignalToken signal_token_tick_second;
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ CPPSRC = main.cpp \
|
|||||||
proc_tpms.cpp \
|
proc_tpms.cpp \
|
||||||
proc_ert.cpp \
|
proc_ert.cpp \
|
||||||
proc_capture.cpp \
|
proc_capture.cpp \
|
||||||
|
stream_input.cpp \
|
||||||
dsp_squelch.cpp \
|
dsp_squelch.cpp \
|
||||||
clock_recovery.cpp \
|
clock_recovery.cpp \
|
||||||
packet_builder.cpp \
|
packet_builder.cpp \
|
||||||
|
76
firmware/baseband/stream_input.cpp
Normal file
76
firmware/baseband/stream_input.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
*
|
||||||
|
* 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_input.hpp"
|
||||||
|
|
||||||
|
#include "lpc43xx_cpp.hpp"
|
||||||
|
using namespace lpc43xx;
|
||||||
|
|
||||||
|
StreamInput::StreamInput(CaptureConfig* 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->write_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->write_size]), config->write_size };
|
||||||
|
fifo_buffers_empty.in(&buffers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StreamInput::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_received += length;
|
||||||
|
config->baseband_bytes_dropped += (length - written);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
@ -25,46 +25,29 @@
|
|||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
#include "fifo.hpp"
|
#include "fifo.hpp"
|
||||||
|
|
||||||
#include "lpc43xx_cpp.hpp"
|
|
||||||
using namespace lpc43xx;
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class StreamInput {
|
class StreamInput {
|
||||||
public:
|
public:
|
||||||
StreamInput(CaptureConfig* const config) :
|
StreamInput(CaptureConfig* const config);
|
||||||
config { config },
|
|
||||||
K { config->write_size_log2 + config->buffer_count_log2 },
|
|
||||||
event_bytes_mask { (1UL << config->write_size_log2) - 1 },
|
|
||||||
data { std::make_unique<uint8_t[]>(1UL << K) },
|
|
||||||
fifo { data.get(), K }
|
|
||||||
{
|
|
||||||
config->fifo = &fifo;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(const void* const data, const size_t length) {
|
size_t write(const void* const data, const size_t length);
|
||||||
const auto written = fifo.in(reinterpret_cast<const uint8_t*>(data), length);
|
|
||||||
|
|
||||||
const auto last_bytes_written = bytes_written;
|
|
||||||
bytes_written += written;
|
|
||||||
if( (bytes_written & event_bytes_mask) < (last_bytes_written & event_bytes_mask) ) {
|
|
||||||
creg::m4txevent::assert();
|
|
||||||
}
|
|
||||||
config->baseband_bytes_received += length;
|
|
||||||
config->baseband_bytes_dropped = config->baseband_bytes_received - bytes_written;
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CaptureConfig* const config;
|
static constexpr size_t buffer_count_max_log2 = 3;
|
||||||
const size_t K;
|
static constexpr size_t buffer_count_max = 1U << buffer_count_max_log2;
|
||||||
const uint64_t event_bytes_mask;
|
|
||||||
uint64_t bytes_written = 0;
|
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 };
|
||||||
|
CaptureConfig* const config { nullptr };
|
||||||
std::unique_ptr<uint8_t[]> data;
|
std::unique_ptr<uint8_t[]> data;
|
||||||
FIFO<uint8_t> fifo;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__STREAM_INPUT_H__*/
|
#endif/*__STREAM_INPUT_H__*/
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -411,21 +412,63 @@ public:
|
|||||||
const iir_biquad_config_t audio_hpf_config;
|
const iir_biquad_config_t audio_hpf_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Put this somewhere else, or at least the implementation part.
|
||||||
|
class StreamBuffer {
|
||||||
|
uint8_t* data_;
|
||||||
|
size_t used_;
|
||||||
|
size_t capacity_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr StreamBuffer(
|
||||||
|
void* const data = nullptr,
|
||||||
|
const size_t capacity = 0
|
||||||
|
) : data_ { static_cast<uint8_t*>(data) },
|
||||||
|
used_ { 0 },
|
||||||
|
capacity_ { capacity }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const void* p, const size_t count) {
|
||||||
|
const auto copy_size = std::min(capacity_ - used_, count);
|
||||||
|
memcpy(&data_[used_], p, copy_size);
|
||||||
|
used_ += copy_size;
|
||||||
|
return copy_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_full() const {
|
||||||
|
return used_ >= capacity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* data() const {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return used_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void empty() {
|
||||||
|
used_ = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct CaptureConfig {
|
struct CaptureConfig {
|
||||||
const size_t write_size_log2;
|
const size_t write_size;
|
||||||
const size_t buffer_count_log2;
|
const size_t buffer_count;
|
||||||
uint64_t baseband_bytes_received;
|
uint64_t baseband_bytes_received;
|
||||||
uint64_t baseband_bytes_dropped;
|
uint64_t baseband_bytes_dropped;
|
||||||
FIFO<uint8_t>* fifo;
|
FIFO<StreamBuffer*>* fifo_buffers_empty;
|
||||||
|
FIFO<StreamBuffer*>* fifo_buffers_full;
|
||||||
|
|
||||||
constexpr CaptureConfig(
|
constexpr CaptureConfig(
|
||||||
const size_t write_size_log2,
|
const size_t write_size,
|
||||||
const size_t buffer_count_log2
|
const size_t buffer_count
|
||||||
) : write_size_log2 { write_size_log2 },
|
) : write_size { write_size },
|
||||||
buffer_count_log2 { buffer_count_log2 },
|
buffer_count { buffer_count },
|
||||||
baseband_bytes_received { 0 },
|
baseband_bytes_received { 0 },
|
||||||
baseband_bytes_dropped { 0 },
|
baseband_bytes_dropped { 0 },
|
||||||
fifo { nullptr }
|
fifo_buffers_empty { nullptr },
|
||||||
|
fifo_buffers_full { nullptr }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user