/* * Segmented Ring Buffer * * Copyright (C) 2015 Ettus Research LLC * * Author: Tom Tsou * * 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 . * See the COPYING file in the main directory for details. */ #include #include #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; }