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 . 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 = {}
235 if hasattr(mod, 'wrapped'):
237 if prefix.startswith('COMEDI_'):
238 prefix = prefix[len('COMEDI_'):]
239 for attr in dir(mod):
240 if attr.startswith(prefix):
241 item_name = self._item_name(attr, prefix, translation)
242 if self._is_ignored(item_name, blacklist, whitelist):
244 self._add_item(attr, item_name)
245 self.sort(key=lambda item: item.value)
247 def _item_name(self, attr, prefix, translation):
248 item_name = attr[len(prefix):]
249 if item_name in translation:
250 return translation[item_name]
252 return item_name.lower()
254 def _is_ignored(self, item_name, blacklist, whitelist):
255 return (item_name in blacklist
256 or whitelist != None and item_name not in whitelist)
258 def _add_item(self, attr, item_name):
259 item_value = getattr(_comedi, attr)
260 if not isinstance(item_value, int):
261 return # item_name collided with another object, skip this non-int
263 _LOG.debug('big value for {0:s}: {1:d} ({1:b}) converted to {2:d} ({2:b})'.format(
264 attr, item_value, (1<<32) + item_value))
265 item_value = (1<<32) + item_value # flags are unsigned 32 bit integers, but SWIG signs them
266 item = _NamedInt(item_name, item_value, doc=attr)
269 def append(self, item):
270 super(_Enum, self).append(item)
271 self._name_keys[item.name] = item
272 if item.value in self._value_keys and item.name:
273 raise ValueError('value collision in %s: %s = %s = %#x'
274 % (self.name, item.name,
275 self._value_keys[item.value], item.value))
276 self._value_keys[item.value] = item
277 setattr(self, item.name, item)
279 def index_by_name(self, name):
280 return self._name_keys[name]
282 def index_by_value(self, value):
283 return self._value_keys[value]
288 def __init__(self, *args, **kwargs):
289 super(_Flag, self).__init__(*args, **kwargs)
295 elif flag.value < 0 or abs(_log(flag.value, 2)) % 1 > 1e-13: # deal with rounding errors
298 'mutliple multi-bit flags in %s: %s = %#x and %s = %#x'
299 % (self.name, self._all.name, self._all.value,
300 flag.name, flag.value))
303 self.remove(self._empty)
305 self.remove(self._all)
307 def get(self, value, name):
308 flag = getattr(self, name)
309 assert flag.value != 0, '%s: %s' % (self.name, flag)
310 return value & flag.value == flag.value
312 def set(self, value, name, status):
313 flag = getattr(self, name)
315 return value | flag.value
316 return (value | flag.value) - flag.value
319 class FlagValue (object):
320 """A flag instance (flag + value)
325 >>> f = FlagValue(flag=TRIG_SRC, value=0, default='empty')
336 def __init__(self, flag, value, default='-'):
339 self._default = default
342 flags = [f for f in self.flag if getattr(self, f.name)]
345 return '|'.join([f.name for f in flags])
347 def __getattr__(self, name):
348 return self.flag.get(self._value, name)
350 def __setattr__(self, name, value):
351 if name != 'flag' and not name.startswith('_'):
352 value = self.flag.set(self._value, name, value)
354 super(FlagValue, self).__setattr__(name, value)
357 # blacklist deprecated values (and those belonging to other _Enums or _Flags)
359 CR = _Flag('ChanSpec flags', 'CR_', blacklist=['dither', 'deglitch'])
360 CR.alt_filter.doc += ' (can also mean "dither" or "deglitch")'
362 AREF = _Enum('analog_reference', 'AREF_')
363 AREF.diff.doc += ' (differential)'
364 AREF.other.doc += ' (other / undefined)'
366 #GPCT = _Flag('general_purpose_counter_timer', 'GPCT_')
367 # Two competing flag sets? Need some documentation.
369 INSN_MASK = _Flag('instruction_mask', 'INSN_MASK_')
371 CONFIGURATION_IDS = _Enum('configuration_ids', 'INSN_CONFIG_', blacklist=[
374 INSN = _Enum('instruction', 'INSN_',
375 blacklist=['mask_%s' % i.name for i in INSN_MASK] + [
376 'config_%s' % i.name for i in CONFIGURATION_IDS])
378 TRIG = _Flag('trigger_flags', 'TRIG_', whitelist=[
379 'bogus', 'dither', 'deglitch', 'config', 'wake_eos'])
380 TRIG.bogus.doc += ' (do the motions)'
381 TRIG.config.doc += ' (perform configuration, not triggering)'
382 TRIG.wake_eos.doc += ' (wake up on end-of-scan events)'
384 CMDF = _Flag('command_flags', 'CMDF_')
385 CMDF.priority.doc += (
386 ' (try to use a real-time interrupt while performing command)')
388 EV = _Flag('??', 'COMEDI_EV_')
390 TRIG_ROUND = _Enum('trigger_round', 'TRIG_ROUND_', blacklist=['mask'])
391 TRIG_ROUND.mask = _comedi.TRIG_ROUND_MASK
393 TRIG_SRC = _Flag('trigger_source_flags', 'TRIG_',
394 blacklist=[i.name for i in TRIG] + [
395 'round_%s' % i.name for i in TRIG_ROUND] + [
396 'round_mask', 'rt', 'write'])
397 TRIG_SRC.none.doc += ' (never trigger)'
398 TRIG_SRC.now.doc += ' (trigger now + N ns)'
399 TRIG_SRC.follow.doc += ' (trigger on next lower level trig)'
400 TRIG_SRC.time.doc += ' (trigger at time N ns)'
401 TRIG_SRC.timer.doc += ' (trigger at rate N ns)'
402 TRIG_SRC.count.doc += ' (trigger when count reaches N)'
403 TRIG_SRC.ext.doc += ' (trigger on external signal N)'
404 TRIG_SRC.int.doc += ' (trigger on comedi-internal signal N)'
405 TRIG_SRC.other.doc += ' (driver defined)'
407 SDF_PWM = _Flag('pulse_width_modulation_subdevice_flags', 'SDF_PWM_')
408 SDF_PWM.counter.doc += ' (PWM can automatically switch off)'
409 SDF_PWM.hbridge.doc += ' (PWM is signed (H-bridge))'
411 SDF = _Flag('subdevice_flags', 'SDF_', blacklist=[
412 'pwm_%s' % i.name for i in SDF_PWM] + [
413 'cmd', 'writeable', 'rt'])
414 SDF.busy.doc += ' (device is busy)'
415 SDF.busy_owner.doc += ' (device is busy with your job)'
416 SDF.locked.doc += ' (subdevice is locked)'
417 SDF.lock_owner.doc += ' (you own lock)'
418 SDF.maxdata.doc += ' (maxdata depends on channel)'
419 SDF.flags.doc += ' (flags depend on channel (BROKEN))'
420 SDF.rangetype.doc += ' (range type depends on channel)'
421 SDF.soft_calibrated.doc += ' (subdevice uses software calibration)'
422 SDF.cmd_write.doc += ' (can do output commands)'
423 SDF.cmd_read.doc += ' (can to input commands)'
424 SDF.readable.doc += ' (subdevice can be read, e.g. analog input)'
425 SDF.writable.doc += ' (subdevice can be written, e.g. analog output)'
426 SDF.internal.doc += ' (subdevice does not have externally visible lines)'
427 SDF.ground.doc += ' (can do aref=ground)'
428 SDF.common.doc += ' (can do aref=common)'
429 SDF.diff.doc += ' (can do aref=diff)'
430 SDF.other.doc += ' (can do aref=other)'
431 SDF.dither.doc += ' (can do dithering)'
432 SDF.deglitch.doc += ' (can do deglitching)'
433 SDF.mmap.doc += ' (can do mmap())'
434 SDF.running.doc += ' (subdevice is acquiring data)'
435 SDF.lsampl.doc += ' (subdevice uses 32-bit samples)'
436 SDF.packed.doc += ' (subdevice can do packed DIO)'
438 SUBDEVICE_TYPE = _Enum('subdevice_type', 'COMEDI_SUBD_')
439 SUBDEVICE_TYPE.unused.doc += ' (unused by driver)'
440 SUBDEVICE_TYPE.ai.doc += ' (analog input)'
441 SUBDEVICE_TYPE.ao.doc += ' (analog output)'
442 SUBDEVICE_TYPE.di.doc += ' (digital input)'
443 SUBDEVICE_TYPE.do.doc += ' (digital output)'
444 SUBDEVICE_TYPE.dio.doc += ' (digital input/output)'
445 SUBDEVICE_TYPE.memory.doc += ' (memory, EEPROM, DPRAM)'
446 SUBDEVICE_TYPE.calib.doc += ' (calibration DACs)'
447 SUBDEVICE_TYPE.proc.doc += ' (processor, DSP)'
448 SUBDEVICE_TYPE.serial.doc += ' (serial IO)'
449 SUBDEVICE_TYPE.pwm.doc += ' (pulse-with modulation)'
451 IO_DIRECTION = _Enum('io_direction', 'COMEDI_', whitelist=[
452 'input', 'output', 'opendrain'])
454 SUPPORT_LEVEL = _Enum('support_level', 'COMEDI_', whitelist=[
455 'unknown_support', 'supported', 'unsupported'])
457 UNIT = _Enum('unit', 'UNIT_', translation={'mA':'mA'})
458 # The mA translation avoids lowercasing to 'ma'.
459 UNIT.append(_NamedInt(
461 value=_comedi.RF_EXTERNAL,
462 doc=('RF_EXTERNAL (value unit is defined by an external reference '
465 CALLBACK = _Enum('callback_flags', 'COMEDI_CB_', blacklist=['block', 'eobuf'])
466 CALLBACK.eos.doc += ' (end of scan)'
467 CALLBACK.eoa.doc += ' (end of acquisition)'
468 CALLBACK.error.doc += ' (card error during acquisition)'
469 CALLBACK.overflow.doc += ' (buffer overflow/underflow)'
471 CONVERSION_DIRECTION = _Enum('conversion_direction', 'COMEDI_', whitelist=[
472 'to_physical', 'from_physical'])
474 # The following constants aren't declared in comedi.h or comedilib.h,
475 # but they should be.
477 LOGLEVEL = _Enum('log level', '', whitelist=[''])
478 LOGLEVEL.append(_NamedInt('silent', 0, doc='Comedilib prints nothing.'))
479 LOGLEVEL.append(_NamedInt('bug', 1, doc=(
480 'Comedilib prints error messages when there is a self-consistency '
481 'error (i.e., an internal bug (default).')))
482 LOGLEVEL.append(_NamedInt('invalid', 2, doc=(
483 'Comedilib prints an error message when an invalid parameter is '
485 LOGLEVEL.append(_NamedInt('error', 3, doc=(
486 'Comedilib prints an error message whenever an error is generated '
487 'in the Comedilib library or in the C library, when called by '
489 LOGLEVEL.append(_NamedInt('debug', 4, doc='Comedilib prints a lot of junk.'))