command: Fix except declaration for get_comedi_cmd_pointer
[pycomedi.git] / pycomedi / constant.pyx
1 # Copyright (C) 2011-2012 W. Trevor King <wking@tremily.us>
2 #
3 # This file is part of pycomedi.
4 #
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
8 # version.
9 #
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.
13 #
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/>.
16
17 """Enums and flags are bundled into class instances for easier browsing
18
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>,
23  <_NamedInt pwm>]
24 >>> SUBDEVICE_TYPE.dio
25 <_NamedInt dio>
26 >>> SUBDEVICE_TYPE.dio.value == _comedi.COMEDI_SUBD_DIO
27 True
28 >>> SUBDEVICE_TYPE.dio.doc
29 'COMEDI_SUBD_DIO (digital input/output)'
30
31 You can also search by name or value.
32
33 >>> TRIG_SRC.index_by_name('timer')
34 <_NamedInt timer>
35 >>> TRIG_SRC.index_by_value(_comedi.TRIG_NOW)
36 <_NamedInt now>
37
38 Some flags have constants for setting or clearing all the flags at once.
39
40 >>> TRIG_SRC  # doctest: +NORMALIZE_WHITESPACE
41 [<_NamedInt none>, <_NamedInt now>, <_NamedInt follow>, <_NamedInt time>,
42  <_NamedInt timer>, <_NamedInt count>, <_NamedInt ext>, <_NamedInt int>,
43  <_NamedInt other>]
44 >>> TRIG_SRC._empty
45 <_NamedInt invalid>
46 >>> TRIG_SRC._all
47 <_NamedInt any>
48
49 Flag instances have a special wrapper that stores their value.
50
51 >>> f = FlagValue(SDF, 17)
52 >>> f.flag  # doctest: +ELLIPSIS
53 [<_NamedInt busy>, <_NamedInt busy_owner>, ...]
54 >>> f.busy
55 True
56 >>> f.busy = False
57 >>> f._value
58 16
59
60 You can treat named integers as Python integers with bitwise operations,
61
62 >>> a = TRIG_SRC.now | TRIG_SRC.follow | TRIG_SRC.time | 64
63 >>> a
64 <BitwiseOperator 78>
65 >>> a.value
66 78
67 >>> TRIG_SRC.none & TRIG_SRC.now
68 <BitwiseOperator 0>
69
70 Because of the way Python operator overloading works [#ops]_, you can
71 also start a bitwise chain with an integer.
72
73 >>> 64 | TRIG_SRC.now
74 <BitwiseOperator 66>
75
76 Rich comparisons with other flags and integers are also supported.
77
78 >>> 64 > TRIG_SRC.now
79 True
80 >>> TRIG_SRC.now > 64
81 False
82 >>> TRIG_SRC.now >= 2
83 True
84 >>> TRIG_SRC.now >= 3
85 False
86 >>> import copy
87 >>> TRIG_SRC.now == copy.deepcopy(TRIG_SRC.now)
88 True
89 >>> TRIG_SRC.now != TRIG_SRC.now
90 False
91 >>> TRIG_SRC.now <= 2
92 True
93 >>> TRIG_SRC.now < 3
94 True
95 >>> TRIG_SRC.now > None
96 True
97
98 The ``UNIT`` constant treats ``RF_EXTERNAL`` as a full-fledged unit:
99
100 >>> UNIT.index_by_name('external')
101 <_NamedInt external>
102 >>> UNIT.index_by_value(_comedi.RF_EXTERNAL)
103 <_NamedInt external>
104
105 .. [#ops] See `emulating numeric types`_ and `NotImplementedError` in
106    `the standard type hierarchy`_.
107
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
112 """
113
114 from math import log as _log
115 import sys as _sys
116
117 import numpy as _numpy
118 import comedi as _comedi
119
120 from . import LOG as _LOG
121
122
123 def bitwise_value(object):
124     """Convenience function for flexible value specification
125
126     This funciton makes it easy for functions and methods to accept
127     either integers or `BitwiseOperator` instances as integer
128     parameters.
129     """
130     if isinstance(object, BitwiseOperator):
131         return object.value
132     return object
133
134
135 def _pso(s, o):
136     """External definition of staticmethod until Cython supports the
137     usual syntax.
138
139     http://docs.cython.org/src/userguide/limitations.html#behaviour-of-class-scopes
140     """
141     if isinstance(s, BitwiseOperator):
142         s = s.value
143     if isinstance(o, BitwiseOperator):
144         o = o.value
145     return (long(s), long(o))
146
147
148 cdef class BitwiseOperator (object):
149     """General class for bitwise operations.
150
151     This class allows chaining bitwise operations between
152     `_NamedInt`\s and similar objects.
153
154     Because flag values can be large, we cast all values to longs
155     before performing any bitwise operations.  This avoids issues like
156
157     >>> int.__or__(1073741824, 2147483648L)
158     NotImplemented
159     """
160
161     def __init__(self, value):
162         self.value = value
163
164     def __str__(self):
165         return self.__repr__()
166
167     def __repr__(self):
168         return '<%s %s>' % (self.__class__.__name__, self.value)
169
170     _prepare_self_other = staticmethod(_pso)
171
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)))
176
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)))
181
182     def __richcmp__(self, other, op):
183         if other is None:
184             other = self.value - 1
185         s,o = BitwiseOperator._prepare_self_other(self, other)
186         if op == 0:
187             return s < o
188         elif op == 1:
189             return s <= o
190         elif op == 2:
191             return s == o
192         elif op == 3:
193             return s != o
194         elif op == 4:
195             return s > o
196         elif op == 5:
197             return s >= o
198         else:
199             raise ValueError(op)
200
201     def __reduce__(self):
202         return (BitwiseOperator, (self.value,))
203
204
205 class _NamedInt (BitwiseOperator):
206     "A flag or enum item."
207     def __init__(self, name, value, doc=None):
208         super(_NamedInt, self).__init__(value)
209         self.name = name
210         self.doc = doc
211
212     def __str__(self):
213         return self.name
214
215     def __repr__(self):
216         return '<%s %s>' % (self.__class__.__name__, self.name)
217
218     def __reduce__(self):
219         return (_NamedInt, (self.name, self.value, self.doc))
220
221
222 class _Enum (list):
223     "An enumerated list"
224     def __init__(self, name, prefix='', blacklist=None, whitelist=None,
225                  translation=None):
226         super(_Enum, self).__init__()
227         self.name = name
228         if blacklist == None:
229             blacklist = []
230         if translation == None:
231             translation = {}
232         self._name_keys = {}
233         self._value_keys = {}
234         mod = _comedi
235         if hasattr(mod, 'wrapped'):
236             mod = 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):
243                     continue
244                 self._add_item(attr, item_name)
245         self.sort(key=lambda item: item.value)
246
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]
251         else:
252             return item_name.lower()
253
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)
257
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
262         if item_value < 0:
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)
267         self.append(item)
268
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)
278
279     def index_by_name(self, name):
280         return self._name_keys[name]
281
282     def index_by_value(self, value):
283         return self._value_keys[value]
284
285
286 class _Flag (_Enum):
287     "A flag"
288     def __init__(self, *args, **kwargs):
289         super(_Flag, self).__init__(*args, **kwargs)
290         self._empty = None
291         self._all = None
292         for flag in self:
293             if flag.value == 0:
294                 self._empty = flag
295             elif flag.value < 0 or abs(_log(flag.value, 2)) % 1 > 1e-13:  # deal with rounding errors
296                 if self._all:
297                     raise ValueError(
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))
301                 self._all = flag
302         if self._empty:
303             self.remove(self._empty)
304         if self._all:
305             self.remove(self._all)
306
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
311
312     def set(self, value, name, status):
313         flag = getattr(self, name)
314         if status == True:
315             return value | flag.value
316         return (value | flag.value) - flag.value
317
318
319 class FlagValue (object):
320     """A flag instance (flag + value)
321
322     Examples
323     --------
324
325     >>> f = FlagValue(flag=TRIG_SRC, value=0, default='empty')
326     >>> f.any
327     False
328     >>> print f
329     empty
330     >>> f.now = True
331     >>> f.timer = True
332     >>> f.int = True
333     >>> print f
334     now|timer|int
335     """
336     def __init__(self, flag, value, default='-'):
337         self.flag = flag
338         self._value = value
339         self._default = default
340
341     def __str__(self):
342         flags = [f for f in self.flag if getattr(self, f.name)]
343         if len(flags) == 0:
344             return self._default
345         return '|'.join([f.name for f in flags])
346
347     def __getattr__(self, name):
348         return self.flag.get(self._value, name)
349
350     def __setattr__(self, name, value):
351         if name != 'flag' and not name.startswith('_'):
352             value = self.flag.set(self._value, name, value)
353             name = '_value'
354         super(FlagValue, self).__setattr__(name, value)
355
356
357 # blacklist deprecated values (and those belonging to other _Enums or _Flags)
358
359 CR = _Flag('ChanSpec flags', 'CR_', blacklist=['dither', 'deglitch'])
360 CR.alt_filter.doc += ' (can also mean "dither" or "deglitch")'
361
362 AREF = _Enum('analog_reference', 'AREF_')
363 AREF.diff.doc += ' (differential)'
364 AREF.other.doc += ' (other / undefined)'
365
366 #GPCT = _Flag('general_purpose_counter_timer', 'GPCT_')
367 # Two competing flag sets?  Need some documentation.
368
369 INSN_MASK = _Flag('instruction_mask', 'INSN_MASK_')
370
371 CONFIGURATION_IDS = _Enum('configuration_ids', 'INSN_CONFIG_', blacklist=[
372         '8254_set_mode'])
373
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])
377
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)'
383
384 CMDF = _Flag('command_flags', 'CMDF_')
385 CMDF.priority.doc += (
386     ' (try to use a real-time interrupt while performing command)')
387
388 EV = _Flag('??', 'COMEDI_EV_')
389
390 TRIG_ROUND = _Enum('trigger_round', 'TRIG_ROUND_', blacklist=['mask'])
391 TRIG_ROUND.mask = _comedi.TRIG_ROUND_MASK
392
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)'
406
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))'
410
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)'
437
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)'
450
451 IO_DIRECTION = _Enum('io_direction', 'COMEDI_', whitelist=[
452         'input', 'output', 'opendrain'])
453
454 SUPPORT_LEVEL = _Enum('support_level', 'COMEDI_', whitelist=[
455         'unknown_support', 'supported', 'unsupported'])
456
457 UNIT = _Enum('unit', 'UNIT_', translation={'mA':'mA'})
458 # The mA translation avoids lowercasing to 'ma'.
459 UNIT.append(_NamedInt(
460         name='external',
461         value=_comedi.RF_EXTERNAL,
462         doc=('RF_EXTERNAL (value unit is defined by an external reference '
463              'channel)')))
464
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)'
470
471 CONVERSION_DIRECTION = _Enum('conversion_direction', 'COMEDI_', whitelist=[
472         'to_physical', 'from_physical'])
473
474 # The following constants aren't declared in comedi.h or comedilib.h,
475 # but they should be.
476
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 '
484             'passed.')))
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 '
488             'Comedilib.')))
489 LOGLEVEL.append(_NamedInt('debug', 4, doc='Comedilib prints a lot of junk.'))