DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
HardwareAdapterNIDAQ.h
Go to the documentation of this file.
1// This file is part of DynExp.
2
9#pragma once
10
11#include "stdafx.h"
12#include "HardwareAdapter.h"
13#include "../MetaInstruments/DataStreamInstrument.h"
14
16{
17 #include "../include/NIDAQ/NIDAQmx.h"
18}
19
20namespace DynExpHardware
21{
23
25 {
26 public:
28 const std::source_location Location = std::source_location::current()) noexcept
29 : Exception(std::move(Description), Type, ErrorCode, Location)
30 {}
31 };
32
34 {
35 public:
37
38 private:
40
41 public:
43
45 : UseOnlyOnBrdMem{ Owner, UseOnlyOnBrdMemTypeStrList(), "UseOnlyOnBrdMem", "Onboard memory usage",
46 "Determines whether samples are written using a buffered transfer or a direct transfer to the device's onboard memory.", true, DefaultUseOnlyOnBrdMem }
47 {}
48
50
55 };
56
58 {
59 public:
62
65
68 virtual ~NIDAQHardwareAdapterParams() = default;
69
70 virtual const char* GetParamClassTag() const noexcept override { return "NIDAQHardwareAdapterParams"; }
71
73 "If timing is configured for multiple channels (stream size > 1 sample), they have to be combined into a number of NI-DAQmx tasks limited by the amount of the respective device's clocks.",
75
78
80 "Trigger assigned to this channel to start sample generation/acquisition", true, TriggerModeType::Disabled };
81 DynExp::ParamsBase::Param<ParamsConfigDialog::TextType> TriggerChannel = { *this, "TriggerChannelName", "Trigger channel name",
82 "Path of the trigger channel to be used for triggering (ignored if triggering is disabled)", true, "/Dev1/PFI0" };
83
84 private:
87 };
88
90 {
91 public:
94
97
98 private:
99 virtual DynExp::ParamsBasePtrType MakeParams(DynExp::ItemIDType ID, const DynExp::DynExpCore& Core) const override { return DynExp::MakeParams<NIDAQHardwareAdapterConfigurator>(ID, Core); }
100 };
101
103 {
105
106 public:
107 using ChannelHandleType = size_t;
108 using AnalogValueType = double;
109 using DigitalValueType = uint8_t;
110
113
115 ~NIDAQTask();
116
117 auto GetType() const noexcept { return Type; }
119 auto GetTimeout() const noexcept { return Timeout; }
120 auto GetSamplingRate() const noexcept { return SamplingRate; }
121 auto GetSamplingMode() const noexcept { return SamplingMode; }
122 auto GetNumSamples() const noexcept { return NumSamples; }
123 bool IsMultisample() const noexcept { return NumSamples > 1; }
124 auto GetNumChannels() const noexcept { return NumChannels; }
125 auto GetBufferSizeInSamples() const noexcept { return NumSamples * NumChannels; }
126 auto GetSampleSizeInBytes() const noexcept { return (Type == ChannelType::DigialIn || Type == ChannelType::DigitalOut) ? sizeof(DigitalValueType) : sizeof(AnalogValueType); }
127 auto GetChannelIndex(ChannelHandleType ChannelHandle) const { return ChannelIndexMap.at(ChannelHandle); }
128
129 private:
131 {
132 CircularStream(size_t BufferSize);
133
134 void Clear();
135
137 std::iostream Stream;
138 };
139
140 void AddChannel(ChannelHandleType ChannelHandle, uint64_t NumSamples);
141
143 const NIDAQSyms::TaskHandle NITask;
145
146 double Timeout = 0; // in seconds
147 double SamplingRate = 0; // in samples per second
149 uint64_t NumSamples = 1;
150 uint32_t NumChannels = 0;
151
152 std::map<ChannelHandleType, uint32_t> ChannelIndexMap;
153 std::vector<DigitalValueType> DigitalValues;
154 std::vector<AnalogValueType> AnalogValues;
155 std::vector<std::unique_ptr<CircularStream>> ReadStreamPerChannel;
156 };
157
159 {
160 public:
164
165 constexpr static auto Name() noexcept { return "NI-DAQmx"; }
166 constexpr static auto Category() noexcept { return "I/O"; }
167 static auto Enumerate();
168
170 virtual ~NIDAQHardwareAdapter();
171
172 virtual std::string GetName() const override { return Name(); }
173 virtual std::string GetCategory() const override { return Category(); }
174
175 // Timeout in seconds, MinValue and MaxValue in volts.
176 ChannelHandleType InitializeDigitalInChannel(std::string_view ChannelName, double Timeout = 0) const;
177 ChannelHandleType InitializeDigitalOutChannel(std::string_view ChannelName,
178 NIDAQOutputPortParamsExtension::UseOnlyOnBrdMemType UseOnlyOnBrdMem, double Timeout = 0) const;
179 ChannelHandleType InitializeAnalogInChannel(std::string_view ChannelName, double MinValue, double MaxValue, double Timeout = 0,
180 int32_t TerminalConfig = DAQmx_Val_RSE) const;
181 ChannelHandleType InitializeAnalogOutChannel(std::string_view ChannelName, double MinValue, double MaxValue,
182 NIDAQOutputPortParamsExtension::UseOnlyOnBrdMemType UseOnlyOnBrdMem, double Timeout = 0) const;
183 bool DeregisterChannel(ChannelHandleType ChannelHandle) const;
184
185 std::vector<NIDAQTask::DigitalValueType> ReadDigitalValues(ChannelHandleType ChannelHandle) const;
186 int32_t WriteDigitalValues(ChannelHandleType ChannelHandle, const std::vector<NIDAQTask::DigitalValueType>& Values) const;
187 std::vector<NIDAQTask::AnalogValueType> ReadAnalogValues(ChannelHandleType ChannelHandle) const;
188 int32_t WriteAnalogValues(ChannelHandleType ChannelHandle, const std::vector<NIDAQTask::AnalogValueType>& Values) const;
189
190 void StartTask(ChannelHandleType ChannelHandle) const;
191 void StopTask(ChannelHandleType ChannelHandle) const;
192 void RestartTask(ChannelHandleType ChannelHandle) const;
193 bool HasFinishedTask(ChannelHandleType ChannelHandle) const;
194 const NIDAQTask* GetTask(ChannelHandleType ChannelHandle) const;
195
196 private:
197 using TasksMapType = std::unordered_map<ChannelHandleType, std::shared_ptr<NIDAQTask>>;
198
199 void ResetImpl(dispatch_tag<HardwareAdapterBase>) override final;
201
202 void EnsureReadyStateChild() override final;
203 bool IsReadyChild() const override final;
204 bool IsConnectedChild() const noexcept override final;
205
206 // Not thread-safe, must be called from function calling AcquireLock().
207 void CheckError(const int32_t Result, const std::source_location Location = std::source_location::current()) const;
208 void CheckReadError(NIDAQTask* Task, const int32_t Result, const std::source_location Location = std::source_location::current()) const;
209
210 NIDAQSyms::TaskHandle CreateTaskUnsafe() const;
212 double Timeout, double SamplingRate, DynExpInstr::NumericSampleStreamParamsExtension::SamplingModeType SamplingMode) const;
213 void InitializeTriggerUnsafe(NIDAQTask* Task, NIDAQHardwareAdapterParams::TriggerModeType TriggerMode, std::string_view TriggerChannelName) const;
214 void StartTaskUnsafe(NIDAQTask* Task) const;
215 void StopTaskUnsafe(NIDAQTask* Task) const;
216 void RestartTaskUnsafe(NIDAQTask* Task) const;
217 bool HasFinishedTaskUnsafe(NIDAQTask* Task) const;
218
219 ChannelHandleType ChannelNameToChannelHandle(std::string_view ChannelName) const;
220 bool TaskExistsUnsafe(ChannelHandleType ChannelHandle) const;
221 bool TaskExistsUnsafe(std::string_view ChannelName) const;
222 NIDAQTask* GetTaskUnsafe(ChannelHandleType ChannelHandle) const;
223 NIDAQTask* GetTaskUnsafe(std::string_view ChannelName) const;
224 ChannelHandleType InsertTaskUnsafe(std::string_view ChannelName, std::shared_ptr<NIDAQTask>&& TaskHandle) const;
225 ChannelHandleType CreateTaskIfNotExistsUnsafe(std::string_view ChannelName, NIDAQTask::ChannelType Type) const;
226 bool RemoveTaskUnsafe(ChannelHandleType ChannelHandle) const;
227
228 // Map holding NIDAQ's tasks indexed by std::hash of NIDAQTask::ChannelName
229 // Logical const-ness: mutable, so that Instruments can (indirectly) make use of task map.
231 };
232}
Implementation of DynExp hardware adapter objects.
NIDAQException(std::string Description, const int ErrorCode, Util::ErrorType Type=Util::ErrorType::Error, const std::source_location Location=std::source_location::current()) noexcept
virtual DynExp::ParamsBasePtrType MakeParams(DynExp::ItemIDType ID, const DynExp::DynExpCore &Core) const override
Override to make derived classes call DynExp::MakeParams with the correct configurator type derived f...
NIDAQHardwareAdapterParams(DynExp::ItemIDType ID, const DynExp::DynExpCore &Core)
virtual void ConfigureParamsImpl(dispatch_tag< NIDAQHardwareAdapterParams >)
DynExpInstr::StreamSizeParamsExtension StreamSizeParams
DynExp::ParamsBase::Param< TriggerModeType > TriggerMode
static Util::TextValueListType< ChannelModeType > ChannelModeTypeStrList()
DynExpInstr::NumericSampleStreamParamsExtension NumericSampleStreamParams
DynExp::ParamsBase::Param< ChannelModeType > ChannelMode
virtual const char * GetParamClassTag() const noexcept override
This function is intended to be overridden once in each derived class returning the name of the respe...
static Util::TextValueListType< TriggerModeType > TriggerModeTypeStrList()
void ConfigureParamsImpl(dispatch_tag< HardwareAdapterParamsBase >) override final
DynExp::ParamsBase::Param< ParamsConfigDialog::TextType > TriggerChannel
ChannelHandleType InitializeDigitalOutChannel(std::string_view ChannelName, NIDAQOutputPortParamsExtension::UseOnlyOnBrdMemType UseOnlyOnBrdMem, double Timeout=0) const
void EnsureReadyStateChild() override final
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
void StartTask(ChannelHandleType ChannelHandle) const
void StartTaskUnsafe(NIDAQTask *Task) const
bool DeregisterChannel(ChannelHandleType ChannelHandle) const
bool HasFinishedTask(ChannelHandleType ChannelHandle) const
void InitializeTaskTimingUnsafe(NIDAQTask *Task, double Timeout, double SamplingRate, DynExpInstr::NumericSampleStreamParamsExtension::SamplingModeType SamplingMode) const
int32_t WriteAnalogValues(ChannelHandleType ChannelHandle, const std::vector< NIDAQTask::AnalogValueType > &Values) const
ChannelHandleType InitializeAnalogInChannel(std::string_view ChannelName, double MinValue, double MaxValue, double Timeout=0, int32_t TerminalConfig=DAQmx_Val_RSE) const
bool TaskExistsUnsafe(ChannelHandleType ChannelHandle) const
void CheckReadError(NIDAQTask *Task, const int32_t Result, const std::source_location Location=std::source_location::current()) const
std::unordered_map< ChannelHandleType, std::shared_ptr< NIDAQTask > > TasksMapType
ChannelHandleType CreateTaskIfNotExistsUnsafe(std::string_view ChannelName, NIDAQTask::ChannelType Type) const
virtual std::string GetCategory() const override
Returns the category of this Object type.
void StopTask(ChannelHandleType ChannelHandle) const
bool IsConnectedChild() const noexcept override final
Determines the connection status of the hardware interface.
ChannelHandleType InsertTaskUnsafe(std::string_view ChannelName, std::shared_ptr< NIDAQTask > &&TaskHandle) const
ChannelHandleType InitializeAnalogOutChannel(std::string_view ChannelName, double MinValue, double MaxValue, NIDAQOutputPortParamsExtension::UseOnlyOnBrdMemType UseOnlyOnBrdMem, double Timeout=0) const
virtual void ResetImpl(dispatch_tag< NIDAQHardwareAdapter >)
NIDAQTask::ChannelHandleType ChannelHandleType
bool HasFinishedTaskUnsafe(NIDAQTask *Task) const
NIDAQTask * GetTaskUnsafe(ChannelHandleType ChannelHandle) const
NIDAQSyms::TaskHandle CreateTaskUnsafe() const
void RestartTaskUnsafe(NIDAQTask *Task) const
const NIDAQTask * GetTask(ChannelHandleType ChannelHandle) const
std::vector< NIDAQTask::DigitalValueType > ReadDigitalValues(ChannelHandleType ChannelHandle) const
void InitializeTriggerUnsafe(NIDAQTask *Task, NIDAQHardwareAdapterParams::TriggerModeType TriggerMode, std::string_view TriggerChannelName) const
ChannelHandleType InitializeDigitalInChannel(std::string_view ChannelName, double Timeout=0) const
static constexpr auto Name() noexcept
bool IsReadyChild() const override final
Returns wheter this Object instance is ready (e.g. it is running or connected to a hardware device) a...
void RestartTask(ChannelHandleType ChannelHandle) const
virtual std::string GetName() const override
Returns the name of this Object type.
ChannelHandleType ChannelNameToChannelHandle(std::string_view ChannelName) const
static constexpr auto Category() noexcept
void ResetImpl(dispatch_tag< HardwareAdapterBase >) override final
bool RemoveTaskUnsafe(ChannelHandleType ChannelHandle) const
int32_t WriteDigitalValues(ChannelHandleType ChannelHandle, const std::vector< NIDAQTask::DigitalValueType > &Values) const
std::vector< NIDAQTask::AnalogValueType > ReadAnalogValues(ChannelHandleType ChannelHandle) const
void CheckError(const int32_t Result, const std::source_location Location=std::source_location::current()) const
DynExp::ParamsBase::Param< UseOnlyOnBrdMemType > UseOnlyOnBrdMem
Write directly to device's onboard memory?
static constexpr UseOnlyOnBrdMemType DefaultUseOnlyOnBrdMem
static Util::TextValueListType< UseOnlyOnBrdMemType > UseOnlyOnBrdMemTypeStrList()
bool IsCombined() const noexcept
std::vector< AnalogValueType > AnalogValues
auto GetSamplingMode() const noexcept
bool IsMultisample() const noexcept
std::map< ChannelHandleType, uint32_t > ChannelIndexMap
auto GetSamplingRate() const noexcept
auto GetNumChannels() const noexcept
auto GetTimeout() const noexcept
const NIDAQHardwareAdapterParams::ChannelModeType ChannelMode
auto GetType() const noexcept
auto GetChannelIndex(ChannelHandleType ChannelHandle) const
auto GetNumSamples() const noexcept
auto GetSampleSizeInBytes() const noexcept
void AddChannel(ChannelHandleType ChannelHandle, uint64_t NumSamples)
const NIDAQSyms::TaskHandle NITask
std::vector< std::unique_ptr< CircularStream > > ReadStreamPerChannel
std::vector< DigitalValueType > DigitalValues
auto GetBufferSizeInSamples() const noexcept
Bundles parameters to describe a NumericSampleStream's sampling properties.
Bundles parameters to describe a data stream's stream size.
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition DynExpCore.h:127
Defines the base class for a hardware adapter object. Hardware adapters describe interfaces/connectio...
Configurator class for HardwareAdapterBase.
Parameter class for HardwareAdapterBase.
HardwareAdapterParamsBase(ItemIDType ID, const DynExpCore &Core)
Constructs the parameters for a HardwareAdapterBase instance.
const std::thread::id OwnerThreadID
Thread id of the thread which has constructed (and owns) this Object instance.
Definition Object.h:2302
const ParamsBasePtrType Params
Pointer to the parameter class instance belonging to this Object instance.
Definition Object.h:2303
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2018
Abstract base class for object parameter classes. Each class derived from class Object must be accomp...
Definition Object.h:326
const ItemIDType ID
ID of the Object this parameter class instance belongs to.
Definition Object.h:1779
const DynExpCore & Core
Reference to DynExp's core.
Definition Object.h:1780
Tag for function dispatching mechanism within this class used when derived classes are not intended t...
Definition Object.h:349
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
Definition Exception.h:51
Exception(std::string Description, const ErrorType Type=ErrorType::Error, const int ErrorCode=-1, const std::source_location Location=std::source_location::current()) noexcept
Constructs an exception. Constructor is noexcept, although std::runtime_error() might throw std::bad_...
Definition Exception.cpp:8
const ErrorType Type
DynExp error type from Util::ErrorType
Definition Exception.h:105
const int ErrorCode
DynExp error code from DynExpErrorCodes::DynExpErrorCodes
Definition Exception.h:106
Circular stream buffer to be used with the standard library's stream classes. Reading from or writing...
Definition circularbuf.h:20
DynExp's hardware namespace contains the implementation of DynExp hardware adapters which extend DynE...
DynExp's instrument namespace contains the implementation of DynExp instruments which extend DynExp's...
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition Object.h:1807
size_t ItemIDType
ID type of objects/items managed by DynExp.
ErrorType
DynExp's error types
Definition Exception.h:15
std::vector< std::pair< TextType, ValueType > > TextValueListType
Type of a list containing key-value pairs where key is a text of type Util::TextType.
Definition QtUtil.h:37
Accumulates include statements to provide a precompiled header.