blob: 62f6553f3129acba76c19c72fe64a21d133f05b2 [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)
31 : writeIndex(0), readIndex(0), availSamples(0)
32{
33 if (!outDirection)
34 hLen = 0;
35
36 buffer = new float[2 * (hLen + numSegments * segmentLen)];
37 bufferLen = numSegments * segmentLen;
38
39 segments.resize(numSegments);
40
41 for (size_t i = 0; i < numSegments; i++)
42 segments[i] = &buffer[2 * (hLen + i * segmentLen)];
43
44 this->outDirection = outDirection;
45 this->numSegments = numSegments;
46 this->segmentLen = segmentLen;
47 this->hLen = hLen;
48}
49
50RadioBuffer::~RadioBuffer()
51{
pierre.baudry9436fbb2016-10-20 16:30:51 +020052 delete[] buffer;
Tom Tsou28670fb2015-08-21 19:32:58 -070053}
54
55void RadioBuffer::reset()
56{
57 writeIndex = 0;
58 readIndex = 0;
59 availSamples = 0;
60}
61
62/*
63 * Output direction
64 *
65 * Return a pointer to the oldest segment or NULL if a complete segment is not
66 * available.
67 */
68const float *RadioBuffer::getReadSegment()
69{
70 if (!outDirection) {
71 std::cout << "Invalid direction" << std::endl;
72 return NULL;
73 }
74 if (availSamples < segmentLen) {
75 std::cout << "Not enough samples " << std::endl;
76 std::cout << availSamples << " available per segment "
77 << segmentLen << std::endl;
78 return NULL;
79 }
80
81 size_t num = readIndex / segmentLen;
82
83 if (num >= numSegments) {
84 std::cout << "Invalid segment" << std::endl;
85 return NULL;
86 } else if (!num) {
87 memcpy(buffer,
88 &buffer[2 * bufferLen],
89 hLen * 2 * sizeof(float));
90 }
91
92 availSamples -= segmentLen;
93 readIndex = (readIndex + segmentLen) % bufferLen;
94
95 return segments[num];
96}
97
98/*
99 * Output direction
100 *
Pau Espin Pedrolbdb970e2019-07-22 12:03:39 +0200101 * Write a non-segment length of samples to the buffer.
Tom Tsou28670fb2015-08-21 19:32:58 -0700102 */
103bool RadioBuffer::write(const float *wr, size_t len)
104{
105 if (!outDirection) {
106 std::cout << "Invalid direction" << std::endl;
107 return false;
108 }
109 if (availSamples + len > bufferLen) {
110 std::cout << "Insufficient space" << std::endl;
111 std::cout << bufferLen - availSamples << " available per write "
112 << len << std::endl;
113 return false;
114 }
115
116 if (writeIndex + len <= bufferLen) {
117 memcpy(&buffer[2 * (writeIndex + hLen)],
118 wr, len * 2 * sizeof(float));
119 } else {
120 size_t len0 = bufferLen - writeIndex;
121 size_t len1 = len - len0;
122 memcpy(&buffer[2 * (writeIndex + hLen)], wr, len0 * 2 * sizeof(float));
123 memcpy(&buffer[2 * hLen], &wr[2 * len0], len1 * 2 * sizeof(float));
124 }
125
126 availSamples += len;
127 writeIndex = (writeIndex + len) % bufferLen;
128
129 return true;
130}
131
132bool RadioBuffer::zero(size_t len)
133{
134 if (!outDirection) {
135 std::cout << "Invalid direction" << std::endl;
136 return false;
137 }
138 if (availSamples + len > bufferLen) {
139 std::cout << "Insufficient space" << std::endl;
140 std::cout << bufferLen - availSamples << " available per zero "
141 << len << std::endl;
142 return false;
143 }
144
145 if (writeIndex + len <= bufferLen) {
146 memset(&buffer[2 * (writeIndex + hLen)],
147 0, len * 2 * sizeof(float));
148 } else {
149 size_t len0 = bufferLen - writeIndex;
150 size_t len1 = len - len0;
151 memset(&buffer[2 * (writeIndex + hLen)], 0, len0 * 2 * sizeof(float));
152 memset(&buffer[2 * hLen], 0, len1 * 2 * sizeof(float));
153 }
154
155 availSamples += len;
156 writeIndex = (writeIndex + len) % bufferLen;
157
158 return true;
159}
160
161/*
162 * Input direction
163 */
164float *RadioBuffer::getWriteSegment()
165{
166 if (outDirection) {
167 std::cout << "Invalid direction" << std::endl;
168 return NULL;
169 }
170 if (bufferLen - availSamples < segmentLen) {
171 std::cout << "Insufficient samples" << std::endl;
172 std::cout << bufferLen - availSamples
173 << " available for segment " << segmentLen
174 << std::endl;
175 return NULL;
176 }
177 if (writeIndex % segmentLen) {
178 std::cout << "Internal segment error" << std::endl;
179 return NULL;
180 }
181
182 size_t num = writeIndex / segmentLen;
183
184 if (num >= numSegments)
185 return NULL;
186
187 availSamples += segmentLen;
188 writeIndex = (writeIndex + segmentLen) % bufferLen;
189
190 return segments[num];
191}
192
193bool RadioBuffer::zeroWriteSegment()
194{
195 float *segment = getWriteSegment();
196 if (!segment)
197 return false;
198
199 memset(segment, 0, segmentLen * 2 * sizeof(float));
200
201 return true;
202}
203
204bool RadioBuffer::read(float *rd, size_t len)
205{
206 if (outDirection) {
207 std::cout << "Invalid direction" << std::endl;
208 return false;
209 }
210 if (availSamples < len) {
211 std::cout << "Insufficient samples" << std::endl;
212 std::cout << availSamples << " available for "
213 << len << std::endl;
214 return false;
215 }
216
217 if (readIndex + len <= bufferLen) {
218 memcpy(rd, &buffer[2 * readIndex], len * 2 * sizeof(float));
219 } else {
220 size_t len0 = bufferLen - readIndex;
221 size_t len1 = len - len0;
222 memcpy(rd, &buffer[2 * readIndex], len0 * 2 * sizeof(float));
223 memcpy(&rd[2 * len0], buffer, len1 * 2 * sizeof(float));
224 }
225
226 availSamples -= len;
227 readIndex = (readIndex + len) % bufferLen;
228
229 return true;
230}