diff options
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; +} |