#pragma once #include "lasp_config.h" #include "lasp_daqdata.h" #include "lasp_deviceinfo.h" #include "lasp_types.h" #include #include /** * \defgroup device Device interfacing * \addtogroup device * @{ * @brief Callback of DAQ for input data. Callback should return * false for a stop request. */ using InDaqCallback = std::function; /** * @brief */ using OutDaqCallback = std::function; /** * @brief Base cass for all DAQ (Data Acquisition) interfaces. A DAQ can be a * custom device, or for example a sound card. */ class Daq : public DaqConfiguration, public DeviceInfo { protected: Daq(const DeviceInfo &devinfo, const DaqConfiguration &config); Daq(const Daq &) = delete; public: /** * @brief Information regarding a stream. */ class StreamStatus { public: enum class StreamError { noError, inputXRun, outputXRun, driverError, systemError, threadError, logicError, apiSpecificError }; /** * @brief Map between error types and messages */ inline static const std::map errorMessages{ {StreamError::noError, "No error"}, {StreamError::inputXRun, "Input buffer overrun"}, {StreamError::outputXRun, "Output buffer underrun"}, {StreamError::driverError, "Driver error"}, {StreamError::systemError, "System error"}, {StreamError::threadError, "Thread error"}, {StreamError::logicError, "Logic error (probably a bug)"}, }; bool isRunning = false; /** * @brief Check if stream has error * * @return true if there is an error. */ bool error() const { return errorType != StreamError::noError; }; StreamError errorType{StreamError::noError}; std::string errorMsg() const { return errorMessages.at(errorType); } /** * @brief Returns true if everything is OK with a certain stream and the * stream is running. * * @return as described above. */ bool runningOK() const { return isRunning && !error(); } }; /** * @brief Create a Daq based on given device info and configuration * * @param devinfo Device information of device to be used. * @param config Configuation to apply to the deviec * * @return Pointer to Daq device created. */ static std::unique_ptr createDaq(const DeviceInfo &devinfo, const DaqConfiguration &config); /** * @brief Start the Daq. * * @param inCallback Function that is called with input data as argument, * and which expects output data as a return value. If no input data is * required, this callback should be unset. * @param outCallback Function that is called when output data is required. * If the stream does not require output data, this callback should be unset. */ virtual void start(InDaqCallback inCallback, OutDaqCallback outCallback) = 0; /** * @brief Stop the Daq device. Throws an exception if the device is not * running at the time this method is called. */ virtual void stop() = 0; virtual ~Daq() = 0; /** * @brief Returns the number of enabled input channels * * @param include_monitorchannels if true, all channels that are internally * monitored are added to the list. * * @return number of enabled input channels */ us neninchannels(bool include_monitorchannels = true) const; /** * @brief Returns the number of enabled output channels * * @return Number of enabled output channels */ us nenoutchannels() const; /** * @brief Create a vector of boolean values of the enabled input channels. * * @param include_monitor If set to true and a monitor channel is available, * the first index in the array will correspond to the monitor channel, and * whether it is enabled * * @return Boolean vector */ boolvec eninchannels(bool include_monitor = true) const; /** * @brief Create an array of booleans for each enabled output channel. * * @return Boolean vector */ boolvec enoutchannels() const; /** * @brief Returns current sample rate * * @return Sample rate in [Hz] */ double samplerate() const; /** * @brief Returns the input range for each channel. Means the minimum from * the absolute value of the minumum and maximum value that is allowed to * pass unclipped. * * @param ch The channel index from the input channels. * * @return Maximum offset from 0 before clipping. */ double inputRangeForChannel(us ch) const; /** * @brief Returns datatype (enum) corresponding to the datatype of the * samples. * * @return That as stated aboce */ DataTypeDescriptor::DataType dataType() const; /** * @brief More elaborate description of the datatypes. * * @return A DataTypeDescriptor */ const DataTypeDescriptor& dtypeDescr() const; /** * @brief The number of frames that is send in a block of DaqData. * * @return The number of frames per block */ us framesPerBlock() const { return availableFramesPerBlock.at(framesPerBlockIndex); } /** * @brief Get stream status corresponding to current DAQ. * * @return StreamStatus object. */ virtual StreamStatus getStreamStatus() const = 0; /** * @brief Whether the device runs in duplex mode (both input and output), or * false if only input / only output. * * @return true if duplex */ bool duplexMode() const { return (neninchannels() > 0 && nenoutchannels() > 0); } }; /** @} */