-# Copyright (C) 2011-2012 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2011-2012 W. Trevor King <wking@tremily.us>
#
# This file is part of pycomedi.
#
class _ReadWriteThread (_threading.Thread):
"Base class for all reader/writer threads"
- def __init__(self, subdevice, buffer, name=None):
+ def __init__(self, subdevice, buffer, name=None,
+ block_while_running=False):
if name == None:
name = '<%s subdevice %d>' % (
self.__class__.__name__, subdevice.index)
self.subdevice = subdevice
self.buffer = buffer
+ self.block_while_running = block_while_running
self._setup_buffer()
super(_ReadWriteThread, self).__init__(name=name)
"""
return self.subdevice.device.file
+ def block(self):
+ while self.subdevice.get_flags().running:
+ _time.sleep(0)
+ self.subdevice.cancel() # become unbusy
+
class Reader (_ReadWriteThread):
"""`read()`-based reader
shape=self.buffer.shape, dtype=self.buffer.dtype,
buffer=buf)
self.buffer[:] = a
- #_LOG.critical('ai running? %s' % self.subdevice.get_flags().running)
- #while self.subdevice.get_flags().running:
- ##_LOG.critical('ai running? %s' % self.subdevice.get_flags().running)
- # _time.sleep(0)
- #_LOG.critical('ai running? %s' % self.subdevice.get_flags().running)
- #_time.sleep(1)
+ if self.block_while_running:
+ self.block()
+
+
+class CallbackReader (Reader):
+ """`read()`-based reader with callbacks
+
+ Examples
+ --------
+
+ Setup a temporary data file for testing.
+
+ >>> from os import close, remove
+ >>> from sys import stdout
+ >>> from tempfile import mkstemp
+ >>> from time import sleep
+ >>> fd,t = mkstemp(suffix='.dat', prefix='pycomedi-')
+ >>> f = _os.fdopen(fd, 'rb+')
+ >>> buf = _numpy.array([[0,10],[1,11],[2,12]], dtype=_numpy.uint16)
+ >>> buf.tofile(t)
+
+ Override the default `Reader` methods for our dummy subdevice.
+
+ >>> class TestReader (CallbackReader):
+ ... def _file(self):
+ ... return f
+
+ Define a callback function.
+
+ >>> def callback(data):
+ ... sleep(0.1) # for consistent output spacing
+ ... print('got: {0}'.format(repr(data)))
+ ... stdout.flush()
+
+ Run the test reader.
+
+ >>> rbuf = _numpy.zeros((buf.shape[1],), dtype=_numpy.uint16)
+ >>> r = TestReader(subdevice=None, buffer=rbuf, name='Reader-doctest',
+ ... callback=callback, count=buf.shape[0])
+ >>> r.start()
+ >>> sleep(0.25)
+ got: array([ 0, 10], dtype=uint16)
+ got: array([ 1, 11], dtype=uint16)
+ >>> r.join()
+ got: array([ 2, 12], dtype=uint16)
+
+ While `numpy` arrays make multi-channel indexing easy, they do
+ require an external library. For single-channel input, the
+ `array` module is sufficient.
+
+ >>> f.seek(0)
+ >>> rbuf = _array.array('H', [0])
+ >>> r = TestReader(subdevice=None, buffer=rbuf, name='Reader-doctest',
+ ... callback=callback, count=buf.size)
+ >>> r.start()
+ >>> sleep(0.35)
+ got: array('H', [0])
+ got: array('H', [10])
+ got: array('H', [1])
+ >>> r.join()
+ got: array('H', [11])
+ got: array('H', [2])
+ got: array('H', [12])
+
+ Cleanup the temporary data file.
+
+ >>> f.close() # no need for `close(fd)`
+ >>> remove(t)
+ """
+ def __init__(self, callback=None, count=None, **kwargs):
+ self.callback = callback
+ self.count = count
+ super(CallbackReader, self).__init__(**kwargs)
+
+ def run(self):
+ count = self.count
+ block_while_running = self.block_while_running
+ while count is None or count > 0:
+ if count is not None:
+ count -= 1
+ try:
+ self.block_while_running = False
+ super(CallbackReader, self).run()
+ finally:
+ self.block_while_running = block_while_running
+ if self.callback:
+ self.callback(self.buffer)
+ if self.block_while_running:
+ self.block()
class Writer (_ReadWriteThread):
f = self._file()
remaining_buffer.tofile(f)
f.flush()
- #_LOG.critical('ao running? %s' % self.subdevice.get_flags().running)
- #while self.subdevice.get_flags().running:
- ##_LOG.critical('ao running? %s' % self.subdevice.get_flags().running)
- #_time.sleep(0)
- #_LOG.critical('ao running? %s' % self.subdevice.get_flags().running)
- #_time.sleep(1)
+ if self.block_while_running:
+ self.block()
class _MMapReadWriteThread (_ReadWriteThread):
- "`mmap()`-based reader/wrtier"
+ "`mmap()`-based reader/writer"
def __init__(self, *args, **kwargs):
preload = kwargs.pop('preload', 0)
access = kwargs.pop('access')
remaining -= action
else:
_time.sleep(sleep_time)
+ if self.block_while_running:
+ self.block()
def _act(self, mmap, mmap_offset, buffer_offset, remaining, mmap_size,
action_bytes=None, builtin_array=None):
return self.subdevice.get_buffer_size()
def _fileno(self):
- return self.subdevice._device.fileno()
+ return self.subdevice.device.fileno()
def _action_bytes(self):
return self.subdevice.get_buffer_contents()