18 #define MRPT_HAS_SOME_NIDAQMX (MRPT_HAS_NIDAQMXBASE || MRPT_HAS_NIDAQMX)
20 #define MRPT_USE_NIDAQMXBASE (MRPT_HAS_NIDAQMXBASE && !MRPT_HAS_NIDAQMX)
21 #define MRPT_USE_NIDAQMX (MRPT_HAS_NIDAQMX)
23 #if MRPT_USE_NIDAQMXBASE
24 #include "NIDAQmxBase.h"
32 #if MRPT_USE_NIDAQMXBASE
33 #define MRPT_DAQmxGetExtendedErrorInfo DAQmxBaseGetExtendedErrorInfo
34 #define MRPT_DAQmxCreateTask DAQmxBaseCreateTask
35 #define MRPT_DAQmxCreateAIVoltageChan DAQmxBaseCreateAIVoltageChan
36 #define MRPT_DAQmxCreateAOVoltageChan DAQmxBaseCreateAOVoltageChan
37 #define MRPT_DAQmxCreateDIChan DAQmxBaseCreateDIChan
38 #define MRPT_DAQmxCreateDOChan DAQmxBaseCreateDOChan
39 #define MRPT_DAQmxCreateCIPeriodChan DAQmxBaseCreateCIPeriodChan
40 #define MRPT_DAQmxCreateCICountEdgesChan DAQmxBaseCreateCICountEdgesChan
41 #define MRPT_DAQmxCreateCIPulseWidthChan DAQmxBaseCreateCIPulseWidthChan
42 #define MRPT_DAQmxCreateCILinEncoderChan DAQmxBaseCreateCILinEncoderChan
43 #define MRPT_DAQmxCreateCIAngEncoderChan DAQmxBaseCreateCIAngEncoderChan
44 #define MRPT_DAQmxCreateCOPulseChanFreq DAQmxBaseCreateCOPulseChanFreq
45 #define MRPT_DAQmxCfgSampClkTiming DAQmxBaseCfgSampClkTiming
46 #define MRPT_DAQmxCfgInputBuffer DAQmxBaseCfgInputBuffer
47 #define MRPT_DAQmxCfgOutputBuffer DAQmxBaseCfgOutputBuffer
48 #define MRPT_DAQmxStartTask DAQmxBaseStartTask
49 #define MRPT_DAQmxStopTask DAQmxBaseStopTask
50 #define MRPT_DAQmxClearTask DAQmxBaseClearTask
51 #define MRPT_DAQmxReadAnalogF64 DAQmxBaseReadAnalogF64
52 #define MRPT_DAQmxReadCounterF64 DAQmxBaseReadCounterF64
53 #define MRPT_DAQmxReadDigitalU8 DAQmxBaseReadDigitalU8
54 #define MRPT_DAQmxWriteAnalogF64 DAQmxBaseWriteAnalogF64
55 #define MRPT_DAQmxWriteDigitalU32 DAQmxBaseWriteDigitalU32
56 #define MRPT_DAQmxWriteDigitalLines DAQmxBaseWriteDigitalLines
58 #define MRPT_DAQmxGetExtendedErrorInfo DAQmxGetExtendedErrorInfo
59 #define MRPT_DAQmxCreateTask DAQmxCreateTask
60 #define MRPT_DAQmxCreateAIVoltageChan DAQmxCreateAIVoltageChan
61 #define MRPT_DAQmxCreateAOVoltageChan DAQmxCreateAOVoltageChan
62 #define MRPT_DAQmxCreateDIChan DAQmxCreateDIChan
63 #define MRPT_DAQmxCreateDOChan DAQmxCreateDOChan
64 #define MRPT_DAQmxCreateCIPeriodChan DAQmxCreateCIPeriodChan
65 #define MRPT_DAQmxCreateCICountEdgesChan DAQmxCreateCICountEdgesChan
66 #define MRPT_DAQmxCreateCIPulseWidthChan DAQmxCreateCIPulseWidthChan
67 #define MRPT_DAQmxCreateCILinEncoderChan DAQmxCreateCILinEncoderChan
68 #define MRPT_DAQmxCreateCIAngEncoderChan DAQmxCreateCIAngEncoderChan
69 #define MRPT_DAQmxCreateCOPulseChanFreq DAQmxCreateCOPulseChanFreq
70 #define MRPT_DAQmxCfgSampClkTiming DAQmxCfgSampClkTiming
71 #define MRPT_DAQmxCfgInputBuffer DAQmxCfgInputBuffer
72 #define MRPT_DAQmxCfgOutputBuffer DAQmxCfgOutputBuffer
73 #define MRPT_DAQmxStartTask DAQmxStartTask
74 #define MRPT_DAQmxStopTask DAQmxStopTask
75 #define MRPT_DAQmxClearTask DAQmxClearTask
76 #define MRPT_DAQmxReadAnalogF64 DAQmxReadAnalogF64
77 #define MRPT_DAQmxReadCounterF64 DAQmxReadCounterF64
78 #define MRPT_DAQmxReadDigitalU8 DAQmxReadDigitalU8
79 #define MRPT_DAQmxWriteAnalogF64 DAQmxWriteAnalogF64
80 #define MRPT_DAQmxWriteDigitalU32 DAQmxWriteDigitalU32
81 #define MRPT_DAQmxWriteDigitalLines DAQmxWriteDigitalLines
86 #define MRPT_DAQmx_ErrChk(functionCall) \
87 if ((functionCall) < 0) \
90 MRPT_DAQmxGetExtendedErrorInfo(errBuff, 2048); \
91 std::string sErr = mrpt::format( \
92 "DAQ error: '%s'\nCalling: '%s'", errBuff, #functionCall); \
93 THROW_EXCEPTION(sErr); \
109 new_obs_available(0),
124 #define MY_LOAD_HERE_CONFIG_VAR( \
125 variableName, variableType, targetVariable, configFileObject, \
127 targetVariable = configFileObject.read_##variableType( \
128 sectionNameStr, variableName, targetVariable, false);
130 #define MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( \
131 variableName, variableType, targetVariable, configFileObject, \
136 targetVariable = configFileObject.read_##variableType( \
137 sectionNameStr, variableName, targetVariable, true); \
139 catch (std::exception&) \
143 "Value for '%s' not found in config file", \
144 std::string(variableName).c_str())); \
157 const unsigned int nTasks = cfg.
read_uint64_t(sect,
"num_tasks", 0,
true);
160 std::cerr <<
"[CNationalInstrumentsDAQ] Warning: Number of tasks is "
161 "zero. No datalogging will be done.\n";
165 for (
unsigned int i = 0; i < nTasks; i++)
172 const string sChanns =
173 cfg.
read_string(sect, sTask +
string(
".channels"),
"",
true);
174 vector<string> lstStrChanns;
176 if (lstStrChanns.empty())
180 sTask +
string(
".samplesPerSecond"),
double,
t.samplesPerSecond,
183 sTask +
string(
".samplesPerChannelToRead"),
double,
184 t.samplesPerChannelToRead, cfg, sect)
186 sTask +
string(
".sampleClkSource"),
string,
t.sampleClkSource, cfg,
189 sTask +
string(
".bufferSamplesPerChannel"),
double,
190 t.bufferSamplesPerChannel, cfg, sect)
192 cfg.
read_string(sect, sTask +
string(
".taskLabel"), sTask,
false);
194 for (
size_t j = 0; j < lstStrChanns.size(); j++)
196 if (
strCmpI(lstStrChanns[j],
"ai"))
200 sTask +
string(
".ai.physicalChannel"),
string,
201 t.ai.physicalChannel, cfg, sect)
203 sTask +
string(
".ai.physicalChannelCount"),
uint64_t,
204 t.ai.physicalChannelCount, cfg, sect)
206 sTask +
string(
".ai.terminalConfig"),
string,
207 t.ai.terminalConfig, cfg, sect)
209 sTask +
string(
".ai.minVal"),
double,
t.ai.minVal, cfg,
212 sTask +
string(
".ai.maxVal"),
double,
t.ai.maxVal, cfg,
215 else if (
strCmpI(lstStrChanns[j],
"ao"))
219 sTask +
string(
".ao.physicalChannel"),
string,
220 t.ao.physicalChannel, cfg, sect)
222 sTask +
string(
".ao.physicalChannelCount"),
uint64_t,
223 t.ao.physicalChannelCount, cfg, sect)
225 sTask +
string(
".ao.minVal"),
double,
t.ao.minVal, cfg,
228 sTask +
string(
".ao.maxVal"),
double,
t.ao.maxVal, cfg,
231 else if (
strCmpI(lstStrChanns[j],
"di"))
235 sTask +
string(
".di.line"),
string,
t.di.line, cfg, sect)
237 else if (
strCmpI(lstStrChanns[j],
"do"))
241 sTask +
string(
".do.line"),
string,
t.douts.line, cfg, sect)
243 else if (
strCmpI(lstStrChanns[j],
"ci_period"))
245 t.has_ci_period =
true;
247 sTask +
string(
".ci_period.counter"),
string,
248 t.ci_period.counter, cfg, sect)
250 sTask +
string(
".ci_period.minVal"),
double,
251 t.ci_period.minVal, cfg, sect)
253 sTask +
string(
".ci_period.maxVal"),
double,
254 t.ci_period.maxVal, cfg, sect)
256 sTask +
string(
".ci_period.units"),
string,
257 t.ci_period.units, cfg, sect)
259 sTask +
string(
".ci_period.edge"),
string,
t.ci_period.edge,
262 sTask +
string(
".ci_period.measTime"),
double,
263 t.ci_period.measTime, cfg, sect)
265 sTask +
string(
".ci_period.divisor"),
int,
266 t.ci_period.divisor, cfg, sect)
268 else if (
strCmpI(lstStrChanns[j],
"ci_count_edges"))
270 t.has_ci_count_edges =
true;
272 sTask +
string(
".ci_count_edges.counter"),
string,
273 t.ci_count_edges.counter, cfg, sect)
275 sTask +
string(
".ci_count_edges.edge"),
string,
276 t.ci_count_edges.edge, cfg, sect)
278 sTask +
string(
".ci_count_edges.initialCount"),
int,
279 t.ci_count_edges.initialCount, cfg, sect)
281 sTask +
string(
".ci_count_edges.countDirection"),
string,
282 t.ci_count_edges.countDirection, cfg, sect)
284 else if (
strCmpI(lstStrChanns[j],
"ci_pulse_width"))
286 t.has_ci_pulse_width =
true;
288 sTask +
string(
".ci_pulse_width.counter"),
string,
289 t.ci_pulse_width.counter, cfg, sect)
291 sTask +
string(
".ci_pulse_width.minVal"),
double,
292 t.ci_pulse_width.minVal, cfg, sect)
294 sTask +
string(
".ci_pulse_width.maxVal"),
double,
295 t.ci_pulse_width.maxVal, cfg, sect)
297 sTask +
string(
".ci_pulse_width.units"),
string,
298 t.ci_pulse_width.units, cfg, sect)
300 sTask +
string(
".ci_pulse_width.startingEdge"),
string,
301 t.ci_pulse_width.startingEdge, cfg, sect)
303 else if (
strCmpI(lstStrChanns[j],
"ci_lin_encoder"))
305 t.has_ci_lin_encoder =
true;
307 sTask +
string(
".ci_lin_encoder.counter"),
string,
308 t.ci_lin_encoder.counter, cfg, sect)
310 sTask +
string(
".ci_lin_encoder.decodingType"),
string,
311 t.ci_lin_encoder.decodingType, cfg, sect)
313 sTask +
string(
".ci_lin_encoder.ZidxEnable"),
bool,
314 t.ci_lin_encoder.ZidxEnable, cfg, sect)
316 sTask +
string(
".ci_lin_encoder.ZidxVal"),
double,
317 t.ci_lin_encoder.ZidxVal, cfg, sect)
319 sTask +
string(
".ci_lin_encoder.ZidxPhase"),
string,
320 t.ci_lin_encoder.ZidxPhase, cfg, sect)
322 sTask +
string(
".ci_lin_encoder.units"),
string,
323 t.ci_lin_encoder.units, cfg, sect)
325 sTask +
string(
".ci_lin_encoder.distPerPulse"),
double,
326 t.ci_lin_encoder.distPerPulse, cfg, sect)
328 sTask +
string(
".ci_lin_encoder.initialPos"),
double,
329 t.ci_lin_encoder.initialPos, cfg, sect)
331 else if (
strCmpI(lstStrChanns[j],
"ci_ang_encoder"))
333 t.has_ci_ang_encoder =
true;
335 sTask +
string(
".ci_ang_encoder.counter"),
string,
336 t.ci_ang_encoder.counter, cfg, sect)
338 sTask +
string(
".ci_ang_encoder.decodingType"),
string,
339 t.ci_ang_encoder.decodingType, cfg, sect)
341 sTask +
string(
".ci_ang_encoder.ZidxEnable"),
bool,
342 t.ci_ang_encoder.ZidxEnable, cfg, sect)
344 sTask +
string(
".ci_ang_encoder.ZidxVal"),
double,
345 t.ci_ang_encoder.ZidxVal, cfg, sect)
347 sTask +
string(
".ci_ang_encoder.ZidxPhase"),
string,
348 t.ci_ang_encoder.ZidxPhase, cfg, sect)
350 sTask +
string(
".ci_ang_encoder.units"),
string,
351 t.ci_ang_encoder.units, cfg, sect)
353 sTask +
string(
".ci_ang_encoder.pulsesPerRev"),
int,
354 t.ci_ang_encoder.pulsesPerRev, cfg, sect)
356 sTask +
string(
".ci_ang_encoder.initialAngle"),
double,
357 t.ci_ang_encoder.initialAngle, cfg, sect)
359 sTask +
string(
".ci_ang_encoder.decimate"),
int,
360 t.ci_ang_encoder.decimate, cfg, sect)
362 else if (
strCmpI(lstStrChanns[j],
"co_pulses"))
364 t.has_co_pulses =
true;
366 sTask +
string(
".co_pulses.counter"),
string,
367 t.co_pulses.counter, cfg, sect)
369 sTask +
string(
".co_pulses.idleState"),
string,
370 t.co_pulses.idleState, cfg, sect)
372 sTask +
string(
".co_pulses.initialDelay"),
double,
373 t.co_pulses.initialDelay, cfg, sect)
375 sTask +
string(
".co_pulses.freq"),
double,
t.co_pulses.freq,
378 sTask +
string(
".co_pulses.dutyCycle"),
double,
379 t.co_pulses.dutyCycle, cfg, sect)
384 "Unknown channel type '%s'! See the docs of "
385 "CNationalInstrumentsDAQ",
386 lstStrChanns[j].c_str())
396 #if MRPT_HAS_SOME_NIDAQMX
404 const daqmx_str_val daqmx_vals[] = {
405 {
"DAQmx_Val_Cfg_Default", DAQmx_Val_Cfg_Default},
406 {
"DAQmx_Val_RSE", DAQmx_Val_RSE},
407 {
"DAQmx_Val_NRSE", DAQmx_Val_NRSE},
408 {
"DAQmx_Val_Diff", DAQmx_Val_Diff},
409 {
"DAQmx_Val_Seconds", DAQmx_Val_Seconds},
410 {
"DAQmx_Val_Rising", DAQmx_Val_Rising},
411 {
"DAQmx_Val_Falling", DAQmx_Val_Falling},
412 {
"DAQmx_Val_CountUp", DAQmx_Val_CountUp},
413 {
"DAQmx_Val_CountDown", DAQmx_Val_CountDown},
414 {
"DAQmx_Val_ExtControlled", DAQmx_Val_ExtControlled},
415 {
"DAQmx_Val_AHighBHigh", DAQmx_Val_AHighBHigh},
416 {
"DAQmx_Val_AHighBLow", DAQmx_Val_AHighBLow},
417 {
"DAQmx_Val_ALowBHigh", DAQmx_Val_ALowBHigh},
418 {
"DAQmx_Val_ALowBLow", DAQmx_Val_ALowBLow},
419 {
"DAQmx_Val_X1", DAQmx_Val_X1},
420 {
"DAQmx_Val_X2", DAQmx_Val_X2},
421 {
"DAQmx_Val_X4", DAQmx_Val_X4},
422 {
"DAQmx_Val_Meters", DAQmx_Val_Meters},
423 {
"DAQmx_Val_Inches", DAQmx_Val_Inches},
424 {
"DAQmx_Val_Ticks", DAQmx_Val_Ticks},
425 {
"DAQmx_Val_Degrees", DAQmx_Val_Degrees},
426 {
"DAQmx_Val_Radians", DAQmx_Val_Radians},
427 {
"DAQmx_Val_High", DAQmx_Val_High},
428 {
"DAQmx_Val_Low", DAQmx_Val_Low}};
434 for (
unsigned int i = 0; i <
sizeof(daqmx_vals) /
sizeof(daqmx_vals[0]);
437 if (
strCmpI(daqmx_vals[i].str,
s.c_str()))
return daqmx_vals[i].
val;
448 #if MRPT_HAS_SOME_NIDAQMX
463 TaskHandle& taskHandle =
464 *
reinterpret_cast<TaskHandle*
>(&ipt.
taskHandle);
472 "ai.physicalChannelCount is zero! Please, define it "
479 tf.
ai.
maxVal, DAQmx_Val_Volts,
nullptr));
485 "ai.physicalChannelCount is zero! Please, define it "
497 taskHandle, tf.
di.
line.c_str(),
nullptr,
498 DAQmx_Val_ChanPerLine));
504 taskHandle, tf.
douts.
line.c_str(),
nullptr,
505 DAQmx_Val_ChanPerLine));
610 ipt.
read_pipe->timeout_read_start_us = 100000;
611 ipt.
read_pipe->timeout_read_between_us = 100000;
618 catch (std::exception
const& e)
620 std::cerr <<
"[CNationalInstrumentsDAQ] Error:" << std::endl
621 << e.what() << std::endl;
624 TaskHandle& taskHandle =
625 *
reinterpret_cast<TaskHandle*
>(&ipt.
taskHandle);
634 cerr <<
"[CNationalInstrumentsDAQ::initialize] Waiting for the "
635 "grabbing thread to end due to exception...\n";
637 cerr <<
"[CNationalInstrumentsDAQ::initialize] Grabbing thread "
644 std::cerr <<
"[CNationalInstrumentsDAQ] Error while creating "
645 "tasks. Closing other tasks before returning...\n";
647 std::cerr <<
"[CNationalInstrumentsDAQ] Closing tasks done.\n";
666 it->must_close =
true;
669 cout <<
"[CNationalInstrumentsDAQ::stop] Waiting for grabbing threads "
675 if (it->hThread.joinable()) it->hThread.join();
682 cout <<
"[CNationalInstrumentsDAQ::stop] All threads ended.\n";
685 #if MRPT_HAS_SOME_NIDAQMX
689 TaskHandle& taskHandle =
690 *
reinterpret_cast<TaskHandle*
>(&it->taskHandle);
694 taskHandle =
nullptr;
709 std::vector<mrpt::obs::CObservationRawDAQ::Ptr>& outObservations,
712 hardwareError =
false;
713 outObservations.clear();
717 hardwareError =
true;
730 if (it->new_obs_available != 0)
733 arch.ReadObject(&tmp_obs);
734 --(it->new_obs_available);
737 outObservations.push_back(
766 std::vector<mrpt::serialization::CSerializable::Ptr> new_obs;
781 #if MRPT_HAS_SOME_NIDAQMX
784 TaskHandle& taskHandle =
785 *
reinterpret_cast<TaskHandle*
>(&ipt.
taskHandle);
787 cout <<
"[CNationalInstrumentsDAQ::grabbing_thread] Starting "
794 const float timeout =
799 vector<uint8_t> u8Buf;
813 bool there_are_data =
false;
825 dBuf.resize(totalSamplesToRead);
826 int32 pointsReadPerChan = -1;
830 : DAQmx_Val_GroupByChannel,
831 &dBuf[0], dBuf.size(), &pointsReadPerChan,
nullptr)) <
833 err != DAQmxErrorSamplesNotYetAvailable)
837 else if (pointsReadPerChan > 0)
843 there_are_data =
true;
845 cout <<
"[CNationalInstrumentsDAQ::grabbing_thread] "
846 << pointsReadPerChan <<
" analog samples read.\n";
853 u8Buf.resize(totalSamplesToRead);
855 int32 pointsReadPerChan = -1;
858 DAQmx_Val_GroupByChannel, &u8Buf[0], u8Buf.size(),
859 &pointsReadPerChan,
nullptr)) < 0 &&
860 err != DAQmxErrorSamplesNotYetAvailable)
864 else if (pointsReadPerChan > 0)
870 there_are_data =
true;
872 cout <<
"[CNationalInstrumentsDAQ::grabbing_thread] "
873 << pointsReadPerChan <<
" digital samples read.\n";
878 const int32 totalSamplesToRead =
880 dBuf.resize(totalSamplesToRead);
881 int32 pointsReadPerChan = -1;
883 taskHandle, totalSamplesToRead, timeout, &dBuf[0],
884 dBuf.size(), &pointsReadPerChan,
nullptr)) < 0 &&
885 err != DAQmxErrorSamplesNotYetAvailable)
889 else if (pointsReadPerChan > 0)
899 there_are_data =
true;
902 static int decim = 0;
904 cout <<
"[CNationalInstrumentsDAQ::grabbing_"
907 <<
" counter samples read ([0]="
909 if (++decim > 100) decim = 0;
925 std::this_thread::sleep_for(1ms);
930 catch (std::exception& e)
932 std::cerr <<
"[CNationalInstrumentsDAQ::grabbing_thread] Exception:\n"
933 << e.what() << std::endl;
935 #endif // MRPT_HAS_SOME_NIDAQMX
941 size_t task_index,
size_t nSamplesPerChannel,
const double* volt_values,
942 double timeout,
bool groupedByChannel)
944 #if MRPT_HAS_SOME_NIDAQMX
947 std::advance(it, task_index);
949 TaskHandle& taskHandle = *
reinterpret_cast<TaskHandle*
>(&ipt.
taskHandle);
951 int32 samplesWritten = 0;
954 taskHandle, nSamplesPerChannel,
FALSE, timeout,
955 groupedByChannel ? DAQmx_Val_GroupByChannel
956 : DAQmx_Val_GroupByScanNumber,
957 const_cast<float64*
>(volt_values), &samplesWritten,
nullptr))
971 size_t task_index,
bool line_value,
double timeout)
973 #if MRPT_HAS_SOME_NIDAQMX
976 std::advance(it, task_index);
978 TaskHandle& taskHandle = *
reinterpret_cast<TaskHandle*
>(&ipt.
taskHandle);
980 uInt8 dat = line_value ? 1 : 0;
982 int32 samplesWritten = 0;
983 int32 nSamplesPerChannel = 1;
986 taskHandle, nSamplesPerChannel,
FALSE, timeout,
987 DAQmx_Val_GroupByScanNumber, &dat, &samplesWritten,
nullptr))
1005 has_ci_period(false),
1006 has_ci_count_edges(false),
1007 has_ci_pulse_width(false),
1008 has_ci_lin_encoder(false),
1009 has_ci_ang_encoder(false),
1010 has_co_pulses(false),
1011 samplesPerSecond(1000.0),
1012 bufferSamplesPerChannel(200000),
1013 samplesPerChannelToRead(1000)