1 # Copyright (C) 2010 W. Trevor King
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 """Enums and flags are bundled into class instances for easier browsing.
18 >>> SUBDEVICE_TYPE # doctest: +NORMALIZE_WHITESPACE
19 [<_NamedInt unused>, <_NamedInt ai>, <_NamedInt ao>, <_NamedInt di>,
20 <_NamedInt do>, <_NamedInt dio>, <_NamedInt counter>, <_NamedInt timer>,
21 <_NamedInt memory>, <_NamedInt calib>, <_NamedInt proc>, <_NamedInt serial>,
23 >>> SUBDEVICE_TYPE.dio
25 >>> SUBDEVICE_TYPE.dio.value == _comedi.COMEDI_SUBD_DIO
27 >>> SUBDEVICE_TYPE.dio.doc
28 'COMEDI_SUBD_DIO (digital input/output)'
30 You can also search by name or value.
32 >>> TRIG_SRC.index_by_name('timer')
34 >>> TRIG_SRC.index_by_value(_comedi.TRIG_NOW)
37 Some flags have constants for setting or clearing all the flags at once.
39 >>> TRIG_SRC # doctest: +NORMALIZE_WHITESPACE
40 [<_NamedInt none>, <_NamedInt now>, <_NamedInt follow>, <_NamedInt time>,
41 <_NamedInt timer>, <_NamedInt count>, <_NamedInt ext>, <_NamedInt int>,
48 Flag instances have a special wrapper that stores their value.
50 >>> f = FlagValue(SDF, 17)
51 >>> f.flag # doctest: +ELLIPSIS
52 [<_NamedInt busy>, <_NamedInt busy_owner>, ...]
59 You can treat named integers as Python integers with bitwise operations,
61 >>> a = TRIG_SRC.now | TRIG_SRC.follow | TRIG_SRC.time | 64
66 >>> TRIG_SRC.none & TRIG_SRC.now
69 But because of the way Python operator overloading works, plain
70 integers must go at the end of bitwise chains.
73 Traceback (most recent call last):
75 TypeError: unsupported operand type(s) for |: 'int' and '_NamedInt'
78 from math import log as _log
80 import comedi as _comedi
83 class _BitwiseOperator (object):
84 def __init__(self, value):
88 return self.__repr__()
91 return '<%s %s>' % (self.__class__.__name__, self.value)
93 def __and__(self, other):
94 "Bitwise and acts on `_BitwiseOperator.value`."
95 if isinstance(other, _BitwiseOperator):
97 return _BitwiseOperator(int.__and__(self.value, other))
99 def __or__(self, other):
100 "Bitwise or acts on `_BitwiseOperator.value`."
101 if isinstance(other, _BitwiseOperator):
103 return _BitwiseOperator(int.__or__(self.value, other))
106 class _NamedInt (_BitwiseOperator):
107 "A flag or enum item."
108 def __init__(self, name, value, doc=None):
109 super(_NamedInt, self).__init__(value)
117 return '<%s %s>' % (self.__class__.__name__, self.name)
122 def __init__(self, name, prefix, blacklist=None, whitelist=None,
124 super(_Enum, self).__init__()
126 if blacklist == None:
128 if translation == None:
131 self._value_keys = {}
132 for attr in dir(_comedi):
133 if attr.startswith(prefix):
134 item_name = self._item_name(attr, prefix, translation)
135 if self._is_ignored(item_name, blacklist, whitelist):
137 self._add_item(attr, item_name)
138 self.sort(key=lambda item: item.value)
140 def _item_name(self, attr, prefix, translation):
141 item_name = attr[len(prefix):]
142 if item_name in translation:
143 return translation[item_name]
145 return item_name.lower()
147 def _is_ignored(self, item_name, blacklist, whitelist):
148 return (item_name in blacklist
149 or whitelist != None and item_name not in whitelist)
151 def _add_item(self, attr, item_name):
152 item_value = getattr(_comedi, attr)
153 item = _NamedInt(item_name, item_value, doc=attr)
155 self._name_keys[item_name] = item
156 if item_value in self._value_keys and item_name:
157 raise ValueError('value collision in %s: %s = %s = %#x'
158 % (self.name, item_name,
159 self._value_keys[item_value], item_value))
160 self._value_keys[item_value] = item
161 setattr(self, item_name, item)
163 def index_by_name(self, name):
164 return self._name_keys[name]
166 def index_by_value(self, value):
167 return self._value_keys[value]
172 def __init__(self, *args, **kwargs):
173 super(_Flag, self).__init__(*args, **kwargs)
179 elif flag.value < 0 or _log(flag.value, 2) % 1 != 0:
182 'mutliple multi-bit flags in %s: %s = %#x and %s = %#x'
183 % (self.name, self._all.name, self._all.value,
184 flag.name, flag.value))
187 self.remove(self._empty)
189 self.remove(self._all)
191 def get(self, value, name):
192 flag = getattr(self, name)
193 assert flag.value != 0, '%s: %s' % (self.name, flag)
194 return value & flag.value == flag.value
196 def set(self, value, name, status):
197 flag = getattr(self, name)
199 return value | flag.value
200 return (value | flag.value) - flag.value
203 class FlagValue (object):
204 """A flag instance (flag + value)
209 >>> f = FlagValue(flag=TRIG_SRC, value=0, default='empty')
220 def __init__(self, flag, value, default='-'):
223 self._default = default
226 flags = [f for f in self.flag if getattr(self, f.name)]
229 return '|'.join([f.name for f in flags])
231 def __getattr__(self, name):
232 return self.flag.get(self._value, name)
234 def __setattr__(self, name, value):
235 if name != 'flag' and not name.startswith('_'):
236 value = self.flag.set(self._value, name, value)
238 super(FlagValue, self).__setattr__(name, value)
241 # blacklist deprecated values (and those belonging to other _Enums or _Flags)
243 AREF = _Enum('analog_reference', 'AREF_')
244 AREF.diff.doc += ' (differential)'
245 AREF.other.doc += ' (other / undefined)'
247 #GPCT = _Flag('general_purpose_counter_timer', 'GPCT_')
248 # Two competing flag sets? Need some documentation.
250 INSN_MASK = _Flag('instruction_mask', 'INSN_MASK_')
252 CONFIGURATION_IDS = _Enum('configuration_ids', 'INSN_CONFIG_', blacklist=[
255 INSN = _Enum('instruction', 'INSN_',
256 blacklist=['mask_%s' % i.name for i in INSN_MASK] + [
257 'config_%s' % i.name for i in CONFIGURATION_IDS])
259 TRIG = _Flag('trigger_flags', 'TRIG_', whitelist=[
260 'bogus', 'dither', 'deglitch', 'config', 'wake_eos'])
261 TRIG.bogus.doc += ' (do the motions)'
262 TRIG.config.doc += ' (perform configuration, not triggering)'
263 TRIG.wake_eos.doc += ' (wake up on end-of-scan events)'
265 CMDF = _Flag('command_flags', 'CMDF_')
266 CMDF.priority.doc += (
267 ' (try to use a real-time interrupt while performing command)')
269 EV = _Flag('??', 'COMEDI_EV_')
271 TRIG_ROUND = _Enum('trigger_round', 'TRIG_ROUND_', blacklist=['mask'])
272 TRIG_ROUND.mask = _comedi.TRIG_ROUND_MASK
274 TRIG_SRC = _Flag('trigger_source_flags', 'TRIG_',
275 blacklist=[i.name for i in TRIG] + [
276 'round_%s' % i.name for i in TRIG_ROUND] + [
277 'round_mask', 'rt', 'write'])
278 TRIG_SRC.none.doc += ' (never trigger)'
279 TRIG_SRC.now.doc += ' (trigger now + N ns)'
280 TRIG_SRC.follow.doc += ' (trigger on next lower level trig)'
281 TRIG_SRC.time.doc += ' (trigger at time N ns)'
282 TRIG_SRC.timer.doc += ' (trigger at rate N ns)'
283 TRIG_SRC.count.doc += ' (trigger when count reaches N)'
284 TRIG_SRC.ext.doc += ' (trigger on external signal N)'
285 TRIG_SRC.int.doc += ' (trigger on comedi-internal signal N)'
286 TRIG_SRC.other.doc += ' (driver defined)'
288 SDF_PWM = _Flag('pulse_width_modulation_subdevice_flags', 'SDF_PWM_')
289 SDF_PWM.counter.doc += ' (PWM can automatically switch off)'
290 SDF_PWM.hbridge.doc += ' (PWM is signed (H-bridge))'
292 SDF = _Flag('subdevice_flags', 'SDF_', blacklist=[
293 'pwm_%s' % i.name for i in SDF_PWM] + [
294 'cmd', 'writeable', 'rt'])
295 SDF.busy.doc += ' (device is busy)'
296 SDF.busy_owner.doc += ' (device is busy with your job)'
297 SDF.locked.doc += ' (subdevice is locked)'
298 SDF.lock_owner.doc += ' (you own lock)'
299 SDF.maxdata.doc += ' (maxdata depends on channel)'
300 SDF.flags.doc += ' (flags depend on channel)'
301 SDF.rangetype.doc += ' (range type depends on channel)'
302 SDF.soft_calibrated.doc += ' (subdevice uses software calibration)'
303 SDF.cmd_write.doc += ' (can do output commands)'
304 SDF.cmd_read.doc += ' (can to input commands)'
305 SDF.readable.doc += ' (subdevice can be read, e.g. analog input)'
306 SDF.writable.doc += ' (subdevice can be written, e.g. analog output)'
307 SDF.internal.doc += ' (subdevice does not have externally visible lines)'
308 SDF.ground.doc += ' (can do aref=ground)'
309 SDF.common.doc += ' (can do aref=common)'
310 SDF.diff.doc += ' (can do aref=diff)'
311 SDF.other.doc += ' (can do aref=other)'
312 SDF.dither.doc += ' (can do dithering)'
313 SDF.deglitch.doc += ' (can do deglitching)'
314 SDF.mmap.doc += ' (can do mmap())'
315 SDF.running.doc += ' (subdevice is acquiring data)'
316 SDF.lsampl.doc += ' (subdevice uses 32-bit samples)'
317 SDF.packed.doc += ' (subdevice can do packed DIO)'
319 SUBDEVICE_TYPE = _Enum('subdevice_type', 'COMEDI_SUBD_')
320 SUBDEVICE_TYPE.unused.doc += ' (unused by driver)'
321 SUBDEVICE_TYPE.ai.doc += ' (analog input)'
322 SUBDEVICE_TYPE.ao.doc += ' (analog output)'
323 SUBDEVICE_TYPE.di.doc += ' (digital input)'
324 SUBDEVICE_TYPE.do.doc += ' (digital output)'
325 SUBDEVICE_TYPE.dio.doc += ' (digital input/output)'
326 SUBDEVICE_TYPE.memory.doc += ' (memory, EEPROM, DPRAM)'
327 SUBDEVICE_TYPE.calib.doc += ' (calibration DACs)'
328 SUBDEVICE_TYPE.proc.doc += ' (processor, DSP)'
329 SUBDEVICE_TYPE.serial.doc += ' (serial IO)'
330 SUBDEVICE_TYPE.pwm.doc += ' (pulse-with modulation)'
332 IO_DIRECTION = _Enum('io_direction', 'COMEDI_', whitelist=[
333 'input', 'output', 'opendrain'])
335 SUPPORT_LEVEL = _Enum('support_level', 'COMEDI_', whitelist=[
336 'unknown_support', 'supported', 'unsupported'])
338 UNIT = _Enum('unit', 'UNIT_', translation={'mA':'mA'})
340 CB = _Enum('callback_flags', 'COMEDI_CB_', blacklist=['block', 'eobuf'])
341 CB.eos.doc += ' (end of scan)'
342 CB.eoa.doc += ' (end of acquisition)'
343 CB.error.doc += ' (card error during acquisition)'
344 CB.overflow.doc += ' (buffer overflow/underflow)'