blob: 33161bcc697a74dd3033695955c15c3c340550fb [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 *
Pau Espin Pedrol21d03d32019-07-22 12:05:52 +020010 * SPDX-License-Identifier: AGPL-3.0+
11 *
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020012 * This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Affero General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * See the COPYING file in the main directory for details.
25 */
26
27#include "smpl_buf.h"
28#include <inttypes.h>
29
Pau Espin Pedrol580c48b2019-05-03 14:38:36 +020030smpl_buf::smpl_buf(size_t len)
31 : buf_len(len), time_start(0), time_end(0),
32 data_start(0), data_end(0)
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020033{
34 data = new uint32_t[len];
35}
36
37smpl_buf::~smpl_buf()
38{
39 delete[] data;
40}
41
42ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
43{
44 if (timestamp < time_start)
45 return ERROR_TIMESTAMP;
46 else if (timestamp >= time_end)
47 return 0;
48 else
49 return time_end - timestamp;
50}
51
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020052ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
53{
54 int type_sz = 2 * sizeof(short);
55
56 // Check for valid read
57 if (timestamp < time_start)
58 return ERROR_TIMESTAMP;
59 if (timestamp >= time_end)
60 return 0;
61 if (len >= buf_len)
62 return ERROR_READ;
63
64 // How many samples should be copied
65 size_t num_smpls = time_end - timestamp;
66 if (num_smpls > len)
67 num_smpls = len;
68
69 // Starting index
70 size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
71
72 // Read it
73 if (read_start + num_smpls < buf_len) {
74 size_t numBytes = len * type_sz;
75 memcpy(buf, data + read_start, numBytes);
76 } else {
77 size_t first_cp = (buf_len - read_start) * type_sz;
78 size_t second_cp = len * type_sz - first_cp;
79
80 memcpy(buf, data + read_start, first_cp);
81 memcpy((char*) buf + first_cp, data, second_cp);
82 }
83
84 data_start = (read_start + len) % buf_len;
85 time_start = timestamp + len;
86
87 if (time_start > time_end)
88 return ERROR_READ;
89 else
90 return num_smpls;
91}
92
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +020093ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
94{
95 int type_sz = 2 * sizeof(short);
96
97 // Check for valid write
98 if ((len == 0) || (len >= buf_len))
99 return ERROR_WRITE;
100 if ((timestamp + len) <= time_end)
101 return ERROR_TIMESTAMP;
102
103 if (timestamp < time_end) {
Pau Espin Pedrola7919262019-05-03 19:13:52 +0200104 LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="
105 << timestamp << " time_end=" << time_end;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200106 // Do not return error here, because it's a rounding error and is not fatal
107 }
108 if (timestamp > time_end && time_end != 0) {
Pau Espin Pedrola7919262019-05-03 19:13:52 +0200109 LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="
110 << timestamp << " time_end=" << time_end;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200111 // Do not return error here, because it's a rounding error and is not fatal
112 }
113
114 // Starting index
115 size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
116
117 // Write it
118 if ((write_start + len) < buf_len) {
119 size_t numBytes = len * type_sz;
120 memcpy(data + write_start, buf, numBytes);
121 } else {
122 size_t first_cp = (buf_len - write_start) * type_sz;
123 size_t second_cp = len * type_sz - first_cp;
124
125 memcpy(data + write_start, buf, first_cp);
126 memcpy(data, (char*) buf + first_cp, second_cp);
127 }
128
129 data_end = (write_start + len) % buf_len;
130 time_end = timestamp + len;
131
132 if (!data_start)
133 data_start = write_start;
134
135 if (((write_start + len) > buf_len) && (data_end > data_start))
136 return ERROR_OVERFLOW;
137 else if (time_end <= time_start)
138 return ERROR_WRITE;
139 else
140 return len;
141}
142
Pau Espin Pedrol3e9179a2019-04-30 18:13:23 +0200143std::string smpl_buf::str_status(TIMESTAMP timestamp) const
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200144{
145 std::ostringstream ost("Sample buffer: ");
146
Pau Espin Pedrol3e9179a2019-04-30 18:13:23 +0200147 ost << "timestamp = " << timestamp;
Pau Espin Pedrol7bef2342019-04-29 17:23:21 +0200148 ost << ", length = " << buf_len;
149 ost << ", time_start = " << time_start;
150 ost << ", time_end = " << time_end;
151 ost << ", data_start = " << data_start;
152 ost << ", data_end = " << data_end;
153
154 return ost.str();
155}
156
157std::string smpl_buf::str_code(ssize_t code)
158{
159 switch (code) {
160 case ERROR_TIMESTAMP:
161 return "Sample buffer: Requested timestamp is not valid";
162 case ERROR_READ:
163 return "Sample buffer: Read error";
164 case ERROR_WRITE:
165 return "Sample buffer: Write error";
166 case ERROR_OVERFLOW:
167 return "Sample buffer: Overrun";
168 default:
169 return "Sample buffer: Unknown error";
170 }
171}