1 # Copyright (C) 2011-2012 W. Trevor King <wking@tremily.us>
3 # This file is part of pycomedi.
5 # pycomedi is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 2 of the License, or (at your option) any later
10 # pycomedi is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along with
15 # pycomedi. If not, see <http://www.gnu.org/licenses/>.
17 """Enums and flags are bundled into class instances for easier browsing
19 >>> SUBDEVICE_TYPE # doctest: +NORMALIZE_WHITESPACE
20 [<_NamedInt unused>, <_NamedInt ai>, <_NamedInt ao>, <_NamedInt di>,
21 <_NamedInt do>, <_NamedInt dio>, <_NamedInt counter>, <_NamedInt timer>,
22 <_NamedInt memory>, <_NamedInt calib>, <_NamedInt proc>, <_NamedInt serial>,
24 >>> SUBDEVICE_TYPE.dio
26 >>> SUBDEVICE_TYPE.dio.value == _comedi.COMEDI_SUBD_DIO
28 >>> SUBDEVICE_TYPE.dio.doc
29 'COMEDI_SUBD_DIO (digital input/output)'
31 You can also search by name or value.
33 >>> TRIG_SRC.index_by_name('timer')
35 >>> TRIG_SRC.index_by_value(_comedi.TRIG_NOW)
38 Some flags have constants for setting or clearing all the flags at once.
40 >>> TRIG_SRC # doctest: +NORMALIZE_WHITESPACE
41 [<_NamedInt none>, <_NamedInt now>, <_NamedInt follow>, <_NamedInt time>,
42 <_NamedInt timer>, <_NamedInt count>, <_NamedInt ext>, <_NamedInt int>,
49 Flag instances have a special wrapper that stores their value.
51 >>> f = FlagValue(SDF, 17)
52 >>> f.flag # doctest: +ELLIPSIS
53 [<_NamedInt busy>, <_NamedInt busy_owner>, ...]
60 You can treat named integers as Python integers with bitwise operations,
62 >>> a = TRIG_SRC.now | TRIG_SRC.follow | TRIG_SRC.time | 64
67 >>> TRIG_SRC.none & TRIG_SRC.now
70 Because of the way Python operator overloading works [#ops]_, you can
71 also start a bitwise chain with an integer.
76 Rich comparisons with other flags and integers are also supported.
87 >>> TRIG_SRC.now == copy.deepcopy(TRIG_SRC.now)
89 >>> TRIG_SRC.now != TRIG_SRC.now
95 >>> TRIG_SRC.now > None
98 The ``UNIT`` constant treats ``RF_EXTERNAL`` as a full-fledged unit:
100 >>> UNIT.index_by_name('external')
102 >>> UNIT.index_by_value(_comedi.RF_EXTERNAL)
105 .. [#ops] See `emulating numeric types`_ and `NotImplementedError` in
106 `the standard type hierarchy`_.
108 .. _emulating numeric types:
109 http://docs.python.org/reference/datamodel.html#emulating-numeric-types
110 .. _the standard type hierarchy`_
111 http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy
114 from math import log as _log
117 import numpy as _numpy
118 import comedi as _comedi
120 from pycomedi import LOG as _LOG
123 def bitwise_value(object):
124 """Convenience function for flexible value specification
126 This funciton makes it easy for functions and methods to accept
127 either integers or `BitwiseOperator` instances as integer
130 if isinstance(object, BitwiseOperator):
136 """External definition of staticmethod until Cython supports the
139 http://docs.cython.org/src/userguide/limitations.html#behaviour-of-class-scopes
141 if isinstance(s, BitwiseOperator):
143 if isinstance(o, BitwiseOperator):
145 return (long(s), long(o))
148 cdef class BitwiseOperator (object):
149 """General class for bitwise operations.
151 This class allows chaining bitwise operations between
152 `_NamedInt`\s and similar objects.
154 Because flag values can be large, we cast all values to longs
155 before performing any bitwise operations. This avoids issues like
157 >>> int.__or__(1073741824, 2147483648L)
161 def __init__(self, value):
165 return self.__repr__()
168 return '<%s %s>' % (self.__class__.__name__, self.value)
170 _prepare_self_other = staticmethod(_pso)
172 def __and__(self, other):
173 "Bitwise and acts on `BitwiseOperator.value`."
174 s,o = BitwiseOperator._prepare_self_other(self, other)
175 return BitwiseOperator(int(long.__and__(s, o)))
177 def __or__(self, other):
178 "Bitwise or acts on `BitwiseOperator.value`."
179 s,o = BitwiseOperator._prepare_self_other(self, other)
180 return BitwiseOperator(int(long.__or__(s, o)))
182 def __richcmp__(self, other, op):
184 other = self.value - 1
185 s,o = BitwiseOperator._prepare_self_other(self, other)
201 def __reduce__(self):
202 return (BitwiseOperator, (self.value,))
205 class _NamedInt (BitwiseOperator):
206 "A flag or enum item."
207 def __init__(self, name, value, doc=None):
208 super(_NamedInt, self).__init__(value)
216 return '<%s %s>' % (self.__class__.__name__, self.name)
218 def __reduce__(self):
219 return (_NamedInt, (self.name, self.value, self.doc))
224 def __init__(self, name, prefix='', blacklist=None, whitelist=None,
226 super(_Enum, self).__init__()
228 if blacklist == None:
230 if translation == None:
233 self._value_keys = {}
234 for attr in dir(_comedi):
235 if attr.startswith(prefix):
236 item_name = self._item_name(attr, prefix, translation)
237 if self._is_ignored(item_name, blacklist, whitelist):
239 self._add_item(attr, item_name)
240 self.sort(key=lambda item: item.value)
242 def _item_name(self, attr, prefix, translation):
243 item_name = attr[len(prefix):]
244 if item_name in translation:
245 return translation[item_name]
247 return item_name.lower()
249 def _is_ignored(self, item_name, blacklist, whitelist):
250 return (item_name in blacklist
251 or whitelist != None and item_name not in whitelist)
253 def _add_item(self, attr, item_name):
254 item_value = getattr(_comedi, attr)
256 _LOG.debug('big value for {0:s}: {1:d} ({1:b}) converted to {2:d} ({2:b})'.format(
257 attr, item_value, (1<<32) + item_value))
258 item_value = (1<<32) + item_value # flags are unsigned 32 bit integers, but SWIG signs them
259 item = _NamedInt(item_name, item_value, doc=attr)
262 def append(self, item):
263 super(_Enum, self).append(item)
264 self._name_keys[item.name] = item
265 if item.value in self._value_keys and item.name:
266 raise ValueError('value collision in %s: %s = %s = %#x'
267 % (self.name, item.name,
268 self._value_keys[item.value], item.value))
269 self._value_keys[item.value] = item
270 setattr(self, item.name, item)
272 def index_by_name(self, name):
273 return self._name_keys[name]
275 def index_by_value(self, value):
276 return self._value_keys[value]
281 def __init__(self, *args, **kwargs):
282 super(_Flag, self).__init__(*args, **kwargs)
288 elif flag.value < 0 or abs(_log(flag.value, 2)) % 1 > 1e-13: # deal with rounding errors
291 'mutliple multi-bit flags in %s: %s = %#x and %s = %#x'
292 % (self.name, self._all.name, self._all.value,
293 flag.name, flag.value))
296 self.remove(self._empty)
298 self.remove(self._all)
300 def get(self, value, name):
301 flag = getattr(self, name)
302 assert flag.value != 0, '%s: %s' % (self.name, flag)
303 return value & flag.value == flag.value
305 def set(self, value, name, status):
306 flag = getattr(self, name)
308 return value | flag.value
309 return (value | flag.value) - flag.value
312 class FlagValue (object):
313 """A flag instance (flag + value)
318 >>> f = FlagValue(flag=TRIG_SRC, value=0, default='empty')
329 def __init__(self, flag, value, default='-'):
332 self._default = default
335 flags = [f for f in self.flag if getattr(self, f.name)]
338 return '|'.join([f.name for f in flags])
340 def __getattr__(self, name):
341 return self.flag.get(self._value, name)
343 def __setattr__(self, name, value):
344 if name != 'flag' and not name.startswith('_'):
345 value = self.flag.set(self._value, name, value)
347 super(FlagValue, self).__setattr__(name, value)
350 # blacklist deprecated values (and those belonging to other _Enums or _Flags)
352 CR = _Flag('ChanSpec flags', 'CR_', blacklist=['dither', 'deglitch'])
353 CR.alt_filter.doc += ' (can also mean "dither" or "deglitch")'
355 AREF = _Enum('analog_reference', 'AREF_')
356 AREF.diff.doc += ' (differential)'
357 AREF.other.doc += ' (other / undefined)'
359 #GPCT = _Flag('general_purpose_counter_timer', 'GPCT_')
360 # Two competing flag sets? Need some documentation.
362 INSN_MASK = _Flag('instruction_mask', 'INSN_MASK_')
364 CONFIGURATION_IDS = _Enum('configuration_ids', 'INSN_CONFIG_', blacklist=[
367 INSN = _Enum('instruction', 'INSN_',
368 blacklist=['mask_%s' % i.name for i in INSN_MASK] + [
369 'config_%s' % i.name for i in CONFIGURATION_IDS])
371 TRIG = _Flag('trigger_flags', 'TRIG_', whitelist=[
372 'bogus', 'dither', 'deglitch', 'config', 'wake_eos'])
373 TRIG.bogus.doc += ' (do the motions)'
374 TRIG.config.doc += ' (perform configuration, not triggering)'
375 TRIG.wake_eos.doc += ' (wake up on end-of-scan events)'
377 CMDF = _Flag('command_flags', 'CMDF_')
378 CMDF.priority.doc += (
379 ' (try to use a real-time interrupt while performing command)')
381 EV = _Flag('??', 'COMEDI_EV_')
383 TRIG_ROUND = _Enum('trigger_round', 'TRIG_ROUND_', blacklist=['mask'])
384 TRIG_ROUND.mask = _comedi.TRIG_ROUND_MASK
386 TRIG_SRC = _Flag('trigger_source_flags', 'TRIG_',
387 blacklist=[i.name for i in TRIG] + [
388 'round_%s' % i.name for i in TRIG_ROUND] + [
389 'round_mask', 'rt', 'write'])
390 TRIG_SRC.none.doc += ' (never trigger)'
391 TRIG_SRC.now.doc += ' (trigger now + N ns)'
392 TRIG_SRC.follow.doc += ' (trigger on next lower level trig)'
393 TRIG_SRC.time.doc += ' (trigger at time N ns)'
394 TRIG_SRC.timer.doc += ' (trigger at rate N ns)'
395 TRIG_SRC.count.doc += ' (trigger when count reaches N)'
396 TRIG_SRC.ext.doc += ' (trigger on external signal N)'
397 TRIG_SRC.int.doc += ' (trigger on comedi-internal signal N)'
398 TRIG_SRC.other.doc += ' (driver defined)'
400 SDF_PWM = _Flag('pulse_width_modulation_subdevice_flags', 'SDF_PWM_')
401 SDF_PWM.counter.doc += ' (PWM can automatically switch off)'
402 SDF_PWM.hbridge.doc += ' (PWM is signed (H-bridge))'
404 SDF = _Flag('subdevice_flags', 'SDF_', blacklist=[
405 'pwm_%s' % i.name for i in SDF_PWM] + [
406 'cmd', 'writeable', 'rt'])
407 SDF.busy.doc += ' (device is busy)'
408 SDF.busy_owner.doc += ' (device is busy with your job)'
409 SDF.locked.doc += ' (subdevice is locked)'
410 SDF.lock_owner.doc += ' (you own lock)'
411 SDF.maxdata.doc += ' (maxdata depends on channel)'
412 SDF.flags.doc += ' (flags depend on channel (BROKEN))'
413 SDF.rangetype.doc += ' (range type depends on channel)'
414 SDF.soft_calibrated.doc += ' (subdevice uses software calibration)'
415 SDF.cmd_write.doc += ' (can do output commands)'
416 SDF.cmd_read.doc += ' (can to input commands)'
417 SDF.readable.doc += ' (subdevice can be read, e.g. analog input)'
418 SDF.writable.doc += ' (subdevice can be written, e.g. analog output)'
419 SDF.internal.doc += ' (subdevice does not have externally visible lines)'
420 SDF.ground.doc += ' (can do aref=ground)'
421 SDF.common.doc += ' (can do aref=common)'
422 SDF.diff.doc += ' (can do aref=diff)'
423 SDF.other.doc += ' (can do aref=other)'
424 SDF.dither.doc += ' (can do dithering)'
425 SDF.deglitch.doc += ' (can do deglitching)'
426 SDF.mmap.doc += ' (can do mmap())'
427 SDF.running.doc += ' (subdevice is acquiring data)'
428 SDF.lsampl.doc += ' (subdevice uses 32-bit samples)'
429 SDF.packed.doc += ' (subdevice can do packed DIO)'
431 SUBDEVICE_TYPE = _Enum('subdevice_type', 'COMEDI_SUBD_')
432 SUBDEVICE_TYPE.unused.doc += ' (unused by driver)'
433 SUBDEVICE_TYPE.ai.doc += ' (analog input)'
434 SUBDEVICE_TYPE.ao.doc += ' (analog output)'
435 SUBDEVICE_TYPE.di.doc += ' (digital input)'
436 SUBDEVICE_TYPE.do.doc += ' (digital output)'
437 SUBDEVICE_TYPE.dio.doc += ' (digital input/output)'
438 SUBDEVICE_TYPE.memory.doc += ' (memory, EEPROM, DPRAM)'
439 SUBDEVICE_TYPE.calib.doc += ' (calibration DACs)'
440 SUBDEVICE_TYPE.proc.doc += ' (processor, DSP)'
441 SUBDEVICE_TYPE.serial.doc += ' (serial IO)'
442 SUBDEVICE_TYPE.pwm.doc += ' (pulse-with modulation)'
444 IO_DIRECTION = _Enum('io_direction', 'COMEDI_', whitelist=[
445 'input', 'output', 'opendrain'])
447 SUPPORT_LEVEL = _Enum('support_level', 'COMEDI_', whitelist=[
448 'unknown_support', 'supported', 'unsupported'])
450 UNIT = _Enum('unit', 'UNIT_', translation={'mA':'mA'})
451 # The mA translation avoids lowercasing to 'ma'.
452 UNIT.append(_NamedInt(
454 value=_comedi.RF_EXTERNAL,
455 doc=('RF_EXTERNAL (value unit is defined by an external reference '
458 CALLBACK = _Enum('callback_flags', 'COMEDI_CB_', blacklist=['block', 'eobuf'])
459 CALLBACK.eos.doc += ' (end of scan)'
460 CALLBACK.eoa.doc += ' (end of acquisition)'
461 CALLBACK.error.doc += ' (card error during acquisition)'
462 CALLBACK.overflow.doc += ' (buffer overflow/underflow)'
464 CONVERSION_DIRECTION = _Enum('conversion_direction', 'COMEDI_', whitelist=[
465 'to_physical', 'from_physical'])
467 # The following constants aren't declared in comedi.h or comedilib.h,
468 # but they should be.
470 LOGLEVEL = _Enum('log level', '', whitelist=[''])
471 LOGLEVEL.append(_NamedInt('silent', 0, doc='Comedilib prints nothing.'))
472 LOGLEVEL.append(_NamedInt('bug', 1, doc=(
473 'Comedilib prints error messages when there is a self-consistency '
474 'error (i.e., an internal bug (default).')))
475 LOGLEVEL.append(_NamedInt('invalid', 2, doc=(
476 'Comedilib prints an error message when an invalid parameter is '
478 LOGLEVEL.append(_NamedInt('error', 3, doc=(
479 'Comedilib prints an error message whenever an error is generated '
480 'in the Comedilib library or in the C library, when called by '
482 LOGLEVEL.append(_NamedInt('debug', 4, doc='Comedilib prints a lot of junk.'))