From c239322c4d2349edf93f7e15c286008bef967b6c Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Tue, 9 Jun 2015 10:59:56 +0100 Subject: [PATCH] Updated daqpower package - Now works with earlier versions of the DAQmx driver. This is needed to be able to run the server on Linux systems, which support older verisions of the driver only. - DAQ error messages are now properly propaged to the client (PyDAQmx uses "mess" rather than "message" attribute to store the message in the Exception obejects). - pylint and pep8 fixes --- .../external/daq_server/daqpower-1.0.1.tar.gz | Bin 12964 -> 0 bytes .../external/daq_server/daqpower-1.0.2.tar.gz | Bin 0 -> 13795 bytes .../daq_server/src/daqpower/__init__.py | 2 +- .../daq_server/src/daqpower/client.py | 24 ++--- .../daq_server/src/daqpower/config.py | 6 +- .../external/daq_server/src/daqpower/daq.py | 102 ++++++++++++++++-- .../daq_server/src/daqpower/server.py | 33 +++--- wlauto/instrumentation/daq/__init__.py | 6 +- 8 files changed, 132 insertions(+), 41 deletions(-) delete mode 100644 wlauto/external/daq_server/daqpower-1.0.1.tar.gz create mode 100644 wlauto/external/daq_server/daqpower-1.0.2.tar.gz diff --git a/wlauto/external/daq_server/daqpower-1.0.1.tar.gz b/wlauto/external/daq_server/daqpower-1.0.1.tar.gz deleted file mode 100644 index 671a45e8d886d67b7e1ab6fc1c7de75129cabdc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12964 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 X-_?TuzxA*-3xY)rAn*jk0SEg(8y0`u diff --git a/wlauto/external/daq_server/daqpower-1.0.2.tar.gz b/wlauto/external/daq_server/daqpower-1.0.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7e63bf0ee03369d41e71bd58b7f9b37a7c948aa0 GIT binary patch literal 13795 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 ZS%21_^=JKAe?Ir~{{e}65u5-R0RZ_u?T!Ed literal 0 HcmV?d00001 diff --git a/wlauto/external/daq_server/src/daqpower/__init__.py b/wlauto/external/daq_server/src/daqpower/__init__.py index ed442117..97b0d54a 100644 --- a/wlauto/external/daq_server/src/daqpower/__init__.py +++ b/wlauto/external/daq_server/src/daqpower/__init__.py @@ -14,4 +14,4 @@ # -__version__ = '1.0.1' +__version__ = '1.0.2' diff --git a/wlauto/external/daq_server/src/daqpower/client.py b/wlauto/external/daq_server/src/daqpower/client.py index b129dc77..14fe69d4 100644 --- a/wlauto/external/daq_server/src/daqpower/client.py +++ b/wlauto/external/daq_server/src/daqpower/client.py @@ -128,10 +128,11 @@ class CommandExecutorProtocol(Protocol): response.message = 'No ports were returned.' def processDevicesResponse(self, response): - if 'devices' not in response.data: - self.errorOut('Response did not containt devices data: {} ({}).'.format(response, response.data)) - ports = response.data['devices'] - response.data = ports + if response.status == Status.OK: + if 'devices' not in response.data: + self.errorOut('Response did not containt devices data: {} ({}).'.format(response, response.data)) + devices = response.data['devices'] + response.data = devices def sendPullRequest(self, port_id): self.sendRequest('pull', port_id=port_id) @@ -167,7 +168,7 @@ class CommandExecutorProtocol(Protocol): class CommandExecutorFactory(ClientFactory): protocol = CommandExecutorProtocol - wait_delay = 1 + wait_delay = 1 def __init__(self, config, command, timeout=10, retries=1): self.config = config @@ -186,19 +187,19 @@ class CommandExecutorFactory(ClientFactory): os.makedirs(self.output_directory) def buildProtocol(self, addr): - protocol = CommandExecutorProtocol(self.command, self.timeout, self.retries) + protocol = CommandExecutorProtocol(self.command, self.timeout, self.retries) protocol.factory = self return protocol def initiateFileTransfer(self, filename, port): log.debug('Downloading {} from port {}'.format(filename, port)) filepath = os.path.join(self.output_directory, filename) - session = FileReceiverFactory(filepath, self) + session = FileReceiverFactory(filepath, self) connector = reactor.connectTCP(self.config.host, port, session) self.transfers_in_progress[session] = connector def transferComplete(self, session): - connector = self.transfers_in_progress[session] + connector = self.transfers_in_progress[session] log.debug('Transfer on port {} complete.'.format(connector.port)) del self.transfers_in_progress[session] @@ -321,7 +322,7 @@ def execute_command(server_config, command, **kwargs): # so in the long run, we need to do this properly and get the FDs # from the reactor. after_fds = _get_open_fds() - for fd in (after_fds - before_fds): + for fd in after_fds - before_fds: try: os.close(int(fd[1:])) except OSError: @@ -338,8 +339,7 @@ def _get_open_fds(): if os.name == 'posix': import subprocess pid = os.getpid() - procs = subprocess.check_output( - [ "lsof", '-w', '-Ff', "-p", str( pid ) ] ) + procs = subprocess.check_output(["lsof", '-w', '-Ff', "-p", str(pid)]) return set(procs.split()) else: # TODO: Implement the Windows equivalent. @@ -362,7 +362,7 @@ def run_send_command(): else: log.start_logging('INFO', fmt='%(levelname)-8s %(message)s') - if args.command == 'configure': + if args.command == 'configure': args.device_config.validate() command = Command(args.command, config=args.device_config) elif args.command == 'get_data': diff --git a/wlauto/external/daq_server/src/daqpower/config.py b/wlauto/external/daq_server/src/daqpower/config.py index bfc3280f..86343424 100644 --- a/wlauto/external/daq_server/src/daqpower/config.py +++ b/wlauto/external/daq_server/src/daqpower/config.py @@ -44,9 +44,9 @@ class DeviceConfiguration(Serializable): def __init__(self, **kwargs): # pylint: disable=W0231 try: self.device_id = kwargs.pop('device_id') or self.default_device_id - self.v_range = float(kwargs.pop('v_range') or self.default_v_range) + self.v_range = float(kwargs.pop('v_range') or self.default_v_range) self.dv_range = float(kwargs.pop('dv_range') or self.default_dv_range) - self.sampling_rate = int(kwargs.pop('sampling_rate') or self.default_sampling_rate) + self.sampling_rate = int(kwargs.pop('sampling_rate') or self.default_sampling_rate) self.resistor_values = kwargs.pop('resistor_values') or [] self.channel_map = kwargs.pop('channel_map') or self.default_channel_map self.labels = (kwargs.pop('labels') or @@ -98,7 +98,7 @@ class UpdateDeviceConfig(argparse.Action): setting = option_string.strip('-').replace('-', '_') if setting not in DeviceConfiguration.valid_settings: raise ConfigurationError('Unkown option: {}'.format(option_string)) - setattr(namespace._device_config, setting, values) + setattr(namespace._device_config, setting, values) # pylint: disable=protected-access class UpdateServerConfig(argparse.Action): diff --git a/wlauto/external/daq_server/src/daqpower/daq.py b/wlauto/external/daq_server/src/daqpower/daq.py index 22951ab9..d70399b0 100644 --- a/wlauto/external/daq_server/src/daqpower/daq.py +++ b/wlauto/external/daq_server/src/daqpower/daq.py @@ -42,7 +42,7 @@ Port 0 :sampling_rate: The rate at which DAQ takes a sample from each channel. """ -# pylint: disable=F0401,E1101,W0621 +# pylint: disable=F0401,E1101,W0621,no-name-in-module import os import sys import csv @@ -52,23 +52,41 @@ from Queue import Queue, Empty import numpy -from PyDAQmx import Task -from PyDAQmx.DAQmxFunctions import DAQmxGetSysDevNames +from PyDAQmx import Task, DAQError +try: + from PyDAQmx.DAQmxFunctions import DAQmxGetSysDevNames + CAN_ENUMERATE_DEVICES = True +except ImportError: # earlier driver version + DAQmxGetSysDevNames = None + CAN_ENUMERATE_DEVICES = False + from PyDAQmx.DAQmxTypes import int32, byref, create_string_buffer from PyDAQmx.DAQmxConstants import (DAQmx_Val_Diff, DAQmx_Val_Volts, DAQmx_Val_GroupByScanNumber, DAQmx_Val_Auto, - DAQmx_Val_Acquired_Into_Buffer, DAQmx_Val_Rising, DAQmx_Val_ContSamps) + DAQmx_Val_Rising, DAQmx_Val_ContSamps) + +try: + from PyDAQmx.DAQmxConstants import DAQmx_Val_Acquired_Into_Buffer + callbacks_supported = True +except ImportError: # earlier driver version + DAQmx_Val_Acquired_Into_Buffer = None + callbacks_supported = False + from daqpower import log + def list_available_devices(): """Returns the list of DAQ devices visible to the driver.""" - bufsize = 2048 # Should be plenty for all but the most pathalogical of situations. - buf = create_string_buffer('\000' * bufsize) - DAQmxGetSysDevNames(buf, bufsize) - return buf.value.split(',') + if DAQmxGetSysDevNames: + bufsize = 2048 # Should be plenty for all but the most pathalogical of situations. + buf = create_string_buffer('\000' * bufsize) + DAQmxGetSysDevNames(buf, bufsize) + return buf.value.split(',') + else: + return [] -class ReadSamplesTask(Task): +class ReadSamplesBaseTask(Task): def __init__(self, config, consumer): Task.__init__(self) @@ -93,11 +111,27 @@ class ReadSamplesTask(Task): DAQmx_Val_Rising, DAQmx_Val_ContSamps, self.config.sampling_rate) + + +class ReadSamplesCallbackTask(ReadSamplesBaseTask): + """ + More recent verisons of the driver (on Windows) support callbacks + + """ + + def __init__(self, config, consumer): + ReadSamplesBaseTask.__init__(self, config, consumer) # register callbacks self.AutoRegisterEveryNSamplesEvent(DAQmx_Val_Acquired_Into_Buffer, self.config.sampling_rate // 2, 0) self.AutoRegisterDoneEvent(0) def EveryNCallback(self): + # Note to future self: do NOT try to "optimize" this but re-using the same array and just + # zeroing it out each time. The writes happen asynchronously and if your zero it out too soon, + # you'll see a whole bunch of 0.0's in the output. If you wanna go down that route, you'll need + # cycler through several arrays and have the code that's actually doing the writing zero them out + # mark them as available to be used by this call. But, honestly, numpy array allocation does not + # appear to be a bottleneck at the moment, so the current solution is "good enough". samples_buffer = numpy.zeros((self.sample_buffer_size,), dtype=numpy.float64) self.ReadAnalogF64(DAQmx_Val_Auto, 0.0, DAQmx_Val_GroupByScanNumber, samples_buffer, self.sample_buffer_size, byref(self.samples_read), None) @@ -107,6 +141,51 @@ class ReadSamplesTask(Task): return 0 # The function should return an integer +class ReadSamplesThreadedTask(ReadSamplesBaseTask): + """ + Earlier verisons of the driver (on CentOS) do not support callbacks. So need + to create a thread to periodically poll the buffer + + """ + + def __init__(self, config, consumer): + ReadSamplesBaseTask.__init__(self, config, consumer) + self.poller = DaqPoller(self) + + def StartTask(self): + ReadSamplesBaseTask.StartTask(self) + self.poller.start() + + def StopTask(self): + self.poller.stop() + ReadSamplesBaseTask.StopTask(self) + + +class DaqPoller(threading.Thread): + + def __init__(self, task, wait_period=1): + super(DaqPoller, self).__init__() + self.task = task + self.wait_period = wait_period + self._stop_signal = threading.Event() + self.samples_buffer = numpy.zeros((self.task.sample_buffer_size,), dtype=numpy.float64) + + def run(self): + while not self._stop_signal.is_set(): + # Note to future self: see the comment inside EventNCallback() above + samples_buffer = numpy.zeros((self.task.sample_buffer_size,), dtype=numpy.float64) + try: + self.task.ReadAnalogF64(DAQmx_Val_Auto, self.wait_period, DAQmx_Val_GroupByScanNumber, samples_buffer, + self.task.sample_buffer_size, byref(self.task.samples_read), None) + except DAQError: + pass + self.task.consumer.write((samples_buffer, self.task.samples_read.value)) + + def stop(self): + self._stop_signal.set() + self.join() + + class AsyncWriter(threading.Thread): def __init__(self, wait_period=1): @@ -220,7 +299,10 @@ class DaqRunner(object): def __init__(self, config, output_directory): self.config = config self.processor = SampleProcessor(config.resistor_values, output_directory, config.labels) - self.task = ReadSamplesTask(config, self.processor) + if callbacks_supported: + self.task = ReadSamplesCallbackTask(config, self.processor) + else: + self.task = ReadSamplesThreadedTask(config, self.processor) self.is_running = False def start(self): diff --git a/wlauto/external/daq_server/src/daqpower/server.py b/wlauto/external/daq_server/src/daqpower/server.py index 9aac51a2..4dc23272 100644 --- a/wlauto/external/daq_server/src/daqpower/server.py +++ b/wlauto/external/daq_server/src/daqpower/server.py @@ -18,7 +18,6 @@ from __future__ import division import os import sys -import socket import argparse import shutil import time @@ -37,11 +36,13 @@ from daqpower import log from daqpower.config import DeviceConfiguration from daqpower.common import DaqServerRequest, DaqServerResponse, Status try: - from daqpower.daq import DaqRunner, list_available_devices -except ImportError: + from daqpower.daq import DaqRunner, list_available_devices, CAN_ENUMERATE_DEVICES + __import_error = None +except ImportError as e: # May be using debug mode. + __import_error = e DaqRunner = None - list_available_devices = lambda : ['Dev1'] + list_available_devices = lambda: ['Dev1'] class ProtocolError(Exception): @@ -68,7 +69,7 @@ class DummyDaqRunner(object): log.info('runner started') for i in xrange(self.config.number_of_ports): rows = [['power', 'voltage']] + [[random.gauss(1.0, 1.0), random.gauss(1.0, 0.1)] - for j in xrange(self.num_rows)] + for _ in xrange(self.num_rows)] with open(self.get_port_file_path(self.config.labels[i]), 'wb') as wfh: writer = csv.writer(wfh) writer.writerows(rows) @@ -139,7 +140,7 @@ class DaqServer(object): else: raise ProtocolError('Stop called before a session has been configured.') - def list_devices(self): + def list_devices(self): # pylint: disable=no-self-use return list_available_devices() def list_ports(self): @@ -205,7 +206,10 @@ class DaqControlProtocol(LineReceiver): # pylint: disable=W0223 try: request = DaqServerRequest.deserialize(line) except Exception, e: # pylint: disable=W0703 - self.sendError('Received bad request ({}: {})'.format(e.__class__.__name__, e.message)) + # PyDAQmx exceptions use "mess" rather than the standard "message" + # to pass errors... + message = getattr(e, 'mess', e.message) + self.sendError('Received bad request ({}: {})'.format(e.__class__.__name__, message)) else: self.processRequest(request) @@ -269,8 +273,12 @@ class DaqControlProtocol(LineReceiver): # pylint: disable=W0223 self.sendError('Invalid pull request; port id not provided.') def list_devices(self, request): - devices = self.daq_server.list_devices() - self.sendResponse(Status.OK, data={'devices': devices}) + if CAN_ENUMERATE_DEVICES: + devices = self.daq_server.list_devices() + self.sendResponse(Status.OK, data={'devices': devices}) + else: + message = "Server does not support DAQ device enumration" + self.sendResponse(Status.OKISH, message=message) def list_ports(self, request): port_labels = self.daq_server.list_ports() @@ -303,7 +311,7 @@ class DaqControlProtocol(LineReceiver): # pylint: disable=W0223 def sendLine(self, line): log.info('Responding: {}'.format(line)) - LineReceiver.sendLine(self, line.replace('\r\n','')) + LineReceiver.sendLine(self, line.replace('\r\n', '')) def _initiate_file_transfer(self, filepath): sender_factory = FileSenderFactory(filepath, self.factory) @@ -463,7 +471,7 @@ def run_server(): DaqRunner = DummyDaqRunner else: if not DaqRunner: - raise ImportError('DaqRunner') + raise __import_error # pylint: disable=raising-bad-type if args.verbose or args.debug: log.start_logging('DEBUG') else: @@ -471,7 +479,8 @@ def run_server(): server = DaqServer(args.directory) reactor.listenTCP(args.port, DaqFactory(server)).getHost() - hostname = socket.gethostbyname(socket.gethostname()) + #hostname = socket.gethostbyname(socket.gethostname()) + hostname = '192.168.108.131' log.info('Listening on {}:{}'.format(hostname, args.port)) reactor.run() diff --git a/wlauto/instrumentation/daq/__init__.py b/wlauto/instrumentation/daq/__init__.py index 60d759ee..16e11907 100644 --- a/wlauto/instrumentation/daq/__init__.py +++ b/wlauto/instrumentation/daq/__init__.py @@ -134,8 +134,8 @@ class Daq(Instrument): ] def initialize(self, context): - devices = self._execute_command('list_devices') - if not devices: + status, devices = self._execute_command('list_devices') + if status == daq.Status.OK and not devices: raise InstrumentError('DAQ: server did not report any devices registered with the driver.') self._results = OrderedDict() @@ -235,7 +235,7 @@ class Daq(Instrument): raise InstrumentError('DAQ: {}'.format(result.message)) else: raise InstrumentError('DAQ: Unexpected result: {} - {}'.format(result.status, result.message)) - return result.data + return (result.status, result.data) def _send_daq_command(q, *args, **kwargs):