blob: ec868e5c2616bbb3bea5b06b944d95a9eb762928 [file] [log] [blame]
Tom Tsou28670fb2015-08-21 19:32:58 -07001/*
2 * Segmented Ring Buffer
3 *
4 * Copyright (C) 2015 Ettus Research LLC
5 *
6 * Author: Tom Tsou <tom@tsou.cc>
7 *
Pau Espin Pedrol21d03d32019-07-22 12:05:52 +02008 * SPDX-License-Identifier: AGPL-3.0+
9 *
Tom Tsou28670fb2015-08-21 19:32:58 -070010 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * See the COPYING file in the main directory for details.
23 */
24
25#include <string.h>
26#include <iostream>
27#include "radioBuffer.h"
28
29RadioBuffer::RadioBuffer(size_t numSegments, size_t segmentLen,
30 size_t hLen, bool outDirection)
Eric5561f112022-07-19 21:18:21 +020031 : writeIndex(0), readIndex(0), availSamples(0), segments(numSegments)
Tom Tsou28670fb2015-08-21 19:32:58 -070032{
33 if (!outDirection)
34 hLen = 0;
35
36 buffer = new float[2 * (hLen + numSegments * segmentLen)];
37 bufferLen = numSegments * segmentLen;
38
Tom Tsou28670fb2015-08-21 19:32:58 -070039
40 for (size_t i = 0; i < numSegments; i++)
41 segments[i] = &buffer[2 * (hLen + i * segmentLen)];
42
43 this->outDirection = outDirection;
44 this->numSegments = numSegments;
45 this->segmentLen = segmentLen;
46 this->hLen = hLen;
47}
48
49RadioBuffer::~RadioBuffer()
50{
pierre.baudry9436fbb2016-10-20 16:30:51 +020051 delete[] buffer;
Tom Tsou28670fb2015-08-21 19:32:58 -070052}
53
54void RadioBuffer::reset()
55{
56 writeIndex = 0;
57 readIndex = 0;
58 availSamples = 0;
59}
60
61/*
62 * Output direction
63 *
64 * Return a pointer to the oldest segment or NULL if a complete segment is not
65 * available.
66 */
67const float *RadioBuffer::getReadSegment()
68{
69 if (!outDirection) {
70 std::cout << "Invalid direction" << std::endl;
71 return NULL;
72 }
73 if (availSamples < segmentLen) {
74 std::cout << "Not enough samples " << std::endl;
75 std::cout << availSamples << " available per segment "
76 << segmentLen << std::endl;
77 return NULL;
78 }
79
80 size_t num = readIndex / segmentLen;
81
82 if (num >= numSegments) {
83 std::cout << "Invalid segment" << std::endl;
84 return NULL;
85 } else if (!num) {
86 memcpy(buffer,
87 &buffer[2 * bufferLen],
88 hLen * 2 * sizeof(float));
89 }
90
91 availSamples -= segmentLen;
92 readIndex = (readIndex + segmentLen) % bufferLen;
93
94 return segments[num];
95}
96
97/*
98 * Output direction
99 *
Pau Espin Pedrolbdb970e2019-07-22 12:03:39 +0200100 * Write a non-segment length of samples to the buffer.
Tom Tsou28670fb2015-08-21 19:32:58 -0700101 */
102bool RadioBuffer::write(const float *wr, size_t len)
103{
104 if (!outDirection) {
105 std::cout << "Invalid direction" << std::endl;
106 return false;
107 }
108 if (availSamples + len > bufferLen) {
109 std::cout << "Insufficient space" << std::endl;
110 std::cout << bufferLen - availSamples << " available per write "
111 << len << std::endl;
112 return false;
113 }
114
115 if (writeIndex + len <= bufferLen) {
116 memcpy(&buffer[2 * (writeIndex + hLen)],
117 wr, len * 2 * sizeof(float));
118 } else {
119 size_t len0 = bufferLen - writeIndex;
120 size_t len1 = len - len0;
121 memcpy(&buffer[2 * (writeIndex + hLen)], wr, len0 * 2 * sizeof(float));
122 memcpy(&buffer[2 * hLen], &wr[2 * len0], len1 * 2 * sizeof(float));
123 }
124
125 availSamples += len;
126 writeIndex = (writeIndex + len) % bufferLen;
127
128 return true;
129}
130
131bool RadioBuffer::zero(size_t len)
132{
133 if (!outDirection) {
134 std::cout << "Invalid direction" << std::endl;
135 return false;
136 }
137 if (availSamples + len > bufferLen) {
138 std::cout << "Insufficient space" << std::endl;
139 std::cout << bufferLen - availSamples << " available per zero "
140 << len << std::endl;
141 return false;
142 }
143
144 if (writeIndex + len <= bufferLen) {
145 memset(&buffer[2 * (writeIndex + hLen)],
146 0, len * 2 * sizeof(float));
147 } else {
148 size_t len0 = bufferLen - writeIndex;
149 size_t len1 = len - len0;
150 memset(&buffer[2 * (writeIndex + hLen)], 0, len0 * 2 * sizeof(float));
151 memset(&buffer[2 * hLen], 0, len1 * 2 * sizeof(float));
152 }
153
154 availSamples += len;
155 writeIndex = (writeIndex + len) % bufferLen;
156
157 return true;
158}
159
160/*
161 * Input direction
162 */
163float *RadioBuffer::getWriteSegment()
164{
165 if (outDirection) {
166 std::cout << "Invalid direction" << std::endl;
167 return NULL;
168 }
169 if (bufferLen - availSamples < segmentLen) {
170 std::cout << "Insufficient samples" << std::endl;
171 std::cout << bufferLen - availSamples
172 << " available for segment " << segmentLen
173 << std::endl;
174 return NULL;
175 }
176 if (writeIndex % segmentLen) {
177 std::cout << "Internal segment error" << std::endl;
178 return NULL;
179 }
180
181 size_t num = writeIndex / segmentLen;
182
183 if (num >= numSegments)
184 return NULL;
185
186 availSamples += segmentLen;
187 writeIndex = (writeIndex + segmentLen) % bufferLen;
188
189 return segments[num];
190}
191
192bool RadioBuffer::zeroWriteSegment()
193{
194 float *segment = getWriteSegment();
195 if (!segment)
196 return false;
197
198 memset(segment, 0, segmentLen * 2 * sizeof(float));
199
200 return true;
201}
202
203bool RadioBuffer::read(float *rd, size_t len)
204{
205 if (outDirection) {
206 std::cout << "Invalid direction" << std::endl;
207 return false;
208 }
209 if (availSamples < len) {
210 std::cout << "Insufficient samples" << std::endl;
211 std::cout << availSamples << " available for "
212 << len << std::endl;
213 return false;
214 }
215
216 if (readIndex + len <= bufferLen) {
217 memcpy(rd, &buffer[2 * readIndex], len * 2 * sizeof(float));
218 } else {
219 size_t len0 = bufferLen - readIndex;
220 size_t len1 = len - len0;
221 memcpy(rd, &buffer[2 * readIndex], len0 * 2 * sizeof(float));
222 memcpy(&rd[2 * len0], buffer, len1 * 2 * sizeof(float));
223 }
224
225 availSamples -= len;
226 readIndex = (readIndex + len) % bufferLen;
227
228 return true;
229}