Ran update-copyright.py.
[pycomedi.git] / pycomedi / command.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 "Wrap Comedi's `comedi_cmd` struct in the `Command` class"
18
19 cimport libc.stdlib as _stdlib
20 import numpy as _numpy
21
22 cimport _comedi_h
23 cimport _comedilib_h
24 from pycomedi import PyComediError as _PyComediError
25 from chanspec import ChanSpec as _ChanSpec
26 import constant as _constant
27
28
29 cdef class Command (object):
30     """A Comedi command
31
32     >>> from .constant import AREF, CMDF, TRIG_SRC    
33     >>> from .channel import AnalogChannel
34     >>> from .chanspec import ChanSpec
35     >>> from .device import Device
36
37     >>> c = Command()
38     >>> print str(c)
39             subdev: 0
40              flags: -
41          start_src: -
42          start_arg: 0
43     scan_begin_src: -
44     scan_begin_arg: 0
45        convert_src: -
46        convert_arg: 0
47       scan_end_src: -
48       scan_end_arg: 0
49           stop_src: -
50           stop_arg: 0
51           chanlist: []
52               data: []
53
54     `data` takes any iterable that supports `length()` and returns NumPy arrays.
55
56     >>> c.data = [1, 2, 3]
57     >>> type(c.data)
58     <type 'numpy.ndarray'>
59
60     `subdev` is currently just an integer (not a `Subdevice` instance).
61
62     >>> c.subdev = 3
63     >>> c.subdev
64     3L
65     >>> type(c.subdev)
66     <type 'long'>
67
68     `flags` and trigger sources return `FlagValue` instances.
69
70     >>> c.flags  # doctest: +ELLIPSIS
71     <pycomedi.constant.FlagValue object at 0x...>
72     >>> c.flags = CMDF.priority | CMDF.write
73
74     >>> c.start_src  # doctest: +ELLIPSIS
75     <pycomedi.constant.FlagValue object at 0x...>
76     >>> c.start_src = TRIG_SRC.int | TRIG_SRC.now
77     >>> c.scan_begin_src = TRIG_SRC.timer
78     >>> c.scan_begin_arg = 10
79     >>> c.convert_src = TRIG_SRC.now
80     >>> c.scan_end_src = TRIG_SRC.count
81     >>> c.scan_end_arg = 4
82     >>> c.stop_src = TRIG_SRC.none
83
84     Because `ChanSpec` instances store their value internally (not
85     using the value stored in the `Command` instance), direct
86     operations on them have no effect on the intruction.
87
88     >>> chanlist = [
89     ...     ChanSpec(chan=0, aref=AREF.diff),
90     ...     ChanSpec(chan=1, aref=AREF.diff),
91     ...     ]
92     >>> c.chanlist = chanlist
93     >>> c.chanlist[0]
94     <ChanSpec chan:0 range:0 aref:diff flags:->
95     >>> c.chanlist[0].aref = AREF.ground
96     >>> c.chanlist[0]
97     <ChanSpec chan:0 range:0 aref:diff flags:->
98
99     To have an effect, you need to explicity set the `chanlist` attribute:
100
101     >>> chanlist = c.chanlist
102     >>> chanlist[0].aref = AREF.ground
103     >>> c.chanlist = chanlist
104     >>> c.chanlist[0]
105     <ChanSpec chan:0 range:0 aref:ground flags:->
106
107     You can also set chanspec items with `AnalogChannel` instances (or
108     any object that has a `chanspec` method).
109
110     >>> d = Device('/dev/comedi0')
111     >>> d.open()
112     >>> subdevice = d.get_read_subdevice()
113     >>> c.chanlist = [subdevice.channel(1, factory=AnalogChannel,
114     ...     aref=AREF.diff)]
115     >>> d.close()
116
117     >>> print str(c)
118             subdev: 3
119              flags: priority|write
120          start_src: now|int
121          start_arg: 0
122     scan_begin_src: timer
123     scan_begin_arg: 10
124        convert_src: now
125        convert_arg: 0
126       scan_end_src: count
127       scan_end_arg: 4
128           stop_src: none
129           stop_arg: 0
130           chanlist: [<ChanSpec chan:1 range:0 aref:diff flags:->]
131               data: [1 2 3]
132     """
133     def __cinit__(self):
134         self._cmd.chanlist = NULL
135         self._cmd.data = NULL
136         self._fields = [
137             'subdev', 'flags', 'start_src', 'start_arg', 'scan_begin_src',
138             'scan_begin_arg', 'convert_src', 'convert_arg', 'scan_end_src',
139             'scan_end_arg', 'stop_src', 'stop_arg', 'chanlist', 'data']
140
141     def __dealloc__(self):
142         if self._cmd.chanlist is not NULL:
143             _stdlib.free(self._cmd.chanlist)
144         if self._cmd.data is not NULL:
145             _stdlib.free(self._cmd.data)
146
147     cdef _comedi_h.comedi_cmd *get_comedi_cmd_pointer(self):
148         return &self._cmd
149
150     def __str__(self):
151         max_field_length = max([len(f) for f in self._fields])
152         lines = []
153         for f in self._fields:
154             lines.append('%*s: %s' % (max_field_length, f, getattr(self, f)))
155         return '\n'.join(lines)
156
157     def _subdev_get(self):
158         return self._cmd.subdev
159     def _subdev_set(self, value):
160         self._cmd.subdev = _constant.bitwise_value(value)
161     subdev = property(fget=_subdev_get, fset=_subdev_set)
162
163     def _flags_get(self):
164         return _constant.FlagValue(_constant.CMDF, self._cmd.flags)
165     def _flags_set(self, value):
166         self._cmd.flags = _constant.bitwise_value(value)
167     flags = property(fget=_flags_get, fset=_flags_set)
168
169     def _start_src_get(self):
170         return _constant.FlagValue(_constant.TRIG_SRC, self._cmd.start_src)
171     def _start_src_set(self, value):
172         self._cmd.start_src = _constant.bitwise_value(value)
173     start_src = property(fget=_start_src_get, fset=_start_src_set)
174
175     def _start_arg_get(self):
176         return self._cmd.start_arg
177     def _start_arg_set(self, value):
178         self._cmd.start_arg = value
179     start_arg = property(fget=_start_arg_get, fset=_start_arg_set)
180
181     def _scan_begin_src_get(self):
182         return _constant.FlagValue(_constant.TRIG_SRC, self._cmd.scan_begin_src)
183     def _scan_begin_src_set(self, value):
184         self._cmd.scan_begin_src = _constant.bitwise_value(value)
185     scan_begin_src = property(fget=_scan_begin_src_get, fset=_scan_begin_src_set)
186
187     def _scan_begin_arg_get(self):
188         return self._cmd.scan_begin_arg
189     def _scan_begin_arg_set(self, value):
190         self._cmd.scan_begin_arg = value
191     scan_begin_arg = property(fget=_scan_begin_arg_get, fset=_scan_begin_arg_set)
192
193     def _convert_src_get(self):
194         return _constant.FlagValue(_constant.TRIG_SRC, self._cmd.convert_src)
195     def _convert_src_set(self, value):
196         self._cmd.convert_src = _constant.bitwise_value(value)
197     convert_src = property(fget=_convert_src_get, fset=_convert_src_set)
198
199     def _convert_arg_get(self):
200         return self._cmd.convert_arg
201     def _convert_arg_set(self, value):
202         self._cmd.convert_arg = value
203     convert_arg = property(fget=_convert_arg_get, fset=_convert_arg_set)
204
205
206     def _scan_end_src_get(self):
207         return _constant.FlagValue(_constant.TRIG_SRC, self._cmd.scan_end_src)
208     def _scan_end_src_set(self, value):
209         self._cmd.scan_end_src = _constant.bitwise_value(value)
210     scan_end_src = property(fget=_scan_end_src_get, fset=_scan_end_src_set)
211
212     def _scan_end_arg_get(self):
213         return self._cmd.scan_end_arg
214     def _scan_end_arg_set(self, value):
215         self._cmd.scan_end_arg = value
216     scan_end_arg = property(fget=_scan_end_arg_get, fset=_scan_end_arg_set)
217
218     def _stop_src_get(self):
219         return _constant.FlagValue(_constant.TRIG_SRC, self._cmd.stop_src)
220     def _stop_src_set(self, value):
221         self._cmd.stop_src = _constant.bitwise_value(value)
222     stop_src = property(fget=_stop_src_get, fset=_stop_src_set)
223
224     def _stop_arg_get(self):
225         return self._cmd.stop_arg
226     def _stop_arg_set(self, value):
227         self._cmd.stop_arg = value
228     stop_arg = property(fget=_stop_arg_get, fset=_stop_arg_set)
229
230     def _chanlist_get(self):
231         ret = list()
232         for i in range(self._cmd.chanlist_len):
233             c = _ChanSpec()
234             c.value = self._cmd.chanlist[i]
235             ret.append(c)
236         return ret
237     def _chanlist_set(self, value):
238         if self._cmd.chanlist is not NULL:
239             _stdlib.free(self._cmd.chanlist)
240         self._cmd.chanlist_len = len(value)
241         self._cmd.chanlist = <unsigned int *>_stdlib.malloc(
242             self._cmd.chanlist_len*sizeof(unsigned int))
243         if self._cmd.chanlist is NULL:
244             self._cmd.chanlist_len = 0
245             raise _PyComediError('out of memory?')
246         for i,x in enumerate(value):
247             if hasattr(x, 'chanspec'):
248                 x = x.chanspec()
249             self._cmd.chanlist[i] = _constant.bitwise_value(x)
250     chanlist = property(fget=_chanlist_get, fset=_chanlist_set)
251
252     def _data_get(self):
253         data = _numpy.ndarray(shape=(self._cmd.data_len,), dtype=_numpy.uint16)
254         # TODO: point into existing data array?
255         for i in range(self._cmd.data_len):
256             data[i] = self._cmd.data[i]
257         return data
258     def _data_set(self, value):
259         if self._cmd.data is not NULL:
260             _stdlib.free(self._cmd.data)
261         self._cmd.data_len = len(value)
262         self._cmd.data = <_comedi_h.sampl_t *>_stdlib.malloc(
263             self._cmd.data_len*sizeof(_comedi_h.sampl_t))
264         if self._cmd.data is NULL:
265             self._cmd.data_len = 0
266             raise _PyComediError('out of memory?')
267         for i,x in enumerate(value):
268             self._cmd.data[i] = x
269     data = property(fget=_data_get, fset=_data_set)