182 lines
4.6 KiB
C++
182 lines
4.6 KiB
C++
/*
|
|
* Sample Buffer - Allows reading and writing of timed samples
|
|
*
|
|
* Copyright 2010,2011 Free Software Foundation, Inc.
|
|
* Copyright (C) 2015 Ettus Research LLC
|
|
* Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
|
*
|
|
* Author: Tom Tsou <tom.tsou@ettus.com>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0+
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
* See the COPYING file in the main directory for details.
|
|
*/
|
|
|
|
#include "smpl_buf.h"
|
|
#include <inttypes.h>
|
|
|
|
smpl_buf::smpl_buf(size_t len)
|
|
: buf_len(len)
|
|
{
|
|
reset();
|
|
data = new uint32_t[len];
|
|
}
|
|
|
|
smpl_buf::~smpl_buf()
|
|
{
|
|
delete[] data;
|
|
}
|
|
|
|
void smpl_buf::reset()
|
|
{
|
|
time_start = 0;
|
|
time_end = 0;
|
|
data_start = 0;
|
|
data_end = 0;
|
|
}
|
|
|
|
ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
|
|
{
|
|
if (timestamp < time_start)
|
|
return ERROR_TIMESTAMP;
|
|
else if (timestamp >= time_end)
|
|
return 0;
|
|
else
|
|
return time_end - timestamp;
|
|
}
|
|
|
|
ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
|
|
{
|
|
int type_sz = 2 * sizeof(short);
|
|
|
|
// Check for valid read
|
|
if (timestamp < time_start)
|
|
return ERROR_TIMESTAMP;
|
|
if (timestamp >= time_end)
|
|
return 0;
|
|
if (len >= buf_len)
|
|
return ERROR_READ;
|
|
|
|
// How many samples should be copied
|
|
size_t num_smpls = time_end - timestamp;
|
|
if (num_smpls > len)
|
|
num_smpls = len;
|
|
|
|
// Starting index
|
|
size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
|
|
|
|
// Read it
|
|
if (read_start + num_smpls < buf_len) {
|
|
size_t numBytes = len * type_sz;
|
|
memcpy(buf, data + read_start, numBytes);
|
|
} else {
|
|
size_t first_cp = (buf_len - read_start) * type_sz;
|
|
size_t second_cp = len * type_sz - first_cp;
|
|
|
|
memcpy(buf, data + read_start, first_cp);
|
|
memcpy((char*) buf + first_cp, data, second_cp);
|
|
}
|
|
|
|
data_start = (read_start + len) % buf_len;
|
|
time_start = timestamp + len;
|
|
|
|
if (time_start > time_end)
|
|
return ERROR_READ;
|
|
else
|
|
return num_smpls;
|
|
}
|
|
|
|
ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
|
|
{
|
|
int type_sz = 2 * sizeof(short);
|
|
|
|
// Check for valid write
|
|
if ((len == 0) || (len >= buf_len))
|
|
return ERROR_WRITE;
|
|
if ((timestamp + len) <= time_end)
|
|
return ERROR_TIMESTAMP;
|
|
|
|
if (timestamp < time_end) {
|
|
LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="
|
|
<< timestamp << " time_end=" << time_end;
|
|
// Do not return error here, because it's a rounding error and is not fatal
|
|
}
|
|
if (timestamp > time_end && time_end != 0) {
|
|
LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="
|
|
<< timestamp << " time_end=" << time_end;
|
|
// Do not return error here, because it's a rounding error and is not fatal
|
|
}
|
|
|
|
// Starting index
|
|
size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
|
|
|
|
// Write it
|
|
if ((write_start + len) < buf_len) {
|
|
size_t numBytes = len * type_sz;
|
|
memcpy(data + write_start, buf, numBytes);
|
|
} else {
|
|
size_t first_cp = (buf_len - write_start) * type_sz;
|
|
size_t second_cp = len * type_sz - first_cp;
|
|
|
|
memcpy(data + write_start, buf, first_cp);
|
|
memcpy(data, (char*) buf + first_cp, second_cp);
|
|
}
|
|
|
|
data_end = (write_start + len) % buf_len;
|
|
time_end = timestamp + len;
|
|
|
|
if (!data_start)
|
|
data_start = write_start;
|
|
|
|
if (((write_start + len) > buf_len) && (data_end > data_start))
|
|
return ERROR_OVERFLOW;
|
|
else if (time_end <= time_start)
|
|
return ERROR_WRITE;
|
|
else
|
|
return len;
|
|
}
|
|
|
|
std::string smpl_buf::str_status(TIMESTAMP timestamp) const
|
|
{
|
|
std::ostringstream ost("Sample buffer: ");
|
|
|
|
ost << "timestamp = " << timestamp;
|
|
ost << ", length = " << buf_len;
|
|
ost << ", time_start = " << time_start;
|
|
ost << ", time_end = " << time_end;
|
|
ost << ", data_start = " << data_start;
|
|
ost << ", data_end = " << data_end;
|
|
|
|
return ost.str();
|
|
}
|
|
|
|
std::string smpl_buf::str_code(int code)
|
|
{
|
|
switch (code) {
|
|
case ERROR_TIMESTAMP:
|
|
return "Sample buffer: Requested timestamp is not valid";
|
|
case ERROR_READ:
|
|
return "Sample buffer: Read error";
|
|
case ERROR_WRITE:
|
|
return "Sample buffer: Write error";
|
|
case ERROR_OVERFLOW:
|
|
return "Sample buffer: Overrun";
|
|
default:
|
|
std::stringstream ss;
|
|
ss << "Sample buffer: Unknown error " << code;
|
|
return ss.str();
|
|
}
|
|
}
|