diff options
author | Tom Tsou <tom.tsou@ettus.com> | 2015-08-21 19:32:58 -0700 |
---|---|---|
committer | Tom Tsou <tom.tsou@ettus.com> | 2016-07-01 03:03:11 -0700 |
commit | 28670fb5dad8e48ff74051a5bbe0c8309b04c817 (patch) | |
tree | f93d11d8a26701cdecceebdf40b9fac006c8af03 /Transceiver52M/radioBuffer.cpp | |
parent | 05c6feb71dd2f66b74c9e1671d91570485479836 (diff) |
iface: Add inner ring-buffer implementation
Two buffers, inner and outer, are used in the transceiver
implementation. The outer buffer interfaces with the device receive
interface to guarantee timestamp aligned and contiguously allocated
sample buffers. The inner buffer absorbs vector size differences between
GSM bursts (156 or 157 samples) and the resampler interface (typically
fixed multiples of 65).
Reimplement the inner buffer with a ring buffer that allows fixed size
segments on the outer (resampler) portion and variable lengths (GSM
side) on the inner side. Compared to the previous stack-like version,
this implementation removes unnecessary copying of buffer contents.
Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
Diffstat (limited to 'Transceiver52M/radioBuffer.cpp')
-rw-r--r-- | Transceiver52M/radioBuffer.cpp | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/Transceiver52M/radioBuffer.cpp b/Transceiver52M/radioBuffer.cpp new file mode 100644 index 0000000..9e6f079 --- /dev/null +++ b/Transceiver52M/radioBuffer.cpp @@ -0,0 +1,228 @@ +/* + * Segmented Ring Buffer + * + * Copyright (C) 2015 Ettus Research LLC + * + * Author: Tom Tsou <tom@tsou.cc> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * See the COPYING file in the main directory for details. + */ + +#include <string.h> +#include <iostream> +#include "radioBuffer.h" + +RadioBuffer::RadioBuffer(size_t numSegments, size_t segmentLen, + size_t hLen, bool outDirection) + : writeIndex(0), readIndex(0), availSamples(0) +{ + if (!outDirection) + hLen = 0; + + buffer = new float[2 * (hLen + numSegments * segmentLen)]; + bufferLen = numSegments * segmentLen; + + segments.resize(numSegments); + + for (size_t i = 0; i < numSegments; i++) + segments[i] = &buffer[2 * (hLen + i * segmentLen)]; + + this->outDirection = outDirection; + this->numSegments = numSegments; + this->segmentLen = segmentLen; + this->hLen = hLen; +} + +RadioBuffer::~RadioBuffer() +{ + delete buffer; +} + +void RadioBuffer::reset() +{ + writeIndex = 0; + readIndex = 0; + availSamples = 0; +} + +/* + * Output direction + * + * Return a pointer to the oldest segment or NULL if a complete segment is not + * available. + */ +const float *RadioBuffer::getReadSegment() +{ + if (!outDirection) { + std::cout << "Invalid direction" << std::endl; + return NULL; + } + if (availSamples < segmentLen) { + std::cout << "Not enough samples " << std::endl; + std::cout << availSamples << " available per segment " + << segmentLen << std::endl; + return NULL; + } + + size_t num = readIndex / segmentLen; + + if (num >= numSegments) { + std::cout << "Invalid segment" << std::endl; + return NULL; + } else if (!num) { + memcpy(buffer, + &buffer[2 * bufferLen], + hLen * 2 * sizeof(float)); + } + + availSamples -= segmentLen; + readIndex = (readIndex + segmentLen) % bufferLen; + + return segments[num]; +} + +/* + * Output direction + * + * Write a non-segment length of samples to the buffer. + */ +bool RadioBuffer::write(const float *wr, size_t len) +{ + if (!outDirection) { + std::cout << "Invalid direction" << std::endl; + return false; + } + if (availSamples + len > bufferLen) { + std::cout << "Insufficient space" << std::endl; + std::cout << bufferLen - availSamples << " available per write " + << len << std::endl; + return false; + } + + if (writeIndex + len <= bufferLen) { + memcpy(&buffer[2 * (writeIndex + hLen)], + wr, len * 2 * sizeof(float)); + } else { + size_t len0 = bufferLen - writeIndex; + size_t len1 = len - len0; + memcpy(&buffer[2 * (writeIndex + hLen)], wr, len0 * 2 * sizeof(float)); + memcpy(&buffer[2 * hLen], &wr[2 * len0], len1 * 2 * sizeof(float)); + } + + availSamples += len; + writeIndex = (writeIndex + len) % bufferLen; + + return true; +} + +bool RadioBuffer::zero(size_t len) +{ + if (!outDirection) { + std::cout << "Invalid direction" << std::endl; + return false; + } + if (availSamples + len > bufferLen) { + std::cout << "Insufficient space" << std::endl; + std::cout << bufferLen - availSamples << " available per zero " + << len << std::endl; + return false; + } + + if (writeIndex + len <= bufferLen) { + memset(&buffer[2 * (writeIndex + hLen)], + 0, len * 2 * sizeof(float)); + } else { + size_t len0 = bufferLen - writeIndex; + size_t len1 = len - len0; + memset(&buffer[2 * (writeIndex + hLen)], 0, len0 * 2 * sizeof(float)); + memset(&buffer[2 * hLen], 0, len1 * 2 * sizeof(float)); + } + + availSamples += len; + writeIndex = (writeIndex + len) % bufferLen; + + return true; +} + +/* + * Input direction + */ +float *RadioBuffer::getWriteSegment() +{ + if (outDirection) { + std::cout << "Invalid direction" << std::endl; + return NULL; + } + if (bufferLen - availSamples < segmentLen) { + std::cout << "Insufficient samples" << std::endl; + std::cout << bufferLen - availSamples + << " available for segment " << segmentLen + << std::endl; + return NULL; + } + if (writeIndex % segmentLen) { + std::cout << "Internal segment error" << std::endl; + return NULL; + } + + size_t num = writeIndex / segmentLen; + + if (num >= numSegments) + return NULL; + + availSamples += segmentLen; + writeIndex = (writeIndex + segmentLen) % bufferLen; + + return segments[num]; +} + +bool RadioBuffer::zeroWriteSegment() +{ + float *segment = getWriteSegment(); + if (!segment) + return false; + + memset(segment, 0, segmentLen * 2 * sizeof(float)); + + return true; +} + +bool RadioBuffer::read(float *rd, size_t len) +{ + if (outDirection) { + std::cout << "Invalid direction" << std::endl; + return false; + } + if (availSamples < len) { + std::cout << "Insufficient samples" << std::endl; + std::cout << availSamples << " available for " + << len << std::endl; + return false; + } + + if (readIndex + len <= bufferLen) { + memcpy(rd, &buffer[2 * readIndex], len * 2 * sizeof(float)); + } else { + size_t len0 = bufferLen - readIndex; + size_t len1 = len - len0; + memcpy(rd, &buffer[2 * readIndex], len0 * 2 * sizeof(float)); + memcpy(&rd[2 * len0], buffer, len1 * 2 * sizeof(float)); + } + + availSamples -= len; + readIndex = (readIndex + len) % bufferLen; + + return true; +} |