259 lines
6.8 KiB
C++
259 lines
6.8 KiB
C++
#pragma once
|
|
#include "lasp_daq.h"
|
|
#include "lasp_siggen.h"
|
|
#include <list>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
/** \addtogroup device
|
|
* @{
|
|
*/
|
|
class StreamMgr;
|
|
|
|
class InDataHandler {
|
|
|
|
protected:
|
|
StreamMgr &_mgr;
|
|
#if LASP_DEBUG == 1
|
|
std::atomic<bool> stopCalled{false};
|
|
#endif
|
|
|
|
public:
|
|
virtual ~InDataHandler();
|
|
|
|
/**
|
|
* @brief When constructed, the handler is added to the stream manager, which
|
|
* will call the handlers's inCallback() until stop() is called.
|
|
*
|
|
* @param mgr Stream manager.
|
|
*/
|
|
InDataHandler(StreamMgr &mgr);
|
|
|
|
/**
|
|
* @brief This function is called when input data from a DAQ is available.
|
|
*
|
|
* @param daqdata Input data from DAQ
|
|
*
|
|
* @return true if no error. False to stop the stream from running.
|
|
*/
|
|
virtual bool inCallback(const DaqData &daqdata) = 0;
|
|
|
|
/**
|
|
* @brief Reset in-data handler.
|
|
*
|
|
* @param daq New DAQ configuration of inCallback(). If nullptr is given,
|
|
* it means that the stream is stopped.
|
|
*/
|
|
virtual void reset(const Daq* daq = nullptr) = 0;
|
|
|
|
/**
|
|
* @brief This function should be called from the constructor of the
|
|
* implementation of InDataHandler. It will start the stream's calling of
|
|
* inCallback().
|
|
*/
|
|
void start();
|
|
|
|
/**
|
|
* @brief This function should be called from the destructor of derived
|
|
* classes, to disable the calls to inCallback(), such that proper
|
|
* destruction of the object is allowed and no other threads call methods
|
|
* from the object. It removes the inCallback() from the callback list of the
|
|
* StreamMgr(). **Failing to call this function results in deadlocks, errors
|
|
* like "pure virtual function called", or other**.
|
|
*/
|
|
void stop();
|
|
};
|
|
|
|
/**
|
|
* @brief Stream manager. Used to manage the input and output streams.
|
|
* Implemented as a singleton: only one stream manager can be in existance for
|
|
* a given program. The thread that instantiates a stream manager is the only
|
|
* thread that should interact with the stream manager. If this is not true,
|
|
* undefined behavior can be expected. If LASP is compiled in debug mode, this
|
|
* fact is asserted.
|
|
*/
|
|
class StreamMgr {
|
|
#if LASP_DEBUG == 1
|
|
std::thread::id _main_thread_id;
|
|
#endif
|
|
|
|
/**
|
|
* @brief Storage for streams.
|
|
*/
|
|
std::unique_ptr<Daq> _inputStream, _outputStream;
|
|
|
|
/**
|
|
* @brief All indata handlers are called when input data is available. Note
|
|
* that they can be called from different threads and should take care of
|
|
* thread-safety.
|
|
*/
|
|
std::list<InDataHandler *> _inDataHandlers;
|
|
std::mutex _inDataHandler_mtx;
|
|
|
|
/**
|
|
* @brief Signal generator in use to generate output data. Currently
|
|
* implemented as to generate the same data for all output channels.
|
|
*/
|
|
std::shared_ptr<Siggen> _siggen;
|
|
std::mutex _siggen_mtx;
|
|
|
|
std::mutex _devices_mtx;
|
|
std::vector<DeviceInfo> _devices;
|
|
|
|
StreamMgr();
|
|
|
|
friend class InDataHandler;
|
|
friend class Siggen;
|
|
|
|
// Singleton, no public destructor
|
|
~StreamMgr();
|
|
|
|
public:
|
|
enum class StreamType : us {
|
|
/**
|
|
* @brief Input stream
|
|
*/
|
|
input = 1 << 0,
|
|
/**
|
|
* @brief Output stream
|
|
*/
|
|
output = 1 << 1,
|
|
};
|
|
|
|
StreamMgr(const StreamMgr &) = delete;
|
|
StreamMgr &operator=(const StreamMgr &) = delete;
|
|
|
|
/**
|
|
* @brief Get access to stream manager instance
|
|
*
|
|
* @return Reference to stream manager.
|
|
*/
|
|
static StreamMgr &getInstance();
|
|
|
|
/**
|
|
* @brief Obtain a list of devices currently available. When the StreamMgr is
|
|
* first created, this
|
|
*
|
|
* @return A copy of the internal stored list of devices
|
|
*/
|
|
std::vector<DeviceInfo> getDeviceInfo() const {
|
|
std::scoped_lock lck(const_cast<std::mutex &>(_devices_mtx));
|
|
return _devices;
|
|
}
|
|
|
|
/**
|
|
* @brief Triggers a background scan of the DAQ devices, which updates the
|
|
* internally stored list of devices. Throws a runtime error when a
|
|
* background thread is already scanning for devices.
|
|
*
|
|
* @param background Perform searching for DAQ devices in the background. If
|
|
* set to true, the function returns immediately.
|
|
* @param callback Function to call when complete.
|
|
*/
|
|
void
|
|
rescanDAQDevices(bool background = false,
|
|
std::function<void()> callback = std::function<void()>());
|
|
|
|
/**
|
|
* @brief Start a stream based on given configuration.
|
|
*
|
|
* @param config Configuration of a device
|
|
*/
|
|
void startStream(const DaqConfiguration &config);
|
|
|
|
/**
|
|
* @brief Check if a certain stream is running. If running with no errors, it
|
|
* returns true. If an error occured, or the stream is not running, it gives
|
|
* false.
|
|
*
|
|
* @param type The type of stream to check for.
|
|
*/
|
|
bool isStreamRunningOK(const StreamType type) const {
|
|
return getStreamStatus(type).runningOK();
|
|
}
|
|
bool isStreamRunning(const StreamType type) const {
|
|
switch(type) {
|
|
case(StreamType::input):
|
|
return bool(_inputStream);
|
|
break;
|
|
case(StreamType::output):
|
|
return bool(_outputStream);
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the streamstatus object corresponding to a given stream.
|
|
*
|
|
* @param type Type of stream, input, inputType, etc.
|
|
*
|
|
* @return status object.
|
|
*/
|
|
Daq::StreamStatus getStreamStatus(const StreamType type) const;
|
|
|
|
/**
|
|
* @brief Get DAQ pointer for a given stream. Gives a nullptr if stream is
|
|
* not running.
|
|
*
|
|
* @param type The stream type to get a DAQ ptr for.
|
|
*
|
|
* @return Pointer to DAQ
|
|
*/
|
|
const Daq *getDaq(StreamType type) const;
|
|
|
|
/**
|
|
* @brief Stop stream of given type (input / output/ duplex);
|
|
*
|
|
* @param stype The stream type to stop.
|
|
*/
|
|
void stopStream(const StreamType stype);
|
|
|
|
/**
|
|
* @brief Stop and delete all streams. Also called on destruction of the
|
|
* StreamMgr.
|
|
*/
|
|
void stopAllStreams();
|
|
|
|
/**
|
|
* @brief Set active signal generator for output streams. Only one `Siggen'
|
|
* is active at the same time. Siggen controls its own data race protection
|
|
* using a mutex.
|
|
*
|
|
* @param s New Siggen pointer
|
|
*/
|
|
void setSiggen(std::shared_ptr<Siggen> s);
|
|
|
|
private:
|
|
bool inCallback(const DaqData &data);
|
|
bool outCallback(DaqData &data);
|
|
|
|
void removeInDataHandler(InDataHandler &handler);
|
|
|
|
/**
|
|
* @brief Add an input data handler. The handler's inCallback() function is
|
|
* called with data when available. This function should *NOT* be called by
|
|
* the user, instead, an InDataHandler can only be created with the StreamMgr
|
|
* as argument.
|
|
*
|
|
* @param handler The handler to add.
|
|
*/
|
|
void addInDataHandler(InDataHandler &handler);
|
|
|
|
/**
|
|
* @brief Do the actual rescanning.
|
|
*
|
|
* @param callback
|
|
*/
|
|
void rescanDAQDevices_impl(std::function<void()> callback);
|
|
|
|
#if LASP_DEBUG == 1
|
|
void checkRightThread() const;
|
|
#else
|
|
void checkRightThread() const {}
|
|
#endif
|
|
};
|
|
|
|
/** @} */
|