lasp/src/lasp/device/lasp_daqdata.h

204 lines
5.4 KiB
C++

#pragma once
#include "lasp_daqconfig.h"
#include "lasp_types.h"
#include <armadillo>
#include <cassert>
#include <functional>
#include <gsl/gsl-lite.hpp>
#include <memory>
#include <type_traits>
/** \addtogroup device
* @{
*/
class Daq;
using byte_t = char;
/**
* @brief Data coming from / going to DAQ. **Non-interleaved format**, which
* means data in buffer is ordered by channel: _ptr[frame+channel*nframes]
*/
class DaqData {
protected:
/**
* @brief Storage for the actual data.
*/
byte_t *_data;
public:
/**
* @brief The number of frames in this block of data.
*/
us nframes;
/**
* @brief The number of channels
*/
us nchannels;
/**
* @brief The data type corresponding to a sample
*/
DataTypeDescriptor::DataType dtype;
/**
* @brief The data type description corresponding to a sample
*/
DataTypeDescriptor dtype_descr;
/**
* @brief The number of bytes per sample (sample width, sw)
*/
us sw;
/**
* @brief Initialize an empty frame of data
*
* @param nframes The number of frames
* @param nchannels The number of channels
* @param dtype The data type
*/
DaqData(const us nframes, const us nchannels,
const DataTypeDescriptor::DataType dtype);
/**
* @brief Initialize using no allocation
*/
DaqData(const DaqData &);
/* DaqData(DaqData &&); */
DaqData &operator=(const DaqData &) = delete;
virtual ~DaqData();
/**
* @brief Return pointer to the raw data corresponding to a certain sample
* (frame, channel combo).
*
* @param frame The frame number
* @param channel The channel number
*
* @return Pointer to sample, not casted to final type
*/
byte_t *raw_ptr(const us frame = 0, const us channel = 0) {
assert(frame < nframes);
assert(channel < nchannels);
return &(_data[sw * (frame + channel * nframes)]);
}
const byte_t *raw_ptr(const us frame = 0, const us channel = 0) const {
assert(frame < nframes);
assert(channel < nchannels);
return &(_data[sw * (frame + channel * nframes)]);
}
/**
* @brief Return the total number of bytes
*
* @return Number of bytes of data.
*/
us size_bytes() const { return sw * nchannels * nframes; }
/**
* @brief Copy data from a set of raw pointers of *uninterleaved* data.
* Overwrites any existing available data.
*
* @param ptrs Pointers to data from channels
*/
void copyInFromRaw(const std::vector<byte_t *> &ptrs);
/**
* @brief Copy contents of DaqData for a certain channel to a raw pointer.
*
* @param channel The channel to copy.
* @param ptr The pointer where data is copied to.
*/
void copyToRaw(const us channel, byte_t *ptr);
/**
* @brief Convert samples to floating point values and return a nframes x
* nchannels array of floats. For data that is not already floating-point,
* the data is scaled back from MAX_INT to +1.0.
*
* @return Array of floats
*/
arma::Mat<d> toFloat() const;
/**
* @brief Convert samples to floating point value; and return a nframes
* column vector of floats. For data that is not already floating-point,
* the data is scaled back from MAX_INT to +1.0.
*
* @param channel The channel to convert
*
* @return Array of floats
*/
arma::Col<d> toFloat(const us channel_no) const;
/**
* @brief Convert single sample to floating point value; and return a nframes
* column vector of floats. For data that is not already floating-point,
* the data is scaled back from MAX_INT to +1.0.
*
* @param channel The channel to convert
* @param frame_no The frame number to convert
*
* @return Float value
*/
d toFloat(const us frame_no, const us channel_no) const;
// Return value based on type
template <typename T> T &value(const us frame, const us channel) {
#if LASP_DEBUG == 1
check_type<T>();
#endif
return *reinterpret_cast<T *>(raw_ptr(frame, channel));
}
template <typename T> const T &value(const us frame, const us channel) const {
#if LASP_DEBUG == 1
check_type<T>();
#endif
return *reinterpret_cast<const T *>(raw_ptr(frame, channel));
}
/**
* @brief For debugging purposes: prints some stats
*/
void print() const;
protected:
template <typename T> void check_type() const {
using DataType = DataTypeDescriptor::DataType;
bool correct = false;
static_assert(std::is_arithmetic<T>::value);
if constexpr (std::is_floating_point<T>::value) {
correct |= sizeof(T) == 4 && dtype == DataType::dtype_fl32;
correct |= sizeof(T) == 8 && dtype == DataType::dtype_fl64;
} else {
correct |= sizeof(T) == 1 && dtype == DataType::dtype_int8;
correct |= sizeof(T) == 2 && dtype == DataType::dtype_int16;
correct |= sizeof(T) == 4 && dtype == DataType::dtype_int32;
}
if (!correct) {
throw std::runtime_error("Wrong datatype for template argument");
}
}
template <typename T> arma::Mat<d> toFloat() const;
template <typename T> arma::Col<d> toFloat(const us channel_no) const;
template <typename T> d toFloat(const us frame_no, const us channel_no) const;
/**
* @brief Return a value as floating point. Does a conversion from integer to
* float, if the stored type is integer. Also scales by its maximum value.
*
* @tparam T The original type
* @param frame Frame number
* @param channel Channel number
*
* @return Value converted to floating point
*/
};
/** @} */