blob: c21f306a23a4d97e6ee79321d1374987f978790e [file] [log] [blame]
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +02001/*
2 * Sample Buffer - Allows reading and writing of timed samples
3 *
4 * Copyright 2010,2011 Free Software Foundation, Inc.
5 * Copyright (C) 2015 Ettus Research LLC
6 * Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
7 *
8 * Author: Tom Tsou <tom.tsou@ettus.com>
9 *
10 * 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 "smpl_buf.h"
26#include <inttypes.h>
27
Pau Espin Pedrol580c48b2019-05-03 14:38:36 +020028smpl_buf::smpl_buf(size_t len)
29 : buf_len(len), time_start(0), time_end(0),
30 data_start(0), data_end(0)
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020031{
32 data = new uint32_t[len];
33}
34
35smpl_buf::~smpl_buf()
36{
37 delete[] data;
38}
39
40ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
41{
42 if (timestamp < time_start)
43 return ERROR_TIMESTAMP;
44 else if (timestamp >= time_end)
45 return 0;
46 else
47 return time_end - timestamp;
48}
49
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020050ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
51{
52 int type_sz = 2 * sizeof(short);
53
54 // Check for valid read
55 if (timestamp < time_start)
56 return ERROR_TIMESTAMP;
57 if (timestamp >= time_end)
58 return 0;
59 if (len >= buf_len)
60 return ERROR_READ;
61
62 // How many samples should be copied
63 size_t num_smpls = time_end - timestamp;
64 if (num_smpls > len)
65 num_smpls = len;
66
67 // Starting index
68 size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
69
70 // Read it
71 if (read_start + num_smpls < buf_len) {
72 size_t numBytes = len * type_sz;
73 memcpy(buf, data + read_start, numBytes);
74 } else {
75 size_t first_cp = (buf_len - read_start) * type_sz;
76 size_t second_cp = len * type_sz - first_cp;
77
78 memcpy(buf, data + read_start, first_cp);
79 memcpy((char*) buf + first_cp, data, second_cp);
80 }
81
82 data_start = (read_start + len) % buf_len;
83 time_start = timestamp + len;
84
85 if (time_start > time_end)
86 return ERROR_READ;
87 else
88 return num_smpls;
89}
90
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020091ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
92{
93 int type_sz = 2 * sizeof(short);
94
95 // Check for valid write
96 if ((len == 0) || (len >= buf_len))
97 return ERROR_WRITE;
98 if ((timestamp + len) <= time_end)
99 return ERROR_TIMESTAMP;
100
101 if (timestamp < time_end) {
Pau Espin Pedrola7919262019-05-03 19:13:52 +0200102 LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="
103 << timestamp << " time_end=" << time_end;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200104 // Do not return error here, because it's a rounding error and is not fatal
105 }
106 if (timestamp > time_end && time_end != 0) {
Pau Espin Pedrola7919262019-05-03 19:13:52 +0200107 LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="
108 << timestamp << " time_end=" << time_end;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200109 // Do not return error here, because it's a rounding error and is not fatal
110 }
111
112 // Starting index
113 size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
114
115 // Write it
116 if ((write_start + len) < buf_len) {
117 size_t numBytes = len * type_sz;
118 memcpy(data + write_start, buf, numBytes);
119 } else {
120 size_t first_cp = (buf_len - write_start) * type_sz;
121 size_t second_cp = len * type_sz - first_cp;
122
123 memcpy(data + write_start, buf, first_cp);
124 memcpy(data, (char*) buf + first_cp, second_cp);
125 }
126
127 data_end = (write_start + len) % buf_len;
128 time_end = timestamp + len;
129
130 if (!data_start)
131 data_start = write_start;
132
133 if (((write_start + len) > buf_len) && (data_end > data_start))
134 return ERROR_OVERFLOW;
135 else if (time_end <= time_start)
136 return ERROR_WRITE;
137 else
138 return len;
139}
140
Pau Espin Pedrol3e9179a2019-04-30 18:13:23 +0200141std::string smpl_buf::str_status(TIMESTAMP timestamp) const
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200142{
143 std::ostringstream ost("Sample buffer: ");
144
Pau Espin Pedrol3e9179a2019-04-30 18:13:23 +0200145 ost << "timestamp = " << timestamp;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200146 ost << ", length = " << buf_len;
147 ost << ", time_start = " << time_start;
148 ost << ", time_end = " << time_end;
149 ost << ", data_start = " << data_start;
150 ost << ", data_end = " << data_end;
151
152 return ost.str();
153}
154
155std::string smpl_buf::str_code(ssize_t code)
156{
157 switch (code) {
158 case ERROR_TIMESTAMP:
159 return "Sample buffer: Requested timestamp is not valid";
160 case ERROR_READ:
161 return "Sample buffer: Read error";
162 case ERROR_WRITE:
163 return "Sample buffer: Write error";
164 case ERROR_OVERFLOW:
165 return "Sample buffer: Overrun";
166 default:
167 return "Sample buffer: Unknown error";
168 }
169}