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