From 823ce718bf0edc6baa99c2184fe479186771988f Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Wed, 30 Aug 2017 14:55:42 +0100 Subject: [PATCH] instrument: add get_raw() API Derived metrics may be calculated form data in raw output that is not present in the resulting MeasurementCSV. This adds a method to provide uniform access to raw artifacts generated by an instrument. --- devlib/instrument/__init__.py | 3 +++ devlib/instrument/acmecape.py | 3 +++ devlib/instrument/daq.py | 6 ++++++ devlib/instrument/energy_probe.py | 11 ++++++++--- devlib/instrument/frames.py | 10 +++++++--- doc/instrumentation.rst | 11 +++++++++-- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/devlib/instrument/__init__.py b/devlib/instrument/__init__.py index 6d11eda..74113a3 100644 --- a/devlib/instrument/__init__.py +++ b/devlib/instrument/__init__.py @@ -297,3 +297,6 @@ class Instrument(object): def get_data(self, outfile): pass + + def get_raw(self): + return [] diff --git a/devlib/instrument/acmecape.py b/devlib/instrument/acmecape.py index e1bb6c1..1053c9d 100644 --- a/devlib/instrument/acmecape.py +++ b/devlib/instrument/acmecape.py @@ -121,3 +121,6 @@ class AcmeCapeInstrument(Instrument): output_row.append(float(row[i])/1000) writer.writerow(output_row) return MeasurementsCsv(outfile, self.active_channels, self.sample_rate_hz) + + def get_raw(self): + return [self.raw_data_file] diff --git a/devlib/instrument/daq.py b/devlib/instrument/daq.py index 75e854d..d497151 100644 --- a/devlib/instrument/daq.py +++ b/devlib/instrument/daq.py @@ -33,6 +33,7 @@ class DaqInstrument(Instrument): # pylint: disable=no-member super(DaqInstrument, self).__init__(target) self._need_reset = True + self._raw_files = [] if execute_command is None: raise HostError('Could not import "daqpower": {}'.format(import_error_mesg)) if labels is None: @@ -68,6 +69,7 @@ class DaqInstrument(Instrument): if not result.status == Status.OK: # pylint: disable=no-member raise HostError(result.message) self._need_reset = False + self._raw_files = [] def start(self): if self._need_reset: @@ -86,6 +88,7 @@ class DaqInstrument(Instrument): site = os.path.splitext(entry)[0] path = os.path.join(tempdir, entry) raw_file_map[site] = path + self._raw_files.append(path) active_sites = unique([c.site for c in self.active_channels]) file_handles = [] @@ -131,6 +134,9 @@ class DaqInstrument(Instrument): for fh in file_handles: fh.close() + def get_raw(self): + return self._raw_files + def teardown(self): self.execute('close') diff --git a/devlib/instrument/energy_probe.py b/devlib/instrument/energy_probe.py index 5f47430..c8f179e 100644 --- a/devlib/instrument/energy_probe.py +++ b/devlib/instrument/energy_probe.py @@ -52,6 +52,7 @@ class EnergyProbeInstrument(Instrument): self.raw_output_directory = None self.process = None self.sample_rate_hz = 10000 # Determined empirically + self.raw_data_file = None for label in self.labels: for kind in self.attributes: @@ -64,6 +65,7 @@ class EnergyProbeInstrument(Instrument): for i, rval in enumerate(self.resistor_values)] rstring = ''.join(parts) self.command = '{} -d {} -l {} {}'.format(self.caiman, self.device_entry, rstring, self.raw_output_directory) + self.raw_data_file = None def start(self): self.logger.debug(self.command) @@ -92,10 +94,10 @@ class EnergyProbeInstrument(Instrument): num_of_ports = len(self.resistor_values) struct_format = '{}I'.format(num_of_ports * self.attributes_per_sample) not_a_full_row_seen = False - raw_data_file = os.path.join(self.raw_output_directory, '0000000000') + self.raw_data_file = os.path.join(self.raw_output_directory, '0000000000') - self.logger.debug('Parsing raw data file: {}'.format(raw_data_file)) - with open(raw_data_file, 'rb') as bfile: + self.logger.debug('Parsing raw data file: {}'.format(self.raw_data_file)) + with open(self.raw_data_file, 'rb') as bfile: with open(outfile, 'wb') as wfh: writer = csv.writer(wfh) writer.writerow(active_channels) @@ -114,3 +116,6 @@ class EnergyProbeInstrument(Instrument): else: not_a_full_row_seen = True return MeasurementsCsv(outfile, self.active_channels, self.sample_rate_hz) + + def get_raw(self): + return [self.raw_data_file] diff --git a/devlib/instrument/frames.py b/devlib/instrument/frames.py index d1899fb..54869c1 100644 --- a/devlib/instrument/frames.py +++ b/devlib/instrument/frames.py @@ -20,6 +20,7 @@ class FramesInstrument(Instrument): self.collector = None self.header = None self._need_reset = True + self._raw_file = None self._init_channels() def reset(self, sites=None, kinds=None, channels=None): @@ -27,6 +28,7 @@ class FramesInstrument(Instrument): self.collector = self.collector_cls(self.target, self.period, self.collector_target, self.header) self._need_reset = False + self._raw_file = None def start(self): if self._need_reset: @@ -38,14 +40,16 @@ class FramesInstrument(Instrument): self._need_reset = True def get_data(self, outfile): - raw_outfile = None if self.keep_raw: - raw_outfile = outfile + '.raw' - self.collector.process_frames(raw_outfile) + self._raw_file = outfile + '.raw' + self.collector.process_frames(self._raw_file) active_sites = [chan.label for chan in self.active_channels] self.collector.write_frames(outfile, columns=active_sites) return MeasurementsCsv(outfile, self.active_channels, self.sample_rate_hz) + def get_raw(self): + return [self._raw_file] if self._raw_file else [] + def _init_channels(self): raise NotImplementedError() diff --git a/doc/instrumentation.rst b/doc/instrumentation.rst index 6f381b4..f23fc3e 100644 --- a/doc/instrumentation.rst +++ b/doc/instrumentation.rst @@ -65,8 +65,8 @@ Instrument :INSTANTANEOUS: The instrument supports taking a single sample via ``take_measurement()``. :CONTINUOUS: The instrument supports collecting measurements over a - period of time via ``start()``, ``stop()``, and - ``get_data()`` methods. + period of time via ``start()``, ``stop()``, ``get_data()``, + and (optionally) ``get_raw`` methods. .. note:: It's possible for one instrument to support more than a single mode. @@ -161,6 +161,13 @@ Instrument .. note:: This method is only implemented by :class:`Instrument`\ s that support ``CONTINUOUS`` measurement. +.. method:: Instrument.get_raw() + + Returns a list of paths to files containing raw output from the underlying + source(s) that is used to produce the data CSV. If now raw output is + generated or saved, an empty list will be returned. The format of the + contents of the raw files is entirely source-dependent. + .. attribute:: Instrument.sample_rate_hz Sample rate of the instrument in Hz. Assumed to be the same for all channels.