def test_write_read_stats_over_samples_offset(self):
     fh = self._create_file(0, 2)
     r = DataReader()
     r.raw_processor.suppress_mode = 'off'
     r.open(fh)
     data = r.data_get(7, 50, 10)
     np.testing.assert_allclose(np.arange(23, 90, 20), data[:, 0]['mean'])
 def test_create_single(self):
     fh = self._create_file_insert(0, 2, 2)
     r = DataReader()
     r.raw_processor.suppress_mode = 'off'
     r.open(fh)
     self.assertEqual([0, 252], r.sample_id_range)
     self.assertEqual(1000, r.output_sampling_frequency)
     self.assertEqual(0.05, r.reduction_frequency)
     self.assertEqual(0.252, r.duration)
     self.assertEqual(0.0, r.sample_id_to_time(0))
     self.assertEqual(0, r.time_to_sample_id(0))
     self.assertEqual(0.2, r.sample_id_to_time(200))
     self.assertEqual(200, r.time_to_sample_id(0.2))
     data = r.data_get(6, 10, 1)
     np.testing.assert_allclose(np.arange(12, 20, 2), data[:, 0]['mean'])
Beispiel #3
0
def run():
    args = get_parser().parse_args()
    reader = DataReader()
    reader.open(args.infile)
    s_min, s_max = reader.sample_id_range
    sample_count = s_max - s_min
    writer = DataRecorder(args.outfile, reader.calibration, reader.user_data)
    block_size = int(reader.sampling_frequency)
    print(f'samples={sample_count}, fs={reader.sampling_frequency}')
    block_count = (sample_count + block_size - 1) // block_size
    for block in range(block_count):
        offset = block * block_size
        offset_next = offset + block_size
        if offset_next > sample_count:
            offset_next = sample_count
        data = reader.samples_get(offset, offset_next, 'samples')
        writer.insert(data)
        progress(block, block_count - 1)
    reader.close()
    writer.close()
    return 0
class RecordingViewerDevice:
    """A user-interface-compatible device that displays previous recorded data

    :param filename: The filename path to the pre-recorded data.
    """
    def __init__(self, filename, current_ranging_format=None):
        if isinstance(filename, str) and not os.path.isfile(filename):
            raise IOError('file not found')
        self._filename = filename
        self._current_ranging_format = current_ranging_format
        self._reader = None
        self._views = []
        self._coalesce = {}
        self._thread = None
        self._cmd_queue = queue.Queue()  # tuples of (command, args, callback)
        self._response_queue = queue.Queue()
        self._quit = False
        self._log = logging.getLogger(__name__)

    def __str__(self):
        return os.path.basename(self._filename)

    @property
    def sampling_frequency(self):
        if self._reader is None:
            return None
        return self._reader.sampling_frequency

    @property
    def calibration(self):
        if self._reader is None:
            return None
        return self._reader.calibration

    @property
    def voltage_range(self):
        return self._reader.voltage_range

    def _cmd_process(self, cmd, view, args, cbk):
        rv = None
        try:
            # self._log.debug('_cmd_process %s - start', cmd)
            if cmd == 'refresh':
                view._refresh_requested = True
            elif cmd == 'on_x_change':
                rv = view._on_x_change(*args)
            elif cmd == 'samples_get':
                rv = view._samples_get(**args)
            elif cmd == 'statistics_get':
                rv = view._statistics_get(**args)
            elif cmd == 'statistics_get_multiple':
                rv = view._statistics_get_multiple(**args)
            elif cmd == 'view_factory':
                self._views.append(args)
                rv = args
            elif cmd == 'view_close':
                if args in self._views:
                    self._views.remove(args)
            elif cmd == 'open':
                rv = self._open()
            elif cmd == 'close':
                rv = self._close()
            elif cmd == 'ping':
                rv = args
            else:
                self._log.warning('unsupported command %s', cmd)
        except:
            self._log.exception('While running command')
        if callable(cbk):
            try:
                cbk(rv)
            except:
                self._log.exception('in callback')

    def run(self):
        cmd_count = 0
        timeout = 1.0
        self._log.info('RecordingViewerDevice.start')
        while not self._quit:
            try:
                cmd, view, args, cbk = self._cmd_queue.get(timeout=timeout)
            except queue.Empty:
                timeout = 1.0
                for value in self._coalesce.values():
                    self._cmd_process(*value)
                self._coalesce.clear()
                for view in self._views:
                    if view._refresh_requested:
                        view._update()
                cmd_count = 0
                continue
            cmd_count += 1
            timeout = 0.0
            try:
                source_id = args.pop('source_id')
            except:
                source_id = None
            if source_id is not None:
                key = f'{view}_{cmd}_{source_id}'  # keep most recent only
                self._coalesce[key] = (cmd, view, args, cbk)
            else:
                self._cmd_process(cmd, view, args, cbk)
        self._log.info('RecordingViewerDevice.run done')

    def _post(self, command, view=None, args=None, cbk=None):
        if self._thread is None:
            self._log.info('RecordingViewerDevice._post(%s) when thread not running', command)
        else:
            self._cmd_queue.put((command, view, args, cbk))

    def _post_block(self, command, view=None, args=None, timeout=None):
        timeout = TIMEOUT if timeout is None else float(timeout)
        # self._log.debug('_post_block %s start', command)
        while not self._response_queue.empty():
            self._log.warning('response queue not empty')
            try:
                self._response_queue.get(timeout=0.0)
            except queue.Empty:
                pass
        if self._thread is None:
            raise IOError('View thread not running')
        self._post(command, view, args, lambda rv_=None: self._response_queue.put(rv_))
        try:
            rv = self._response_queue.get(timeout=timeout)
        except queue.Empty as ex:
            self._log.error('RecordingViewerDevice thread hung: %s - FORCE CLOSE', command)
            self._post('close', None, None)
            self._thread.join(timeout=TIMEOUT)
            self._thread = None
            rv = ex
        except Exception as ex:
            rv = ex
        if isinstance(rv, Exception):
            raise IOError(rv)
        # self._log.debug('_post_block %s done', command)  # rv
        return rv

    def _open(self):
        self._reader = DataReader()
        if self._current_ranging_format is not None:
            self._reader.raw_processor.suppress_mode = self._current_ranging_format
        self._reader.open(self._filename)  # todo progress bar updates
        self._log.info('RecordingViewerDevice.open')

    def _close(self):
        if self._reader is not None:
            self._reader.close()
            self._reader = None
        self._quit = True

    def view_factory(self):
        view = RecordingView(self)
        return self._post_block('view_factory', None, view)

    def open(self, event_callback_fn=None):
        self.close()
        self._log.info('open')
        self._thread = threading.Thread(name='view', target=self.run)
        self._thread.start()
        self._post_block('open')

    def close(self):
        if self._thread is not None:
            self._log.info('close')
            try:
                self._post_block('close')
            except Exception:
                self._log.exception('while attempting to close')
            self._thread.join(timeout=TIMEOUT)
            self._thread = None