RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
analogy_device.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 University of Bristol, UK
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #include <sstream>
20 
21 #include <analogy_device.h>
22 #include <debug.h>
23 #include <math.h>
24 
25 #define A4L_CHAN_AREF_GROUND 0x1;
26 #define A4L_CHAN_AREF_COMMON 0x2;
27 #define A4L_CHAN_AREF_DIFF 0x4;
28 #define A4L_CHAN_AREF_OTHER 0x8;
29 
30 using namespace DAQ;
31 
33  std::string name,
34  IO::channel_t* chan,
35  size_t size)
36  : DAQ::Device(name, chan, size)
37  , dsc(*d)
38 {
39  int err = 0;
40  a4l_sbinfo_t* sbinfo;
41  a4l_chinfo_t* chinfo;
42 
43  // We need to find each subdevice index manually since idx_*_subd often fails
44  // Go over all subdevices and save the indexes of the first AI, AO and DIO
45  int idx_ai = -1;
46  int idx_ao = -1;
47  int idx_dio = -1;
48  for (int i = 0; i < dsc.nb_subd; i++) {
49  err = a4l_get_subdinfo(&dsc, i, &sbinfo);
50  if (err != 0) {
51  ERROR_MSG(
52  "AnalogyDriver: a4l_get_subd_info failed, wrong subdevice index %i "
53  "(err=%d)\n",
54  i,
55  err);
56  }
57  // Assign subdevice index; save just the first device if many
58  if (((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_AI) && (idx_ai < 0))
59  idx_ai = i;
60  else if (((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_AO) && (idx_ao < 0))
61  idx_ao = i;
62  else if (((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_DIO)
63  && (idx_dio < 0)) {
64  idx_dio = i;
65  }
66  }
67 
68  // Get info about AI subdevice
69  err = a4l_get_subdinfo(&dsc, idx_ai, &sbinfo);
70  if ((err == 0) && ((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_AI)) {
71  subdevice[AI].id = idx_ai;
72  subdevice[AI].active = 0;
73  subdevice[AI].count = sbinfo->nb_chan;
74  subdevice[AI].chan = new channel_t[subdevice[AI].count];
75  if (!subdevice[AI].chan)
76  subdevice[AI].count = 0;
77  else
78  for (size_t i = 0; i < subdevice[AI].count; ++i) {
79  err = a4l_get_chinfo(&dsc, idx_ai, i, &chinfo);
80  // Something went wrong
81  if (err < 0) {
82  subdevice[AI].active = 0;
83  subdevice[AI].count = 0;
84  delete[] subdevice[AI].chan;
85  break;
86  }
87  subdevice[AI].chan[i].active = false;
88  subdevice[AI].chan[i].analog.maxdata = (1 << chinfo->nb_bits) - 1;
89  setAnalogGain(AI, i, 1.0);
90  setAnalogRange(AI, i, 0);
91  setAnalogZeroOffset(AI, i, 0);
92  setAnalogReference(AI, i, 0);
93  setAnalogUnits(AI, i, 0);
94  setAnalogDownsample(AI, i, 1);
95  setAnalogCounter(AI, i);
97  }
98  } else {
99  subdevice[AI].active = 0;
100  subdevice[AI].count = 0;
101  subdevice[AI].chan = NULL;
102  }
103 
104  // Get info about AO subdevice
105  err = a4l_get_subdinfo(&dsc, idx_ao, &sbinfo);
106  if ((err == 0) && ((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_AO)) {
107  subdevice[AO].id = idx_ao;
108  subdevice[AO].active = 0;
109  subdevice[AO].count = sbinfo->nb_chan;
110  subdevice[AO].chan = new channel_t[subdevice[AO].count];
111  if (!subdevice[AO].chan)
112  subdevice[AO].count = 0;
113  else
114  for (size_t i = 0; i < subdevice[AO].count; ++i) {
115  err = a4l_get_chinfo(&dsc, idx_ao, i, &chinfo);
116  // Something went wrong
117  if (err < 0) {
118  subdevice[AO].active = 0;
119  subdevice[AO].count = 0;
120  delete[] subdevice[AO].chan;
121  break;
122  }
123  subdevice[AO].chan[i].active = false;
124  subdevice[AO].chan[i].analog.maxdata = (1 << chinfo->nb_bits) - 1;
125  setAnalogGain(AO, i, 1.0);
126  setAnalogZeroOffset(AO, i, 0);
127  setAnalogRange(AO, i, 0);
128  setAnalogReference(AO, i, 0);
129  setAnalogUnits(AO, i, 0);
131  }
132  } else {
133  subdevice[AO].active = 0;
134  subdevice[AO].count = 0;
135  subdevice[AO].chan = NULL;
136  }
137 
138  // Get info about DIO subdevice and set to INPUT as default
139  // Then add all Digital I/O to INPUT list for the
140  // IO class to handle
141  err = a4l_get_subdinfo(&dsc, idx_dio, &sbinfo);
142  if ((err == 0) && ((sbinfo->flags & A4L_SUBD_TYPES) == A4L_SUBD_DIO)) {
143  subdevice[DIO].id = idx_dio;
144  subdevice[DIO].active = 0;
145  subdevice[DIO].count = sbinfo->nb_chan;
146  subdevice[DIO].chan = new channel_t[subdevice[DIO].count];
147  if (!subdevice[DIO].chan)
148  subdevice[DIO].count = 0;
149  else
150  for (size_t i = 0; i < subdevice[DIO].count; ++i) {
151  subdevice[DIO].chan[i].active = false;
152  subdevice[DIO].chan[i].digital.previous_value = 0;
154  }
155  } else {
156  subdevice[DIO].active = 0;
157  subdevice[DIO].count = 0;
158  subdevice[DIO].chan = NULL;
159  }
160  setActive(true);
161 }
162 
164 {
165  if (subdevice[AI].chan)
166  delete[] subdevice[AI].chan;
167  if (subdevice[AO].chan)
168  delete[] subdevice[AO].chan;
169  if (subdevice[DIO].chan)
170  delete[] subdevice[DIO].chan;
171  if (dsc.sbdata)
172  a4l_close(&dsc);
173 }
174 
175 bool AnalogyDevice::analog_exists(type_t type, index_t count) const
176 {
177  if ((type == AI && count < subdevice[AI].count)
178  || (type == AO && count < subdevice[AO].count))
179  return true;
180  return false;
181 }
182 
183 // Returns number of channels available for type
185 {
186  if (type != AI && type != AO && type != DIO)
187  return 0;
188 
189  return subdevice[type].count;
190 }
191 
193 {
194  if (channel >= getChannelCount(type))
195  return false;
196 
197  return subdevice[type].chan[channel].active;
198 }
199 
200 int AnalogyDevice::setChannelActive(type_t type, index_t channel, bool state)
201 {
202  if (channel >= getChannelCount(type))
203  return -EINVAL;
204 
205  if (type == AI)
206  output(channel) = 0.0;
207 
208  if (subdevice[type].chan[channel].active && !state)
209  --subdevice[type].active;
210  else if (!subdevice[type].chan[channel].active && state)
211  ++subdevice[type].active;
212 
213  subdevice[type].chan[channel].active = state;
214  return 0;
215 }
216 
218 {
219  if (!analog_exists(type, channel))
220  return 0;
221 
222  int err = 0;
223  a4l_chinfo_t* chinfo;
224  a4l_desc_t d = dsc; // Copy descriptor because method is const
225 
226  err = a4l_get_chinfo(&d, subdevice[type].id, channel, &chinfo);
227  if (err < 0)
228  return 0;
229 
230  return static_cast<index_t>(chinfo->nb_rng);
231 }
232 
234  index_t channel) const
235 {
236  if (!analog_exists(type, channel))
237  return 0;
238 
239  return 4;
240 }
241 
243 {
244  if (!analog_exists(type, channel))
245  return 0;
246 
247  return 2;
248 }
249 
251 {
252  if (!analog_exists(type, channel))
253  return 0;
254 
255  return subdevice[type].chan[channel].analog.downsample;
256 }
257 
259  index_t channel,
260  index_t index) const
261 {
262  if (!analog_exists(type, channel)
263  || !(index < getAnalogRangeCount(type, channel)))
264  return "";
265 
266  std::ostringstream rangeString;
267  int err = 0;
268  a4l_rnginfo_t* range;
269  a4l_desc_t d = dsc; // Copy descriptor because method is const
270 
271  err = a4l_get_rnginfo(&d, subdevice[type].id, channel, index, &range);
272  if (err < 0)
273  return "";
274 
275  rangeString << (double)range->min / 1000000 << " to "
276  << (double)range->max / 1000000;
277  return rangeString.str();
278 }
279 
281  index_t channel,
282  index_t index) const
283 {
284  if (!analog_exists(type, channel)
285  || !(index < getAnalogReferenceCount(type, channel)))
286  return "";
287 
288  switch (index) {
289  case 0:
290  return "Ground";
291  case 1:
292  return "Common";
293  case 2:
294  return "Differential";
295  case 3:
296  return "Other";
297  default:
298  return "";
299  }
300 }
301 
303  index_t channel,
304  index_t index) const
305 {
306  if (!analog_exists(type, channel)
307  || !(index < getAnalogUnitsCount(type, channel)))
308  return "";
309 
310  switch (index) {
311  case 0:
312  return "Volts";
313  case 1:
314  return "Amps";
315  default:
316  return "";
317  }
318 }
319 
321 {
322  if (!analog_exists(type, channel))
323  return 0 - 1;
324 
325  return subdevice[type].chan[channel].analog.range;
326 }
327 
329 {
330  if (!analog_exists(type, channel))
331  return 0 - 1;
332 
333  return subdevice[type].chan[channel].analog.reference;
334 }
335 
337 {
338  if (!analog_exists(type, channel))
339  return 0 - 1;
340 
341  return subdevice[type].chan[channel].analog.units;
342 }
343 
345 {
346  if (!analog_exists(type, channel))
347  return 0 - 1;
348 
349  return subdevice[type].chan[channel].analog.offsetunits;
350 }
351 
352 double AnalogyDevice::getAnalogGain(type_t type, index_t channel) const
353 {
354  if (!analog_exists(type, channel))
355  return 0;
356 
357  return subdevice[type].chan[channel].analog.gain;
358 }
359 
361 {
362  if (!analog_exists(type, channel))
363  return 0;
364 
365  return subdevice[type].chan[channel].analog.zerooffset;
366 }
367 
369 {
370  if (!analog_exists(type, channel)
371  || !(index < getAnalogRangeCount(type, channel)))
372  return -EINVAL;
373 
374  channel_t* chan = &subdevice[type].chan[channel];
375  int err = 0;
376  a4l_rnginfo_t* range;
377 
378  err = a4l_get_rnginfo(&dsc, subdevice[type].id, channel, index, &range);
379  if (err < 0)
380  return -EINVAL;
381 
382  chan->analog.range = index;
383  chan->analog.conv = (range->max - range->min) / 1e6 / chan->analog.maxdata;
384  chan->analog.offset = -range->min / chan->analog.conv / 1e6;
385 
386  /*
387  * Save ourselves an extra division each timestep in the fast path.
388  */
389  if (type == AO)
390  chan->analog.conv = 1 / chan->analog.conv;
391 
392  return 0;
393 }
394 
396  index_t channel,
397  index_t index)
398 {
399  if (!analog_exists(type, channel)
400  || !(index < getAnalogReferenceCount(type, channel)))
401  return -EINVAL;
402 
403  subdevice[type].chan[channel].analog.reference = index;
404  return 0;
405 }
406 
408 {
409  if (!analog_exists(type, channel)
410  || !(index < getAnalogUnitsCount(type, channel)))
411  return -EINVAL;
412 
413  subdevice[type].chan[channel].analog.units = index;
414  return 0;
415 }
416 
418  index_t channel,
419  index_t index)
420 {
421  if (!analog_exists(type, channel)
422  || !(index < getAnalogUnitsCount(type, channel)))
423  return -EINVAL;
424 
425  subdevice[type].chan[channel].analog.offsetunits = index;
426  return 0;
427 }
428 
430  index_t channel,
431  double offset)
432 {
433  if (!analog_exists(type, channel))
434  return -EINVAL;
435 
436  subdevice[type].chan[channel].analog.zerooffset = offset;
437  return 0;
438 }
439 
440 int AnalogyDevice::setAnalogGain(type_t type, index_t channel, double gain)
441 {
442  if (!analog_exists(type, channel))
443  return -EINVAL;
444 
445  subdevice[type].chan[channel].analog.gain = gain;
446  return 0;
447 }
448 
450  index_t channel,
451  double value)
452 {
453  if (!analog_exists(type, channel))
454  return -EINVAL;
455 
456  subdevice[type].chan[channel].analog.calOffset = value;
457  return 0;
458 }
459 
461  index_t channel) const
462 {
463  if (!analog_exists(type, channel))
464  return -EINVAL;
465 
466  return subdevice[type].chan[channel].analog.calOffset;
467 }
468 
470  index_t channel,
471  size_t downsample_rate)
472 {
473  if (!analog_exists(type, channel))
474  return -EINVAL;
475 
476  subdevice[type].chan[channel].analog.downsample = downsample_rate;
477  return 0;
478 }
479 
481 {
482  if (!analog_exists(type, channel))
483  return -EINVAL;
484 
485  subdevice[type].chan[channel].analog.counter = 0;
486  return 0;
487 }
488 
489 // Return the direction of the selected digital channel
491 {
492  if (channel >= subdevice[DIO].count)
493  return DAQ::INPUT;
494 
495  return subdevice[DIO].chan[channel].digital.direction;
496 }
497 
498 // Enable digital channel with specific direction
500 {
501  if (channel >= subdevice[DIO].count)
502  return -EINVAL;
503 
504  subdevice[DIO].chan[channel].digital.direction = direction;
505 
506  if (direction == DAQ::INPUT)
507  return a4l_config_subd(
508  &dsc, subdevice[DIO].id, A4L_INSN_CONFIG_DIO_INPUT, channel);
509  else if (direction == DAQ::OUTPUT)
510  return a4l_config_subd(
511  &dsc, subdevice[DIO].id, A4L_INSN_CONFIG_DIO_OUTPUT, channel);
512 
513  return -EINVAL;
514 }
515 
516 // Acquire data
518 {
519  lsampl_t sample = 0;
520  double value = 0;
521  int ref = 0;
522  int size = 0;
523  analog_channel_t* channel;
524  a4l_chinfo_t* chinfo;
525  a4l_rnginfo_t* rnginfo;
526  int err = 0;
527 
528  for (size_t i = 0; i < subdevice[AI].count; ++i)
529  if (subdevice[AI].chan[i].active) {
530  channel = &subdevice[AI].chan[i].analog;
531  if (!channel->counter++) {
532  // Get analogy reference
533  switch (channel->reference) {
534  case 0:
535  ref = AREF_GROUND;
536  break;
537  case 1:
538  ref = AREF_COMMON;
539  break;
540  case 2:
541  ref = AREF_DIFF;
542  break;
543  case 3:
544  ref = AREF_OTHER;
545  break;
546  }
547 
548  // Get channel info
549  err = a4l_get_chinfo(&dsc, subdevice[AI].id, i, &chinfo);
550  if (err < 0)
551  rt_fprintf(
552  stderr, "analogy_device::read::a4l_get_chinfo error: %d\n", err);
553 
554  // Get channel range info
555  err = a4l_get_rnginfo(
556  &dsc, subdevice[AI].id, i, channel->range, &rnginfo);
557  if (err < 0)
558  rt_fprintf(
559  stderr, "analogy_device::read::a4l_get_rnginfo error: %d\n", err);
560  size = a4l_sizeof_chan(chinfo);
561 
562  // Read 1 data sample via synchronous acq
563  err = a4l_sync_read(&dsc,
564  subdevice[AI].id,
565  PACK(i, channel->range, ref),
566  0,
567  &sample,
568  size);
569  if (err < 0)
570  rt_fprintf(
571  stderr, "analogy_device::read::a4l_sync_read error: %d\n", err);
572 
573  // Convert to decimal via a4l
574  err = a4l_rawtod(chinfo, rnginfo, &value, &sample, 1);
575  if (err < 0)
576  rt_fprintf(
577  stderr, "analogy_device::read::a4l_rawtod error: %d\n", err);
578 
579  // Gain, convert, and push into IO pipe
580  output(i) =
581  channel->gain * value + channel->zerooffset - channel->calOffset;
582  }
583  channel->counter %= channel->downsample;
584  }
585 
586  size_t offset = getChannelCount(AI);
587  unsigned int data = 0, mask = 0;
588 
589  // Create mask using only enabled digital channels
590  for (size_t i = 0; i < subdevice[DIO].count; ++i)
591  if (subdevice[DIO].chan[i].active
592  && subdevice[DIO].chan[i].digital.direction == DAQ::INPUT)
593  mask |= (1 << i);
594 
595  // Read all data and output it according to channel activity
596  err = a4l_sync_dio(&dsc, subdevice[DIO].id, &mask, &data);
597  if (err < 0)
598  rt_fprintf(stderr, "analogy_device::read::a4l_sync_dio error: %d\n", err);
599 
600  // Read only enabled digital channels one by one with mask for each bit
601  for (size_t i = 0; i < subdevice[DIO].count; ++i)
602  if (subdevice[DIO].chan[i].active
603  && subdevice[DIO].chan[i].digital.direction == DAQ::INPUT)
604  {
605  mask = (1 << i);
606  output(i + offset) = (data & mask) == 0 ? 0 : 5;
607  }
608 }
609 
611 {
612  {
613  double value;
614  lsampl_t sample;
615  analog_channel_t* channel;
616  int ref = 0;
617  int size = 0;
618  a4l_chinfo_t* chinfo;
619  int err = 0;
620 
621  for (size_t i = 0; i < subdevice[AO].count; ++i)
622  if (subdevice[AO].chan[i].active) {
623  channel = &subdevice[AO].chan[i].analog;
624  value = round(channel->gain * channel->conv
625  * (input(i) - channel->zerooffset)
626  + channel->offset - channel->calOffset);
627 
628  // Prevent wrap around in the data units.
629  if (value > channel->maxdata)
630  value = channel->maxdata;
631  else if (value < 0.0)
632  value = 0.0;
633  sample = static_cast<lsampl_t>(value);
634 
635  // Get anaolgy reference
636  switch (channel->reference) {
637  case 0:
638  ref = A4L_CHAN_AREF_GROUND;
639  break;
640  case 1:
641  ref = A4L_CHAN_AREF_COMMON;
642  break;
643  case 2:
644  ref = A4L_CHAN_AREF_DIFF;
645  break;
646  case 3:
647  ref = A4L_CHAN_AREF_OTHER;
648  break;
649  }
650  // Get channel size
651  err = a4l_get_chinfo(&dsc, subdevice[AO].id, i, &chinfo);
652  if (err < 0)
653  rt_fprintf(
654  stderr, "analogy_device::write::a4l_get_chinfo error: %d\n", err);
655  size = a4l_sizeof_chan(chinfo);
656 
657  // Write sample
658  err = a4l_sync_write(&dsc,
659  subdevice[AO].id,
660  PACK(i, channel->range, ref),
661  0,
662  &sample,
663  size);
664  if (err < 0)
665  rt_fprintf(
666  stderr, "analogy_device::read::a4l_sync_write error: %d\n", err);
667  }
668  }
669  {
670  size_t offset = getChannelCount(AO);
671  int value = 0;
672  unsigned int data = 0, mask = 0;
673 
674  // Create mask and data buffer with bits to be set
675  for (size_t i = 0; i < subdevice[DIO].count; ++i) {
676  value = input(i + offset) != 0.0;
677  if (subdevice[DIO].chan[i].active
678  && subdevice[DIO].chan[i].digital.direction == DAQ::OUTPUT
679  && subdevice[DIO].chan[i].digital.previous_value != value)
680  {
681  subdevice[DIO].chan[i].digital.previous_value = value;
682  data |= value == 0
683  ? (0 << i)
684  : (1 << i); // Toggle the i-th bit for modification (set 0 or 1)
685  mask |= (1 << i); // Set i-th bit to specify channels to modify
686  }
687  }
688  // Write the data according to the mask
689  if (mask)
690  a4l_sync_dio(&dsc, subdevice[DIO].id, &mask, &data);
691  }
692 }
693 
694 void AnalogyDevice::doLoad(const Settings::Object::State& s)
695 {
696  for (size_t i = 0; i < subdevice[AI].count
697  && i < static_cast<size_t>(s.loadInteger("AI Count"));
698  ++i)
699  {
700  std::ostringstream str;
701  str << i;
702  setChannelActive(AI, i, s.loadInteger(str.str() + " AI Active"));
703  setAnalogRange(AI, i, s.loadInteger(str.str() + " AI Range"));
704  setAnalogReference(AI, i, s.loadInteger(str.str() + " AI Reference"));
705  setAnalogUnits(AI, i, s.loadInteger(str.str() + " AI Units"));
706  setAnalogGain(AI, i, s.loadDouble(str.str() + " AI Gain"));
707  setAnalogZeroOffset(AI, i, s.loadDouble(str.str() + " AI Zero Offset"));
708  if (s.loadDouble(str.str() + " AI Calibration Value"))
710  AI, i, s.loadDouble(str.str() + " AI Calibration Value"));
711  if (s.loadInteger(str.str() + " AI Downsample"))
712  setAnalogDownsample(AI, i, s.loadInteger(str.str() + " AI Downsample"));
713  }
714 
715  for (size_t i = 0; i < subdevice[AO].count
716  && i < static_cast<size_t>(s.loadInteger("AO Count"));
717  ++i)
718  {
719  std::ostringstream str;
720  str << i;
721  setChannelActive(AO, i, s.loadInteger(str.str() + " AO Active"));
722  setAnalogRange(AO, i, s.loadInteger(str.str() + " AO Range"));
723  setAnalogReference(AO, i, s.loadInteger(str.str() + " AO Reference"));
724  setAnalogUnits(AO, i, s.loadInteger(str.str() + " AO Units"));
725  setAnalogGain(AO, i, s.loadDouble(str.str() + " AO Gain"));
726  setAnalogZeroOffset(AO, i, s.loadDouble(str.str() + " AO Zero Offset"));
727  if (s.loadDouble(str.str() + " AO Calibration Value"))
729  AO, i, s.loadDouble(str.str() + " AO Calibration Value"));
730  }
731 
732  for (size_t i = 0; i < subdevice[DIO].count
733  && i < static_cast<size_t>(s.loadInteger("DIO Count"));
734  ++i)
735  {
736  std::ostringstream str;
737  str << i;
738  setChannelActive(DIO, i, s.loadInteger(str.str() + " DIO Active"));
740  static_cast<DAQ::direction_t>(
741  s.loadInteger(str.str() + " DIO Direction")));
742  }
743 }
744 
745 void AnalogyDevice::doSave(Settings::Object::State& s) const
746 {
747  s.saveInteger("AI Count", subdevice[AI].count);
748  for (size_t i = 0; i < subdevice[AI].count; ++i) {
749  std::ostringstream str;
750  str << i;
751  s.saveInteger(str.str() + " AI Active", getChannelActive(AI, i));
752  s.saveDouble(str.str() + " AI Calibration Value",
754  s.saveInteger(str.str() + " AI Range", getAnalogRange(AI, i));
755  s.saveInteger(str.str() + " AI Reference", getAnalogReference(AI, i));
756  s.saveInteger(str.str() + " AI Units", getAnalogUnits(AI, i));
757  s.saveDouble(str.str() + " AI Gain", getAnalogGain(AI, i));
758  s.saveDouble(str.str() + " AI Zero Offset", getAnalogZeroOffset(AI, i));
759  s.saveInteger(str.str() + " AI Downsample", getAnalogDownsample(AI, i));
760  }
761 
762  s.saveInteger("AO Count", subdevice[AO].count);
763  for (size_t i = 0; i < subdevice[AO].count; ++i) {
764  std::ostringstream str;
765  str << i;
766  s.saveInteger(str.str() + " AO Active", getChannelActive(AO, i));
767  s.saveDouble(str.str() + " AO Calibration Value",
769  s.saveInteger(str.str() + " AO Range", getAnalogRange(AO, i));
770  s.saveInteger(str.str() + " AO Reference", getAnalogReference(AO, i));
771  s.saveInteger(str.str() + " AO Units", getAnalogUnits(AO, i));
772  s.saveDouble(str.str() + " AO Gain", getAnalogGain(AO, i));
773  s.saveDouble(str.str() + " AO Zero Offset", getAnalogZeroOffset(AO, i));
774  }
775 
776  s.saveInteger("DIO Count", subdevice[DIO].count);
777  for (size_t i = 0; i < subdevice[DIO].count; ++i) {
778  std::ostringstream str;
779  str << i;
780  s.saveInteger(str.str() + " DIO Active", getChannelActive(DIO, i));
781  s.saveInteger(str.str() + " DIO Direction",
782  subdevice[DIO].chan[i].digital.direction);
783  }
784 }
#define A4L_CHAN_AREF_COMMON
#define A4L_CHAN_AREF_DIFF
#define A4L_CHAN_AREF_GROUND
#define A4L_CHAN_AREF_OTHER
int setAnalogCounter(DAQ::type_t, DAQ::index_t)
size_t getAnalogUnitsCount(DAQ::type_t, DAQ::index_t) const
std::string getAnalogRangeString(DAQ::type_t, DAQ::index_t, DAQ::index_t) const
int setAnalogGain(DAQ::type_t, DAQ::index_t, double)
int setAnalogUnits(DAQ::type_t, DAQ::index_t, DAQ::index_t)
AnalogyDevice(a4l_desc_t *, std::string, IO::channel_t *, size_t)
int setAnalogZeroOffset(DAQ::type_t, DAQ::index_t, double)
void write(void)
double getAnalogCalibrationValue(DAQ::type_t, DAQ::index_t) const
int setAnalogDownsample(DAQ::type_t, DAQ::index_t, size_t)
double getAnalogZeroOffset(DAQ::type_t, DAQ::index_t) const
int setDigitalDirection(DAQ::index_t, DAQ::direction_t)
double getAnalogGain(DAQ::type_t, DAQ::index_t) const
std::string getAnalogReferenceString(DAQ::type_t, DAQ::index_t, DAQ::index_t) const
virtual void doSave(Settings::Object::State &) const
virtual void doLoad(const Settings::Object::State &)
DAQ::index_t getAnalogRange(DAQ::type_t, DAQ::index_t) const
size_t getChannelCount(DAQ::type_t) const
bool getChannelActive(DAQ::type_t, DAQ::index_t) const
size_t getAnalogDownsample(DAQ::type_t, DAQ::index_t) const
std::string getAnalogUnitsString(DAQ::type_t, DAQ::index_t, DAQ::index_t) const
DAQ::direction_t getDigitalDirection(DAQ::index_t) const
int setAnalogReference(DAQ::type_t, DAQ::index_t, DAQ::index_t)
int setAnalogCalibrationValue(DAQ::type_t, DAQ::index_t, double)
size_t getAnalogReferenceCount(DAQ::type_t, DAQ::index_t) const
size_t getAnalogRangeCount(DAQ::type_t, DAQ::index_t) const
int setChannelActive(DAQ::type_t, DAQ::index_t, bool)
DAQ::index_t getAnalogReference(DAQ::type_t, DAQ::index_t) const
int setAnalogOffsetUnits(DAQ::type_t, DAQ::index_t, DAQ::index_t)
int setAnalogRange(DAQ::type_t, DAQ::index_t, DAQ::index_t)
DAQ::index_t getAnalogOffsetUnits(DAQ::type_t, DAQ::index_t) const
DAQ::index_t getAnalogUnits(DAQ::type_t, DAQ::index_t) const
void setActive(bool act)
Definition: io.hpp:188
void ERROR_MSG(const std::string &errmsg, Args... args)
Definition: debug.hpp:36
DAQ Oriented Classes.
Definition: daq.hpp:37
uint64_t index_t
Definition: daq.hpp:82
direction_t
Definition: daq.hpp:93
@ INPUT
Definition: daq.hpp:94
@ OUTPUT
Definition: daq.hpp:95
struct IO::channel_t channel_t
struct Oscilloscope::sample sample