blob: d8bdbc48083b1cd3acc7c1a85d668700f4ab9179 [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
28smpl_buf::smpl_buf(size_t len, double rate)
29 : buf_len(len), clk_rt(rate),
30 time_start(0), time_end(0), data_start(0), data_end(0)
31{
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
50ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
51{
52 return avail_smpls(timespec.to_ticks(clk_rt));
53}
54
55ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
56{
57 int type_sz = 2 * sizeof(short);
58
59 // Check for valid read
60 if (timestamp < time_start)
61 return ERROR_TIMESTAMP;
62 if (timestamp >= time_end)
63 return 0;
64 if (len >= buf_len)
65 return ERROR_READ;
66
67 // How many samples should be copied
68 size_t num_smpls = time_end - timestamp;
69 if (num_smpls > len)
70 num_smpls = len;
71
72 // Starting index
73 size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
74
75 // Read it
76 if (read_start + num_smpls < buf_len) {
77 size_t numBytes = len * type_sz;
78 memcpy(buf, data + read_start, numBytes);
79 } else {
80 size_t first_cp = (buf_len - read_start) * type_sz;
81 size_t second_cp = len * type_sz - first_cp;
82
83 memcpy(buf, data + read_start, first_cp);
84 memcpy((char*) buf + first_cp, data, second_cp);
85 }
86
87 data_start = (read_start + len) % buf_len;
88 time_start = timestamp + len;
89
90 if (time_start > time_end)
91 return ERROR_READ;
92 else
93 return num_smpls;
94}
95
96ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
97{
98 return read(buf, len, ts.to_ticks(clk_rt));
99}
100
101ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
102{
103 int type_sz = 2 * sizeof(short);
104
105 // Check for valid write
106 if ((len == 0) || (len >= buf_len))
107 return ERROR_WRITE;
108 if ((timestamp + len) <= time_end)
109 return ERROR_TIMESTAMP;
110
111 if (timestamp < time_end) {
112 LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
113 uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, clk_rt);
114 LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) << ") rate=" << clk_rt;
115 // Do not return error here, because it's a rounding error and is not fatal
116 }
117 if (timestamp > time_end && time_end != 0) {
118 LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="<<timestamp<<" time_end="<<time_end;
119 uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, clk_rt);
120 LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " (real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) << ") rate=" << clk_rt;
121 // Do not return error here, because it's a rounding error and is not fatal
122 }
123
124 // Starting index
125 size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
126
127 // Write it
128 if ((write_start + len) < buf_len) {
129 size_t numBytes = len * type_sz;
130 memcpy(data + write_start, buf, numBytes);
131 } else {
132 size_t first_cp = (buf_len - write_start) * type_sz;
133 size_t second_cp = len * type_sz - first_cp;
134
135 memcpy(data + write_start, buf, first_cp);
136 memcpy(data, (char*) buf + first_cp, second_cp);
137 }
138
139 data_end = (write_start + len) % buf_len;
140 time_end = timestamp + len;
141
142 if (!data_start)
143 data_start = write_start;
144
145 if (((write_start + len) > buf_len) && (data_end > data_start))
146 return ERROR_OVERFLOW;
147 else if (time_end <= time_start)
148 return ERROR_WRITE;
149 else
150 return len;
151}
152
153ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
154{
155 return write(buf, len, ts.to_ticks(clk_rt));
156}
157
158std::string smpl_buf::str_status(size_t ts) const
159{
160 std::ostringstream ost("Sample buffer: ");
161
162 ost << "timestamp = " << ts;
163 ost << ", length = " << buf_len;
164 ost << ", time_start = " << time_start;
165 ost << ", time_end = " << time_end;
166 ost << ", data_start = " << data_start;
167 ost << ", data_end = " << data_end;
168
169 return ost.str();
170}
171
172std::string smpl_buf::str_code(ssize_t code)
173{
174 switch (code) {
175 case ERROR_TIMESTAMP:
176 return "Sample buffer: Requested timestamp is not valid";
177 case ERROR_READ:
178 return "Sample buffer: Read error";
179 case ERROR_WRITE:
180 return "Sample buffer: Write error";
181 case ERROR_OVERFLOW:
182 return "Sample buffer: Overrun";
183 default:
184 return "Sample buffer: Unknown error";
185 }
186}