Main MRPT website > C++ reference for MRPT 1.5.6
CNationalInstrumentsDAQ.cpp
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #include "hwdrivers-precomp.h" // Precompiled headers
11 
13 #include <iterator> // advance()
14 
15 // If we have both, DAQmx & DAQmxBase, prefer DAQmx:
16 #define MRPT_HAS_SOME_NIDAQMX (MRPT_HAS_NIDAQMXBASE || MRPT_HAS_NIDAQMX)
17 
18 #define MRPT_USE_NIDAQMXBASE (MRPT_HAS_NIDAQMXBASE && !MRPT_HAS_NIDAQMX)
19 #define MRPT_USE_NIDAQMX (MRPT_HAS_NIDAQMX)
20 
21 
22 #if MRPT_USE_NIDAQMXBASE
23 # include "NIDAQmxBase.h" // Include file for NI-DAQmx Base API
24 #endif
25 #if MRPT_USE_NIDAQMX
26 # include "NIDAQmx.h" // Include file for NI-DAQmx API
27 #endif
28 
29 // Macros to use either DAQmx or DAQmx Base automatically, depending on the installed libraries:
30 #if MRPT_USE_NIDAQMXBASE
31 # define MRPT_DAQmxGetExtendedErrorInfo DAQmxBaseGetExtendedErrorInfo
32 # define MRPT_DAQmxCreateTask DAQmxBaseCreateTask
33 # define MRPT_DAQmxCreateAIVoltageChan DAQmxBaseCreateAIVoltageChan
34 # define MRPT_DAQmxCreateAOVoltageChan DAQmxBaseCreateAOVoltageChan
35 # define MRPT_DAQmxCreateDIChan DAQmxBaseCreateDIChan
36 # define MRPT_DAQmxCreateDOChan DAQmxBaseCreateDOChan
37 # define MRPT_DAQmxCreateCIPeriodChan DAQmxBaseCreateCIPeriodChan
38 # define MRPT_DAQmxCreateCICountEdgesChan DAQmxBaseCreateCICountEdgesChan
39 # define MRPT_DAQmxCreateCIPulseWidthChan DAQmxBaseCreateCIPulseWidthChan
40 # define MRPT_DAQmxCreateCILinEncoderChan DAQmxBaseCreateCILinEncoderChan
41 # define MRPT_DAQmxCreateCIAngEncoderChan DAQmxBaseCreateCIAngEncoderChan
42 # define MRPT_DAQmxCreateCOPulseChanFreq DAQmxBaseCreateCOPulseChanFreq
43 # define MRPT_DAQmxCfgSampClkTiming DAQmxBaseCfgSampClkTiming
44 # define MRPT_DAQmxCfgInputBuffer DAQmxBaseCfgInputBuffer
45 # define MRPT_DAQmxCfgOutputBuffer DAQmxBaseCfgOutputBuffer
46 # define MRPT_DAQmxStartTask DAQmxBaseStartTask
47 # define MRPT_DAQmxStopTask DAQmxBaseStopTask
48 # define MRPT_DAQmxClearTask DAQmxBaseClearTask
49 # define MRPT_DAQmxReadAnalogF64 DAQmxBaseReadAnalogF64
50 # define MRPT_DAQmxReadCounterF64 DAQmxBaseReadCounterF64
51 # define MRPT_DAQmxReadDigitalU8 DAQmxBaseReadDigitalU8
52 # define MRPT_DAQmxWriteAnalogF64 DAQmxBaseWriteAnalogF64
53 # define MRPT_DAQmxWriteDigitalU32 DAQmxBaseWriteDigitalU32
54 # define MRPT_DAQmxWriteDigitalLines DAQmxBaseWriteDigitalLines
55 #else
56 # define MRPT_DAQmxGetExtendedErrorInfo DAQmxGetExtendedErrorInfo
57 # define MRPT_DAQmxCreateTask DAQmxCreateTask
58 # define MRPT_DAQmxCreateAIVoltageChan DAQmxCreateAIVoltageChan
59 # define MRPT_DAQmxCreateAOVoltageChan DAQmxCreateAOVoltageChan
60 # define MRPT_DAQmxCreateDIChan DAQmxCreateDIChan
61 # define MRPT_DAQmxCreateDOChan DAQmxCreateDOChan
62 # define MRPT_DAQmxCreateCIPeriodChan DAQmxCreateCIPeriodChan
63 # define MRPT_DAQmxCreateCICountEdgesChan DAQmxCreateCICountEdgesChan
64 # define MRPT_DAQmxCreateCIPulseWidthChan DAQmxCreateCIPulseWidthChan
65 # define MRPT_DAQmxCreateCILinEncoderChan DAQmxCreateCILinEncoderChan
66 # define MRPT_DAQmxCreateCIAngEncoderChan DAQmxCreateCIAngEncoderChan
67 # define MRPT_DAQmxCreateCOPulseChanFreq DAQmxCreateCOPulseChanFreq
68 # define MRPT_DAQmxCfgSampClkTiming DAQmxCfgSampClkTiming
69 # define MRPT_DAQmxCfgInputBuffer DAQmxCfgInputBuffer
70 # define MRPT_DAQmxCfgOutputBuffer DAQmxCfgOutputBuffer
71 # define MRPT_DAQmxStartTask DAQmxStartTask
72 # define MRPT_DAQmxStopTask DAQmxStopTask
73 # define MRPT_DAQmxClearTask DAQmxClearTask
74 # define MRPT_DAQmxReadAnalogF64 DAQmxReadAnalogF64
75 # define MRPT_DAQmxReadCounterF64 DAQmxReadCounterF64
76 # define MRPT_DAQmxReadDigitalU8 DAQmxReadDigitalU8
77 # define MRPT_DAQmxWriteAnalogF64 DAQmxWriteAnalogF64
78 # define MRPT_DAQmxWriteDigitalU32 DAQmxWriteDigitalU32
79 # define MRPT_DAQmxWriteDigitalLines DAQmxWriteDigitalLines
80 #endif
81 
82 // An auxiliary macro to check and report errors in the DAQmx library as exceptions with a well-explained message.
83 #define MRPT_DAQmx_ErrChk(functionCall) \
84  if( (functionCall)<0) \
85  { \
86  char errBuff[2048]; \
87  MRPT_DAQmxGetExtendedErrorInfo(errBuff,2048); \
88  std::string sErr = mrpt::format("DAQ error: '%s'\nCalling: '%s'",errBuff,#functionCall); \
89  THROW_EXCEPTION(sErr) \
90  }
91 
92 
93 using namespace mrpt::hwdrivers;
94 using namespace mrpt::obs;
95 using namespace mrpt::system;
96 using namespace std;
97 
99 
100 // ------------- CNationalInstrumentsDAQ::TInfoPerTask -----------
101 // Default ctor:
103  taskHandle(0),
104  must_close(false),
105  is_closed(false),
106  new_obs_available(0),
107  task()
108 { }
109 
110 // Copy ctor (needed for the auto_ptr semantics)
112  taskHandle(o.taskHandle),
113  hThread(o.hThread),
114  read_pipe(o.read_pipe.get()),
115  write_pipe(o.write_pipe.get()),
116  must_close(o.must_close),
117  is_closed(o.is_closed),
118  new_obs_available(0),
119  task(o.task)
120 {
121  const_cast<TInfoPerTask*>(&o)->read_pipe.release();
122  const_cast<TInfoPerTask*>(&o)->write_pipe.release();
123 }
124 
125 
126 /* -----------------------------------------------------
127  Constructor
128  ----------------------------------------------------- */
130  mrpt::utils::COutputLogger("CNationalInstrumentsDAQ")
131 {
132  m_sensorLabel = "NIDAQ";
133 }
134 
135 // Just like "MRPT_LOAD_HERE_CONFIG_VAR" but...
136 #define MY_LOAD_HERE_CONFIG_VAR(variableName,variableType,targetVariable,configFileObject,sectionNameStr) \
137  targetVariable = configFileObject.read_##variableType(sectionNameStr,variableName,targetVariable,false);
138 
139 #define MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT(variableName,variableType,targetVariable,configFileObject,sectionNameStr) \
140  { try { \
141  targetVariable = configFileObject.read_##variableType(sectionNameStr,variableName,targetVariable,true); \
142  } catch (std::exception &) \
143  { \
144  THROW_EXCEPTION( format( "Value for '%s' not found in config file", std::string(variableName).c_str() )); \
145  } }\
146 
147 
148 
149 /* -----------------------------------------------------
150  loadConfig_sensorSpecific
151  ----------------------------------------------------- */
153  const mrpt::utils::CConfigFileBase &cfg,
154  const std::string &sect )
155 {
156  //std::vector<TaskDescription> task_definitions;
157  task_definitions.clear();
158 
159  const unsigned int nTasks = cfg.read_uint64_t(sect, "num_tasks", 0, true );
160  if (!nTasks) {
161  std::cerr << "[CNationalInstrumentsDAQ] Warning: Number of tasks is zero. No datalogging will be done.\n";
162  }
163 
164  task_definitions.resize(nTasks);
165  for (unsigned int i=0;i<nTasks;i++)
166  {
168  const string sTask = mrpt::format("task%u",i);
169 
170  // Read general settings for this task:
171  // ---------------------------------------
172  const string sChanns = cfg.read_string(sect,sTask+string(".channels"),"",true);
173  vector<string> lstStrChanns;
174  mrpt::system::tokenize(sChanns," \t,",lstStrChanns);
175  if (lstStrChanns.empty())
176  THROW_EXCEPTION_FMT("List of channels for task %u is empty!",i)
177 
178  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".samplesPerSecond"), double, t.samplesPerSecond, cfg,sect)
179  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".samplesPerChannelToRead"), double, t.samplesPerChannelToRead, cfg,sect)
180  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".sampleClkSource"), string, t.sampleClkSource, cfg,sect)
181  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".bufferSamplesPerChannel"), double, t.bufferSamplesPerChannel, cfg,sect)
182  t.taskLabel = cfg.read_string(sect,sTask+string(".taskLabel"), sTask, false );
183 
184  for (size_t j=0;j<lstStrChanns.size();j++)
185  {
186  if (strCmpI(lstStrChanns[j],"ai"))
187  {
188  t.has_ai = true;
189  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ai.physicalChannel"), string, t.ai.physicalChannel, cfg,sect)
190  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ai.physicalChannelCount"), uint64_t, t.ai.physicalChannelCount, cfg,sect)
191  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ai.terminalConfig"), string, t.ai.terminalConfig, cfg,sect)
192  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ai.minVal"), double, t.ai.minVal, cfg,sect)
193  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ai.maxVal"), double, t.ai.maxVal, cfg,sect)
194  }
195  else if (strCmpI(lstStrChanns[j],"ao"))
196  {
197  t.has_ao = true;
198  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ao.physicalChannel"), string, t.ao.physicalChannel, cfg,sect)
199  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ao.physicalChannelCount"), uint64_t, t.ao.physicalChannelCount, cfg,sect)
200  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ao.minVal"), double, t.ao.minVal, cfg,sect)
201  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ao.maxVal"), double, t.ao.maxVal, cfg,sect)
202  }
203  else if (strCmpI(lstStrChanns[j],"di"))
204  {
205  t.has_di = true;
206  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".di.line"), string, t.di.line, cfg,sect)
207  }
208  else if (strCmpI(lstStrChanns[j],"do"))
209  {
210  t.has_do = true;
211  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".do.line"), string, t.douts.line, cfg,sect)
212  }
213  else if (strCmpI(lstStrChanns[j],"ci_period"))
214  {
215  t.has_ci_period = true;
216  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_period.counter"), string, t.ci_period.counter, cfg,sect)
217  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_period.minVal"), double, t.ci_period.minVal, cfg,sect)
218  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_period.maxVal"), double, t.ci_period.maxVal, cfg,sect)
219  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_period.units"), string, t.ci_period.units, cfg,sect)
220  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_period.edge"), string, t.ci_period.edge, cfg,sect)
221  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".ci_period.measTime"), double, t.ci_period.measTime, cfg,sect)
222  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".ci_period.divisor"), int, t.ci_period.divisor, cfg,sect)
223  }
224  else if (strCmpI(lstStrChanns[j],"ci_count_edges"))
225  {
226  t.has_ci_count_edges = true;
227  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_count_edges.counter"), string, t.ci_count_edges.counter, cfg,sect)
228  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_count_edges.edge"), string, t.ci_count_edges.edge, cfg,sect)
229  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".ci_count_edges.initialCount"), int, t.ci_count_edges.initialCount, cfg,sect)
230  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".ci_count_edges.countDirection"), string, t.ci_count_edges.countDirection, cfg,sect)
231  }
232  else if (strCmpI(lstStrChanns[j],"ci_pulse_width"))
233  {
234  t.has_ci_pulse_width = true;
235  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_pulse_width.counter"), string, t.ci_pulse_width.counter, cfg,sect)
236  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_pulse_width.minVal"), double, t.ci_pulse_width.minVal, cfg,sect)
237  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_pulse_width.maxVal"), double, t.ci_pulse_width.maxVal, cfg,sect)
238  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_pulse_width.units"), string, t.ci_pulse_width.units, cfg,sect)
239  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_pulse_width.startingEdge"), string, t.ci_pulse_width.startingEdge, cfg,sect)
240  }
241  else if (strCmpI(lstStrChanns[j],"ci_lin_encoder"))
242  {
243  t.has_ci_lin_encoder = true;
244  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.counter"), string, t.ci_lin_encoder.counter, cfg,sect)
245  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.decodingType"), string, t.ci_lin_encoder.decodingType, cfg,sect)
246  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.ZidxEnable"), bool, t.ci_lin_encoder.ZidxEnable, cfg,sect)
247  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.ZidxVal"), double, t.ci_lin_encoder.ZidxVal, cfg,sect)
248  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.ZidxPhase"), string, t.ci_lin_encoder.ZidxPhase, cfg,sect)
249  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.units"), string, t.ci_lin_encoder.units, cfg,sect)
250  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.distPerPulse"), double, t.ci_lin_encoder.distPerPulse, cfg,sect)
251  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_lin_encoder.initialPos"), double, t.ci_lin_encoder.initialPos, cfg,sect)
252  }
253  else if (strCmpI(lstStrChanns[j],"ci_ang_encoder"))
254  {
255  t.has_ci_ang_encoder = true;
256  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.counter"), string, t.ci_ang_encoder.counter, cfg,sect)
257  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.decodingType"), string, t.ci_ang_encoder.decodingType, cfg,sect)
258  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.ZidxEnable"), bool, t.ci_ang_encoder.ZidxEnable, cfg,sect)
259  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.ZidxVal"), double, t.ci_ang_encoder.ZidxVal, cfg,sect)
260  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.ZidxPhase"), string, t.ci_ang_encoder.ZidxPhase, cfg,sect)
261  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.units"), string, t.ci_ang_encoder.units, cfg,sect)
262  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.pulsesPerRev"), int, t.ci_ang_encoder.pulsesPerRev, cfg,sect)
263  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".ci_ang_encoder.initialAngle"), double, t.ci_ang_encoder.initialAngle, cfg,sect)
264  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".ci_ang_encoder.decimate"), int, t.ci_ang_encoder.decimate, cfg,sect)
265 
266  }
267  else if (strCmpI(lstStrChanns[j],"co_pulses"))
268  {
269  t.has_co_pulses = true;
270  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".co_pulses.counter"), string, t.co_pulses.counter, cfg,sect)
271  MY_LOAD_HERE_CONFIG_VAR( sTask+string(".co_pulses.idleState"), string, t.co_pulses.idleState, cfg,sect)
272  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".co_pulses.initialDelay"), double, t.co_pulses.initialDelay, cfg,sect)
273  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".co_pulses.freq"), double, t.co_pulses.freq, cfg,sect)
274  MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( sTask+string(".co_pulses.dutyCycle"), double, t.co_pulses.dutyCycle, cfg,sect)
275  }
276  else
277  {
278  THROW_EXCEPTION_FMT("Unknown channel type '%s'! See the docs of CNationalInstrumentsDAQ",lstStrChanns[j].c_str())
279  }
280  } // end for each "k" channel in channel "i"
281  } // end for "i", each task
282 }
283 
284 /* -----------------------------------------------------
285  Destructor
286  ----------------------------------------------------- */
288 {
289  this->stop();
290 }
291 
292 #if MRPT_HAS_SOME_NIDAQMX
293 // Declare a table to convert strings to their DAQmx #define values:
294 struct daqmx_str_val {
295  const char* str;
296  int val;
297 };
298 
299 const daqmx_str_val daqmx_vals[] = {
300  { "DAQmx_Val_Cfg_Default", DAQmx_Val_Cfg_Default },
301  { "DAQmx_Val_RSE", DAQmx_Val_RSE },
302  { "DAQmx_Val_NRSE", DAQmx_Val_NRSE },
303  { "DAQmx_Val_Diff", DAQmx_Val_Diff },
304  { "DAQmx_Val_Seconds", DAQmx_Val_Seconds },
305  { "DAQmx_Val_Rising", DAQmx_Val_Rising },
306  { "DAQmx_Val_Falling", DAQmx_Val_Falling },
307  { "DAQmx_Val_CountUp", DAQmx_Val_CountUp },
308  { "DAQmx_Val_CountDown", DAQmx_Val_CountDown },
309  { "DAQmx_Val_ExtControlled", DAQmx_Val_ExtControlled },
310  { "DAQmx_Val_AHighBHigh", DAQmx_Val_AHighBHigh },
311  { "DAQmx_Val_AHighBLow", DAQmx_Val_AHighBLow },
312  { "DAQmx_Val_ALowBHigh", DAQmx_Val_ALowBHigh },
313  { "DAQmx_Val_ALowBLow", DAQmx_Val_ALowBLow },
314  { "DAQmx_Val_X1", DAQmx_Val_X1},
315  { "DAQmx_Val_X2", DAQmx_Val_X2},
316  { "DAQmx_Val_X4", DAQmx_Val_X4},
317  { "DAQmx_Val_Meters", DAQmx_Val_Meters },
318  { "DAQmx_Val_Inches", DAQmx_Val_Inches },
319  { "DAQmx_Val_Ticks", DAQmx_Val_Ticks },
320  { "DAQmx_Val_Degrees", DAQmx_Val_Degrees },
321  { "DAQmx_Val_Radians", DAQmx_Val_Radians },
322  { "DAQmx_Val_High", DAQmx_Val_High},
323  { "DAQmx_Val_Low", DAQmx_Val_Low}
324 };
325 
326 int daqmx_defstr2num(const std::string &str)
327 {
328  const std::string s = mrpt::system::trim(str);
329 
330  for (unsigned int i=0;i<sizeof(daqmx_vals)/sizeof(daqmx_vals[0]);i++)
331  {
332  if (strCmpI(daqmx_vals[i].str,s.c_str()))
333  return daqmx_vals[i].val;
334  }
335  THROW_EXCEPTION_FMT("Error: Unknown DAQmx constant: %s",s.c_str())
336 }
337 #endif
338 
339 /* -----------------------------------------------------
340  initialize
341 ----------------------------------------------------- */
343 {
344 #if MRPT_HAS_SOME_NIDAQMX
345  this->stop();
346 
347  for (size_t i=0;i<task_definitions.size();i++)
348  {
349  const TaskDescription & tf = task_definitions[i];
350 
351  // Try to create a new task:
352  m_running_tasks.push_back(TInfoPerTask());
353  TInfoPerTask &ipt = m_running_tasks.back();
354  ipt.task = tf; // Save a copy of the task info for the thread to have all the needed info
355 
356  try
357  {
358  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&ipt.taskHandle);
359 
360  MRPT_DAQmx_ErrChk (MRPT_DAQmxCreateTask("",&taskHandle));
361 
362  if (tf.has_ai) {
363  ASSERTMSG_(tf.ai.physicalChannelCount>0, "ai.physicalChannelCount is zero! Please, define it correctly.")
364 
366  tf.ai.physicalChannel.c_str(),NULL,
367  daqmx_defstr2num(tf.ai.terminalConfig),
368  tf.ai.minVal, tf.ai.maxVal,DAQmx_Val_Volts,NULL));
369  }
370  if (tf.has_ao) {
371  ASSERTMSG_(tf.ao.physicalChannelCount>0, "ai.physicalChannelCount is zero! Please, define it correctly.")
372 
374  tf.ao.physicalChannel.c_str(),NULL,
375  tf.ao.minVal, tf.ao.maxVal,DAQmx_Val_Volts,NULL));
376  }
377  if (tf.has_di) {
379  tf.di.line.c_str(),NULL,DAQmx_Val_ChanPerLine));
380  }
381  if (tf.has_do) {
383  tf.douts.line.c_str(),NULL,DAQmx_Val_ChanPerLine));
384  }
385  if (tf.has_ci_period) {
387  tf.ci_period.counter.c_str(),NULL,
389  daqmx_defstr2num(tf.ci_period.units),
390  daqmx_defstr2num(tf.ci_period.edge),
391  DAQmx_Val_LowFreq1Ctr,
392  tf.ci_period.measTime,
393  tf.ci_period.divisor,NULL));
394  }
395  if (tf.has_ci_count_edges) {
397  tf.ci_count_edges.counter.c_str(),NULL,
398  daqmx_defstr2num(tf.ci_count_edges.edge),
400  daqmx_defstr2num(tf.ci_count_edges.countDirection)));
401  }
402  if (tf.has_ci_pulse_width) {
404  tf.ci_pulse_width.counter.c_str(),NULL,
406  daqmx_defstr2num(tf.ci_pulse_width.units),
407  daqmx_defstr2num(tf.ci_pulse_width.startingEdge),
408  NULL));
409  }
410  if (tf.has_ci_lin_encoder) {
412  tf.ci_lin_encoder.counter.c_str(),NULL,
413  daqmx_defstr2num(tf.ci_lin_encoder.decodingType),
416  daqmx_defstr2num(tf.ci_lin_encoder.ZidxPhase),
417  daqmx_defstr2num(tf.ci_lin_encoder.units),
420  NULL));
421  }
422  if (tf.has_ci_ang_encoder) {
424  tf.ci_ang_encoder.counter.c_str(),NULL,
425  daqmx_defstr2num(tf.ci_ang_encoder.decodingType),
428  daqmx_defstr2num(tf.ci_ang_encoder.ZidxPhase),
429  daqmx_defstr2num(tf.ci_ang_encoder.units),
432  NULL));
433  }
434  if (tf.has_co_pulses) {
436  tf.co_pulses.counter.c_str(),NULL,
437  DAQmx_Val_Hz,
438  daqmx_defstr2num(tf.co_pulses.idleState),
440  tf.co_pulses.freq,
441  tf.co_pulses.dutyCycle));
442  }
443 
444  // Seems to be needed to avoid an errors avoid like:
445  // " Onboard device memory overflow. Because of system and/or bus-bandwidth limitations, the driver could not read data from the device fast enough to keep up with the device throughput."
447  {
448  // sample rate:
450  MRPT_DAQmx_ErrChk (MRPT_DAQmxCfgSampClkTiming(taskHandle,tf.sampleClkSource.c_str(),tf.samplesPerSecond,DAQmx_Val_Rising, DAQmx_Val_ContSamps,tf.samplesPerChannelToRead));
451 
453  }
454 
455  if (tf.has_ao)
456  {
457  // Nothing to do as long as we only need "on demand" outputs.
458  // MRPT_DAQmx_ErrChk (MRPT_DAQmxCfgOutputBuffer(taskHandle,2 /*tf.bufferSamplesPerChannel*/ ));
459  // // Output buffer MUST have some data before starting the task: write 0s:
460  // vector<double> d;
461  // d.assign(tf.ao.physicalChannelCount*2, 0.0);
462  // this->writeAnalogOutputTask(i,1 /* samples per channel */, &d[0], 0.10 /*timeout*/, false);
463  }
464 
465  // Create pipe:
467 
468  // Add a large timeout, just in case the writing thread dies unexpectedly so the reader doesn't hang on:
469  ipt.read_pipe->timeout_read_start_us = 100000; // 100ms
470  ipt.read_pipe->timeout_read_between_us = 100000; // 100ms
471 
473 
474  ipt.hThread = mrpt::system::createThreadFromObjectMethodRef<CNationalInstrumentsDAQ,TInfoPerTask>(this, &CNationalInstrumentsDAQ::grabbing_thread, ipt);
475 
476 
477  }
478  catch (std::exception const &e)
479  {
480  std::cerr << "[CNationalInstrumentsDAQ] Error:" << std::endl << e.what() << std::endl;
481  if( ipt.taskHandle!=NULL )
482  {
483  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&ipt.taskHandle);
484  MRPT_DAQmxStopTask(taskHandle);
485  MRPT_DAQmxClearTask(taskHandle);
486  }
487 
488  // Stop thread:
489  if (!ipt.hThread.isClear())
490  {
491  ipt.must_close=true;
492  cerr << "[CNationalInstrumentsDAQ::initialize] Waiting for the grabbing thread to end due to exception...\n";
494  cerr << "[CNationalInstrumentsDAQ::initialize] Grabbing thread ended.\n";
495  }
496 
497  // Remove from list:
498  m_running_tasks.erase(--m_running_tasks.end());
499 
500  std::cerr << "[CNationalInstrumentsDAQ] Error while creating tasks. Closing other tasks before returning...\n";
501  this->stop();
502  std::cerr << "[CNationalInstrumentsDAQ] Closing tasks done.\n";
503 
504  throw; // Rethrow
505  }
506  } // end for each task_definitions[i]
507 
508 #else
509  THROW_EXCEPTION("MRPT was compiled without support for NI DAQmx!!")
510 #endif
511 }
512 
513 /** Stop the grabbing threads for DAQ tasks. It is automatically called at destruction. */
515 {
516  // Stop all threads:
517  for (list<TInfoPerTask>::iterator it=m_running_tasks.begin();it!=m_running_tasks.end();++it)
518  {
519  it->must_close=true;
520  }
521  if (m_verbose) cout << "[CNationalInstrumentsDAQ::stop] Waiting for grabbing threads to end...\n";
522  for (list<TInfoPerTask>::iterator it=m_running_tasks.begin();it!=m_running_tasks.end();++it)
523  {
524  // For some reason, join doesn't work...
525  // if (!it->hThread.isClear()) mrpt::system::joinThread(it->hThread);
526  // Polling:
527  for (size_t tim=0;tim<250 && !it->is_closed;tim++) { mrpt::system::sleep(1); }
528  it->hThread.clear();
529  }
530  if (m_verbose) cout << "[CNationalInstrumentsDAQ::stop] All threads ended.\n";
531 
532  // Stop all NI tasks:
533 #if MRPT_HAS_SOME_NIDAQMX
534  for (list<TInfoPerTask>::iterator it=m_running_tasks.begin();it!=m_running_tasks.end();++it)
535  {
536  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&it->taskHandle);
537 
538  MRPT_DAQmxStopTask(taskHandle);
539  MRPT_DAQmxClearTask(taskHandle);
540  taskHandle=NULL;
541  }
542 #endif
543 }
544 
545 /** Returns true if initialize() was called successfully. */
547 {
548  return (!m_running_tasks.empty() && !m_running_tasks.begin()->is_closed);
549 }
550 
551 
552 /*-------------------------------------------------------------
553  readFromDAQ
554 -------------------------------------------------------------*/
556  std::vector<mrpt::obs::CObservationRawDAQPtr> &outObservations,
557  bool &hardwareError )
558 {
559  hardwareError = false;
560  outObservations.clear();
561 
562  if ( !checkDAQIsWorking() )
563  {
564  hardwareError = true;
565  return;
566  }
567 
568  // Read from the pipe:
569  m_state = ssWorking;
570 
571 
572  for (list<TInfoPerTask>::iterator it=m_running_tasks.begin();it!=m_running_tasks.end();++it)
573  {
574  CObservationRawDAQ tmp_obs;
575  try
576  {
577  if (it->new_obs_available!=0)
578  {
579  it->read_pipe->ReadObject(&tmp_obs);
580  --(it->new_obs_available);
581 
582  // Yes, valid block of samples was adquired:
583  outObservations.push_back(CObservationRawDAQPtr(new CObservationRawDAQ(tmp_obs)));
584  }
585  }
586  catch (...)
587  {
588  // Timeout...
589  }
590  }
591 }
592 
593 
594 /* -----------------------------------------------------
595  doProcess
596 ----------------------------------------------------- */
598 {
599  bool hwError;
600  readFromDAQ(m_nextObservations, hwError );
601 
602  if (hwError)
603  {
604  m_state = ssError;
605  THROW_EXCEPTION("Couldn't start DAQ task!");
606  }
607 
608  if (!m_nextObservations.empty())
609  {
610  m_state = ssWorking;
611 
612  std::vector<mrpt::utils::CSerializablePtr> new_obs;
613  new_obs.resize(m_nextObservations.size());
614 
615  for (size_t i=0;i<m_nextObservations.size();i++)
616  new_obs[i] = m_nextObservations[i];
617 
618  appendObservations(new_obs);
619  }
620 }
621 
622 
623 /* -----------------------------------------------------
624  grabbing_thread
625 ----------------------------------------------------- */
627 {
628 #if MRPT_HAS_SOME_NIDAQMX
629  try
630  {
631  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&ipt.taskHandle);
632  if (m_verbose) cout << "[CNationalInstrumentsDAQ::grabbing_thread] Starting thread for task " << ipt.taskHandle << "\n";
633 
634  MRPT_TODO("Add write timeout")
635  //ipt.write_pipe->timeout_read_between_us
636 
637  const float timeout = 10*ipt.task.samplesPerChannelToRead/ipt.task.samplesPerSecond;
638 
639  int err=0;
640  vector<double> dBuf;
641  vector<uint8_t> u8Buf;
642 
643  const mrpt::obs::CObservationRawDAQ clean_obs;
645 
646  while (!ipt.must_close)
647  {
648  obs = clean_obs; // Start with an empty observation
649 
650  // Common stuff:
654 
655  bool there_are_data = false; // At least one channel?
656 
657  // Read from each channel in this task:
658  // -----------------------------------------------
659  if (ipt.task.has_ai)
660  {
662  obs.AIN_interleaved = true;
663 
664  const uint32_t totalSamplesToRead = ipt.task.ai.physicalChannelCount * ipt.task.samplesPerChannelToRead;
665  dBuf.resize(totalSamplesToRead);
666  int32 pointsReadPerChan=-1;
667  if ((err = MRPT_DAQmxReadAnalogF64(
668  taskHandle,
669  ipt.task.samplesPerChannelToRead,timeout, obs.AIN_interleaved ? DAQmx_Val_GroupByScanNumber : DAQmx_Val_GroupByChannel,
670  &dBuf[0],dBuf.size(),
671  &pointsReadPerChan,NULL))<0 && err!=DAQmxErrorSamplesNotYetAvailable)
672  {
673  MRPT_DAQmx_ErrChk(err)
674  }
675  else if (pointsReadPerChan>0) {
676  ASSERT_EQUAL_(totalSamplesToRead,pointsReadPerChan*ipt.task.ai.physicalChannelCount)
677  obs.AIN_double = dBuf;
678  there_are_data = true;
679  if (m_verbose) cout << "[CNationalInstrumentsDAQ::grabbing_thread] " << pointsReadPerChan << " analog samples read.\n";
680  }
681  } // end AI
682  if (ipt.task.has_di)
683  {
684  const uint32_t totalSamplesToRead = 1 * ipt.task.samplesPerChannelToRead;
685  u8Buf.resize(totalSamplesToRead);
686 
687  int32 pointsReadPerChan=-1;
688  if ((err = MRPT_DAQmxReadDigitalU8(
689  taskHandle,
690  ipt.task.samplesPerChannelToRead,timeout, DAQmx_Val_GroupByChannel,
691  &u8Buf[0],u8Buf.size(),
692  &pointsReadPerChan,NULL))<0 && err!=DAQmxErrorSamplesNotYetAvailable)
693  {
694  MRPT_DAQmx_ErrChk(err)
695  }
696  else if (pointsReadPerChan>0) {
697  ASSERT_EQUAL_(totalSamplesToRead,pointsReadPerChan*ipt.task.ai.physicalChannelCount)
698  obs.DIN = u8Buf;
699  there_are_data = true;
700  if (m_verbose) cout << "[CNationalInstrumentsDAQ::grabbing_thread] " << pointsReadPerChan << " digital samples read.\n";
701  }
702  } // end DI
704  {
705  const int32 totalSamplesToRead = ipt.task.samplesPerChannelToRead;
706  dBuf.resize(totalSamplesToRead);
707  int32 pointsReadPerChan=-1;
708  if ((err = MRPT_DAQmxReadCounterF64(
709  taskHandle,
710  totalSamplesToRead,timeout,
711  &dBuf[0],dBuf.size(),
712  &pointsReadPerChan,NULL))<0 && err!=DAQmxErrorSamplesNotYetAvailable)
713  {
714  MRPT_DAQmx_ErrChk(err)
715  }
716  else if (pointsReadPerChan>0) {
717  ASSERT_EQUAL_(totalSamplesToRead,pointsReadPerChan)
718 
719  // Decimate?
721  {
723 
724  obs.CNTRIN_double = dBuf;
725  there_are_data = true;
726  if (m_verbose && !obs.CNTRIN_double.empty())
727  {
728  static int decim=0;
729  if (!decim)
730  cout << "[CNationalInstrumentsDAQ::grabbing_thread] " << pointsReadPerChan << " counter samples read ([0]="<< obs.CNTRIN_double[0] <<").\n";
731  if (++decim>100) decim=0;
732  }
733  }
734  }
735  } // end COUNTERS
736 
737  // Send the observation to the main thread:
738  if (there_are_data)
739  {
740  ++(ipt.new_obs_available);
741  ipt.write_pipe->WriteObject(&obs);
742  //mrpt::system::sleep(1); // This seems to be needed to allow all objs to be sent to the recv thread
743  }
744  else {
746  }
747 
748  } // end of main thread loop
749  }
750  catch(std::exception &e)
751  {
752  std::cerr << "[CNationalInstrumentsDAQ::grabbing_thread] Exception:\n" << e.what() << std::endl;
753  }
754 #endif //MRPT_HAS_SOME_NIDAQMX
755 
756  ipt.is_closed = true;
757 }
758 
759 
760 void CNationalInstrumentsDAQ::writeAnalogOutputTask(size_t task_index, size_t nSamplesPerChannel, const double * volt_values, double timeout, bool groupedByChannel)
761 {
762 #if MRPT_HAS_SOME_NIDAQMX
763  ASSERT_(task_index<m_running_tasks.size())
764 
766  std::advance(it, task_index);
767  TInfoPerTask & ipt = *it;
768  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&ipt.taskHandle);
769 
770  int32 samplesWritten=0;
771  int err=0;
772  if (err = MRPT_DAQmxWriteAnalogF64(
773  taskHandle,
774  nSamplesPerChannel,FALSE,timeout, groupedByChannel ? DAQmx_Val_GroupByChannel : DAQmx_Val_GroupByScanNumber,
775  const_cast<float64*>(volt_values),
776  &samplesWritten, NULL) )
777  {
778  MRPT_DAQmx_ErrChk(err)
779  }
780 #else
781  MRPT_UNUSED_PARAM(task_index); MRPT_UNUSED_PARAM(nSamplesPerChannel);
782  MRPT_UNUSED_PARAM(volt_values); MRPT_UNUSED_PARAM(timeout); MRPT_UNUSED_PARAM(groupedByChannel);
783 #endif
784 }
785 
786 void CNationalInstrumentsDAQ::writeDigitalOutputTask(size_t task_index, bool line_value, double timeout)
787 {
788 #if MRPT_HAS_SOME_NIDAQMX
789  ASSERT_(task_index<m_running_tasks.size())
790 
792  std::advance(it, task_index);
793  TInfoPerTask & ipt = *it;
794  TaskHandle &taskHandle= *reinterpret_cast<TaskHandle*>(&ipt.taskHandle);
795 
796  uInt8 dat = line_value ? 1:0;
797 
798  int32 samplesWritten=0;
799  int32 nSamplesPerChannel = 1;
800  int err=0;
801  if (err = MRPT_DAQmxWriteDigitalLines(
802  taskHandle,
803  nSamplesPerChannel,FALSE,timeout, DAQmx_Val_GroupByScanNumber,
804  &dat,&samplesWritten,NULL) )
805  {
806  MRPT_DAQmx_ErrChk(err)
807  }
808 
809 #else
810  MRPT_UNUSED_PARAM(task_index); MRPT_UNUSED_PARAM(line_value); MRPT_UNUSED_PARAM(timeout);
811 #endif
812 }
813 
814 
815 // Ctor:
817  has_ai(false), has_ao(false), has_di(false), has_do(false),
818  has_ci_period(false), has_ci_count_edges(false), has_ci_pulse_width(false), has_ci_lin_encoder(false),has_ci_ang_encoder(false),has_co_pulses(false),
819  samplesPerSecond(1000.0),
820  bufferSamplesPerChannel(200000),
821  samplesPerChannelToRead(1000)
822 {
823 }
824 
#define ASSERT_EQUAL_(__A, __B)
void appendObservations(const std::vector< mrpt::utils::CSerializablePtr > &obj)
This method must be called by derived classes to enqueue a new observation in the list to be returned...
uint16_t AIN_channel_count
Readings from analog input (ADCs) channels (vector length=channel count) in Volts.
#define MRPT_DAQmxCreateCILinEncoderChan
double sample_rate
Readings from ticks counters, such as quadrature encoders.
Each of the tasks to create in CNationalInstrumentsDAQ::initialize().
GLdouble GLdouble t
Definition: glext.h:3610
#define ASSERT_ABOVE_(__A, __B)
virtual void initialize()
Setup and launch the DAQ tasks, in parallel threads.
#define MRPT_DAQmxCreateDOChan
std::string line
The digital line (for example "Dev1/port0/line1")
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:29
#define MRPT_DAQmxCreateCIPulseWidthChan
std::string m_sensorLabel
See CGenericSensor.
#define MRPT_DAQmxStartTask
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Scalar * iterator
Definition: eigen_plugins.h:23
#define MRPT_DAQmxCreateAOVoltageChan
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ao_t ao
Analog outputs.
#define MRPT_DAQmxCreateDIChan
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Definition: datetime.h:70
Contains classes for various device interfaces.
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
#define MY_LOAD_HERE_CONFIG_VAR_NO_DEFAULT(variableName, variableType, targetVariable, configFileObject, sectionNameStr)
#define MRPT_DAQmxCreateCIPeriodChan
STL namespace.
bool checkDAQIsWorking() const
Returns true if initialize() was called and at least one task is running.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_di_t di
Digital inputs (di)
TaskDescription task
A copy of the original task description that generated this thread.
GLdouble s
Definition: glext.h:3602
#define MRPT_DAQmxWriteDigitalLines
#define MRPT_DAQmxReadAnalogF64
void readFromDAQ(std::vector< mrpt::obs::CObservationRawDAQPtr > &outObservations, bool &hardwareError)
Receives data from the DAQ thread(s).
This class allows loading and storing values and vectors of different types from a configuration text...
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
See the class documentation at the top for expected parameters.
MRPT_TODO("Modify ping to run on Windows + Test this")
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_do_t douts
Digital outs (do)
#define MRPT_DAQmxWriteAnalogF64
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_count_edges_t ci_count_edges
Counter: period of a digital signal.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
std::string sampleClkSource
Sample clock source: may be empty (default value) for some channels.
#define MRPT_DAQmxCreateCIAngEncoderChan
void writeDigitalOutputTask(size_t task_index, bool line_value, double timeout)
Changes the boolean state of one digital output line.
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time...
Definition: threads.cpp:57
#define FALSE
Definition: jmorecfg.h:227
#define MRPT_DAQmxCfgInputBuffer
std::auto_ptr< mrpt::synch::CPipeWriteEndPoint > write_pipe
#define MRPT_DAQmxReadCounterF64
This namespace contains representation of robot actions and observations.
int val
Definition: mrpt_jpeglib.h:953
void stop()
Stop the grabbing threads for DAQ tasks.
#define MY_LOAD_HERE_CONFIG_VAR(variableName, variableType, targetVariable, configFileObject, sectionNameStr)
void grabbing_thread(TInfoPerTask &ipt)
Method to be executed in each parallel thread.
An interface to read from data acquisition boards compatible with National Instruments "DAQmx Base" o...
bool isClear() const
Returns true if the handle is uninitialized.
Definition: threads.h:64
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_period_t ci_period
Counter: period of a digital signal.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
bool AIN_interleaved
Whether the channels are interleaved (A0 A1 A2 A0 A1 A2...) or not (A0 A0 A0 A1 A1 A1 A2 A2 A2...
GLsizei const GLchar ** string
Definition: glext.h:3919
#define MRPT_DAQmxStopTask
Store raw data from a Data Acquisition (DAQ) device, such that input or output analog and digital cha...
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
void writeAnalogOutputTask(size_t task_index, size_t nSamplesPerChannel, const double *volt_values, double timeout, bool groupedByChannel)
Set voltage outputs to all the outputs in an AOUT task For the meaning of parameters, refere to NI DAQmx docs for DAQmxBaseWriteAnalogF64()
std::vector< double > CNTRIN_double
Readings from ticks counters, such as quadrature encoders.
uint32_t bufferSamplesPerChannel
(Default=0) From NI&#39;s docs: The number of samples the buffer can hold for each channel in the task...
std::string line
The digital line (for example "Dev1/port0/line1")
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
unsigned __int64 uint64_t
Definition: rptypes.h:52
#define MRPT_DAQmxCreateAIVoltageChan
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::vector< double > AIN_double
Readings from analog input (ADCs) channels (vector length=channel count) in Volts.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp. Where available, this should contain the accurate satellite-based time...
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_ang_encoder_t ci_ang_encoder
Counter: uses an angular encoder to measure angular position.
uint32_t samplesPerChannelToRead
(Default=1000) The number of samples to grab at once from each channel.
std::vector< TaskDescription > task_definitions
Publicly accessible vector with the list of tasks to be launched upon call to CNationalInstrumentsDAQ...
void doProcess()
This method will be invoked at a minimum rate of "process_rate" (Hz)
std::auto_ptr< mrpt::synch::CPipeReadEndPoint > read_pipe
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ai_t ai
Analog inputs.
unsigned int physicalChannelCount
IMPORTANT This must be the total number of channels listed in "physicalChannel" (e.g. 1 for "Dev1/ao0")
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_lin_encoder_t ci_lin_encoder
Counter: uses a linear encoder to measure linear position.
#define ASSERT_(f)
#define MRPT_DAQmxCreateCOPulseChanFreq
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_pulse_width_t ci_pulse_width
Counter: measure the width of a digital pulse.
uint64_t read_uint64_t(const std::string &section, const std::string &name, uint64_t defaultValue, bool failIfNotFound=false) const
#define MRPT_DAQmx_ErrChk(functionCall)
unsigned int physicalChannelCount
IMPORTANT This must be the total number of channels listed in "physicalChannel" (e.g. 4 for "Dev1/ai0:3")
std::string BASE_IMPEXP trim(const std::string &str)
Removes leading and trailing spaces.
#define MRPT_DAQmxClearTask
double samplesPerSecond
Sample clock config: samples per second. Continuous (infinite) sampling is assumed.
std::vector< mrpt::obs::CObservationRawDAQPtr > m_nextObservations
A buffer for doProcess.
std::vector< uint8_t > DIN
Present output values for 16-bit analog output (DACs) channels (vector length=channel count) in volts...
bool BASE_IMPEXP strCmpI(const std::string &s1, const std::string &s2)
Return true if the two strings are equal (case insensitive)
unsigned __int32 uint32_t
Definition: rptypes.h:49
#define ASSERTMSG_(f, __ERROR_MSG)
void BASE_IMPEXP tokenize(const std::string &inString, const std::string &inDelimiters, std::deque< std::string > &outTokens, bool skipBlankTokens=true) MRPT_NO_THROWS
Tokenizes a string according to a set of delimiting characters.
#define MRPT_DAQmxReadDigitalU8
#define MRPT_DAQmxCfgSampClkTiming
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_co_pulses_t co_pulses
Output counter: digital pulses output.
#define MRPT_DAQmxCreateCICountEdgesChan
#define MRPT_DAQmxCreateTask
void BASE_IMPEXP joinThread(const TThreadHandle &threadHandle)
Waits until the given thread ends.
Definition: threads.cpp:190
static void createPipe(ReadPtr &outReadPipe, WritePtr &outWritePipe)
Creates a new pipe and returns the read & write end-points as newly allocated objects.
Definition: CPipe.h:131



Page generated by Doxygen 1.8.14 for MRPT 1.5.6 Git: 4c65e8431 Tue Apr 24 08:18:17 2018 +0200 at lun oct 28 01:35:26 CET 2019