Exemplo n.º 1
0
    def __init__(self, app, quit_app_on_stop):
        # noinspection PyArgumentList
        super().__init__(parent=None)
        self._app = app
        self._quit_app_on_stop = quit_app_on_stop

        self._entries = {}

        self._tick = 0
        self._fn0 = self._t0 = 0

        self._lbl_backends = None
        self._lbl_started = None
        self._lbl_fps = None

        self._init_ui()

        self.flyvr_shared_state = SharedState(options=None,
                                              logger=None,
                                              where='gui')

        self._timer = QTimer()
        # noinspection PyUnresolvedReferences
        self._timer.timeout.connect(self._update_state)
        self._timer.start(1000 / FlyVRStateGui.FPS)
Exemplo n.º 2
0
def do_loop(exp, delay, force=False):
    from flyvr.common import SharedState

    flyvr_state = SharedState(None, None)
    data = flyvr_state._fictrac_shmem_state
    old_frame_count = data.frame_cnt

    while flyvr_state.is_running_well():
        new_frame_count = data.frame_cnt
        if (old_frame_count != new_frame_count) or force:
            exp.process_state(data)
            old_frame_count = new_frame_count
            time.sleep(delay)
Exemplo n.º 3
0
def test_play_sin(tmpdir):
    import time
    import h5py

    stim1 = SinStim(frequency=200,
                    amplitude=1.0,
                    phase=0.0,
                    sample_rate=44100,
                    duration=10000)

    dest = tmpdir.join('test.h5').strpath

    with DatasetLogServer() as log_server:
        logger = log_server.start_logging_server(dest)

        options = Dottable(wait=False)
        shared_state = SharedState(options, logger)

        sound_server = SoundServer(flyvr_shared_state=shared_state)
        sound_server.start_stream(
            frames_per_buffer=SoundServer.DEFAULT_CHUNK_SIZE)
        sound_server.queue.put(stim1)
        time.sleep(1.5)

        sound_server.quit()

    with h5py.File(dest, mode='r') as h5:
        assert h5['audio']['chunk_synchronization_info'].shape[
            -1] == SampleChunk.SYNCHRONIZATION_INFO_NUM_FIELDS
Exemplo n.º 4
0
def test_io_a_output(tmpdir):
    import time

    import h5py

    with DatasetLogServer() as log_server:

        shared_state = SharedState(None,
                                   logger=log_server.start_logging_server(
                                       tmpdir.join('test.h5').strpath))

        taskAO = IOTask(cha_ids=['ao1'],
                        cha_type="output",
                        num_samples_per_chan=DAQ_NUM_OUTPUT_SAMPLES,
                        num_samples_per_event=DAQ_NUM_OUTPUT_SAMPLES_PER_EVENT,
                        shared_state=shared_state)

        taskAO.StartTask()
        for i in range(10):
            time.sleep(0.1)

        taskAO.StopTask()
        taskAO.stop()
        taskAO.ClearTask()

    with h5py.File(shared_state.logger.log_filename, mode='r') as h5:
        assert h5['daq']['chunk_synchronization_info'].shape[
            -1] == SampleChunk.SYNCHRONIZATION_INFO_NUM_FIELDS
Exemplo n.º 5
0
def main_ipc_send():
    import json
    import time
    import argparse

    from flyvr.common.build_arg_parser import setup_logging
    from flyvr.common import SharedState

    parser = argparse.ArgumentParser()
    parser.add_argument('-v', help='Verbose output', default=False, dest='verbose', action='store_true')
    parser.add_argument('--start', action='store_true', help='send start signal')
    parser.add_argument('--stop', action='store_true', help='send stop signal')
    parser.add_argument('json', nargs='?', help='raw json message contents (see README)')
    args = parser.parse_args()

    if args.start:
        setup_logging(args)
        SharedState(None, None, '').signal_start().join(timeout=5)
        return parser.exit(0)

    if args.stop:
        setup_logging(args)
        SharedState(None, None, '').signal_stop().join(timeout=5)
        return parser.exit(0)

    if not args.json:
        return parser.exit(0, 'nothing to do')

    # noinspection PyBroadException
    try:
        dat = json.loads(args.json)
    except json.JSONDecodeError as exc:
        print("PARSE ERROR:\t\n\t", (args.json, exc))
        return parser.exit(1)

    send = PlaylistSender()
    time.sleep(1.0)

    # warm up the pub/sub to give subscribers the chance to connect. this utility is transient and
    # only used for debugging, so this problem doesnt manifest in long running applications
    for i in range(10):
        send.process()

    send.process(**dat)
    send.close(block=True)
    print("SENT: %r" % dat)
Exemplo n.º 6
0
    def run(self, options):

        flyvr_shared_state = SharedState(options=options,
                                         logger=None,
                                         where=BACKEND_HWIO,
                                         _start_rx_thread=False)

        # todo: only if all the things are connected? at least scanimage?
        _ = flyvr_shared_state.signal_ready(BACKEND_HWIO)

        with open(options.record_file.replace('.h5', '.toc.yml'), 'wt') as f:

            def _streaming_yaml_record(_msg):
                # stream yaml records (list of dicts) to the file
                f.write('- ')
                f.write(json.dumps(_msg))
                f.write('\n')
                f.flush()

            while True:
                msg = self._rx.get_next_element()
                if msg:
                    if CommonMessages.EXPERIMENT_PLAYLIST_ITEM in msg:

                        # a backend is playing a new playlist item
                        self._flash_led()

                        if self._tp_enable:
                            self.next_image()

                        _streaming_yaml_record(msg)

                    if CommonMessages.EXPERIMENT_START in msg:
                        # noinspection PyProtectedMember
                        msg = flyvr_shared_state._build_toc_message(
                            'experiment')
                        msg['identifier'] = '_start'
                        _streaming_yaml_record(msg)

                    if CommonMessages.EXPERIMENT_STOP in msg:
                        break

        self._log.info('stopped')

        self.stop_scanimage()
        self.close()
Exemplo n.º 7
0
def run_sound_server(options, quit_evt=None):
    from flyvr.common import SharedState, Randomizer
    from flyvr.common.logger import DatasetLogServerThreaded
    from flyvr.audio.util import get_paylist_object

    setup_logging(options)

    log = logging.getLogger('flyvr.main_sound_server')

    playlist_stim, basedirs = get_paylist_object(
        options,
        playlist_type='audio',
        # optional because we are also called
        # from flyvr main launcher
        paused_fallback=getattr(options, 'paused', False),
        # dudi requested to preserve the last default
        default_repeat=Randomizer.REPEAT_FOREVER,
        attenuator=None)  # fixme: attenuator from config
    if playlist_stim is not None:
        log.info('initialized audio playlist: %r' % playlist_stim)

    with DatasetLogServerThreaded() as log_server:
        logger = log_server.start_logging_server(
            options.record_file.replace('.h5', '.sound_server.h5'))
        state = SharedState(options=options,
                            logger=logger,
                            where=BACKEND_AUDIO)

        sound_server = SoundServer(flyvr_shared_state=state)
        if playlist_stim is not None:
            sound_server.queue.put(playlist_stim)

        ipc = threading.Thread(daemon=True,
                               name='AudioIpcThread',
                               target=_ipc_main,
                               args=(sound_server.queue, basedirs))
        ipc.start()

        # starts the thread
        sound_server.start_stream(
            frames_per_buffer=SoundServer.DEFAULT_CHUNK_SIZE)

        if quit_evt is not None:
            # the single process launcher
            try:
                quit_evt.wait()
            except KeyboardInterrupt:
                sound_server.queue.put(_QUIT)

        sound_server.join()

    log.info('finished')
Exemplo n.º 8
0
    def run(self, options):
        setup_logging(options)

        log = logging.getLogger('flyvr.fictrac.FicTracDriverReplay')

        setup_experiment(options)
        if options.experiment:
            log.info('initialized experiment %r' % options.experiment)

        flyvr_shared_state = SharedState(options=options,
                                         logger=None,
                                         where=BACKEND_FICTRAC)
        if options.experiment:
            # noinspection PyProtectedMember
            options.experiment._set_shared_state(flyvr_shared_state)

        replay = FicTracDriverReplay.StateReplayFictrac(flyvr_shared_state,
                                                        options.experiment,
                                                        self._h5_path)
        replay.replay()  # blocks

        log.info('stopped')
Exemplo n.º 9
0
def run_io(options):
    from flyvr.common import SharedState
    from flyvr.common.logger import DatasetLogServerThreaded

    setup_logging(options)

    q = queue.Queue()
    basedirs = [os.getcwd()]
    if getattr(options, '_config_file_path'):
        # noinspection PyProtectedMember
        basedirs.insert(0, os.path.dirname(options._config_file_path))

    ipc = threading.Thread(daemon=True,
                           name='DAQIpcThread',
                           target=_ipc_main,
                           args=(q, basedirs))
    ipc.start()

    with DatasetLogServerThreaded() as log_server:
        logger = log_server.start_logging_server(
            options.record_file.replace('.h5', '.daq.h5'))
        state = SharedState(options=options, logger=logger, where=BACKEND_DAQ)
        io_task_loop(q, state, options)
Exemplo n.º 10
0
def main_experiment():
    from flyvr.common.build_arg_parser import build_argparser, parse_options, setup_experiment, setup_logging

    parser = build_argparser()
    parser.add_argument(
        '--force',
        action='store_true',
        help='force/fake iterate at 200fps even if no tracking data '
        'is present (for testing)')

    options = parse_options(parser.parse_args(), parser)
    setup_logging(options)

    setup_experiment(options)
    if not options.experiment:
        parser.error("No experiment specified")

    # noinspection PyProtectedMember
    options.experiment._set_shared_state(
        SharedState(options=options, logger=None))

    # noinspection PyProtectedMember
    options.experiment._log_describe()
    do_loop(options.experiment, 1 / 200., options.force)
Exemplo n.º 11
0
    def run(self, options=None):
        """
        Start the the FicTrac process and block till it closes. This function will poll a shared memory region for
        changes in tracking data and invoke a control function when they occur. FicTrac is assumed to exist on the
        system path.

        Args:
            options: options loaded from FlyVR config file. If None, driver runs without logging enabled, this is useful
                for testing.

        :return:
        """

        if options is not None:
            setup_logging(options)

            setup_experiment(options)
            if options.experiment:
                self._log.info('initialized experiment %r' %
                               options.experiment)
            self.experiment = options.experiment

            # fixme: this should be threaded and context manager to close
            log_server = DatasetLogServer()

            flyvr_shared_state = SharedState(
                options=options,
                logger=log_server.start_logging_server(options.record_file),
                where=BACKEND_FICTRAC)
            if self.experiment:
                # noinspection PyProtectedMember
                self.experiment._set_shared_state(flyvr_shared_state)

            # Setup dataset to log FicTrac data to.
            flyvr_shared_state.logger.create(
                "/fictrac/output",
                shape=[2048, NUM_FICTRAC_FIELDS],
                maxshape=[None, NUM_FICTRAC_FIELDS],
                dtype=np.float64,
                chunks=(2048, NUM_FICTRAC_FIELDS))
            flyvr_shared_state.logger.log("/fictrac/output",
                                          H5_DATA_VERSION,
                                          attribute_name='__version')
        else:
            flyvr_shared_state = None

        self.fictrac_signals = new_mmap_signals_buffer()

        # Start FicTrac
        with open(self.console_output_file, "wb") as out:

            self.fictrac_process = subprocess.Popen(
                [self.fictrac_bin_fullpath, self.config_file],
                stdout=out,
                stderr=subprocess.STDOUT)

            # Setup the shared memory conneciton and peek at the frame counter
            data = new_mmap_shmem_buffer()
            first_frame_count = data.frame_cnt
            old_frame_count = data.frame_cnt

            running = True
            self._log.info("waiting for fictrac updates in shared memory")

            semaphore = self._open_fictrac_semaphore()

            # Process FicTrac updates in shared memory
            while (self.fictrac_process.poll() is
                   None) and running and semaphore:

                # Acquire the semaphore copy the current fictrac state.
                try:
                    semaphore.acquire(timeout_ms=1000)
                    data_copy = SHMEMFicTracState()
                    ctypes.pointer(data_copy)[0] = data
                    semaphore.release()
                except FileNotFoundError:
                    # Semaphore is gone, lets shutdown things.
                    break
                except OSError:
                    break

                new_frame_count = data_copy.frame_cnt

                if old_frame_count != new_frame_count:
                    # If this is our first frame incremented, then send a signal to the
                    # that we have started processing frames
                    if old_frame_count == first_frame_count:
                        if flyvr_shared_state:
                            _ = flyvr_shared_state.signal_ready(
                                BACKEND_FICTRAC)

                    if new_frame_count - old_frame_count != 1:
                        # self.fictrac_process.terminate()
                        self._log.error(
                            "frame counter jumped by more than 1 (%s vs %s)" %
                            (old_frame_count, new_frame_count))

                    old_frame_count = new_frame_count

                    # Log the FicTrac data to our master log file.
                    if flyvr_shared_state:
                        flyvr_shared_state.logger.log(
                            '/fictrac/output', fictrac_state_to_vec(data_copy))

                    if self.experiment is not None:
                        self.experiment.process_state(data_copy)

                # If we detect it is time to shutdown, kill the FicTrac process
                if flyvr_shared_state and flyvr_shared_state.is_stopped():
                    running = False

            # Try to close up the semaphore
            try:
                if semaphore:
                    semaphore.close()
            except OSError:
                pass

        self.stop()  # blocks

        self._log.info('fictrac process finished')

        # Get the fictrac process return code
        if self.fictrac_process.returncode is not None and self.fictrac_process.returncode != 0:
            self._log.error(
                'fictrac failed because of an application error. Consult the fictrac console output file'
            )

            if flyvr_shared_state:
                flyvr_shared_state.runtime_error(2)
Exemplo n.º 12
0
def main_launcher():
    options = parse_arguments()
    # flip the default vs the individual launchers - wait for all of the backends
    options.wait = True

    # save the total state
    _opts = get_printable_options_dict(options,
                                       include_experiment_and_playlist=True)
    with open(options.record_file.replace('.h5', '.config.yml'), 'wt') as f:
        yaml.safe_dump(_opts, f)

    log = logging.getLogger('flyvr.main')

    flyvr_shared_state = SharedState(options=options,
                                     logger=None,
                                     where='main')

    # start the IPC bus first as it is needed by many subsystems
    ipc_bus = ConcurrentTask(task=run_main_relay, comms=None, taskinitargs=[])
    ipc_bus.start()

    # start the GUI
    gui = ConcurrentTask(task=run_main_state_gui,
                         comms=None,
                         taskinitargs=[None, True])
    gui.start()

    backend_wait = [BACKEND_FICTRAC]

    trac_drv = _get_fictrac_driver(options, log)
    if trac_drv is not None:
        fictrac_task = ConcurrentTask(task=trac_drv.run,
                                      comms=None,
                                      taskinitargs=[options])
        fictrac_task.start()

        # wait till fictrac is processing frames
        flyvr_shared_state.wait_for_backends(BACKEND_FICTRAC)
        log.info('fictrac is ready')

    # start the other mainloops

    # these always run
    hwio = ConcurrentTask(task=run_phidget_io,
                          comms=None,
                          taskinitargs=[options])
    backend_wait.append(BACKEND_HWIO)
    hwio.start()

    daq = ConcurrentTask(task=run_io, comms=None, taskinitargs=[options])
    backend_wait.append(BACKEND_DAQ)
    daq.start()

    # these are optional
    if options.keepalive_video or options.playlist.get('video'):
        video = ConcurrentTask(task=run_video_server,
                               comms=None,
                               taskinitargs=[options])
        backend_wait.append(BACKEND_VIDEO)
        video.start()
    else:
        video = None
        log.info(
            'not starting video backend (playlist empty or keepalive_video not specified)'
        )

    if options.keepalive_audio or options.playlist.get('audio'):
        audio = ConcurrentTask(task=run_sound_server,
                               comms=None,
                               taskinitargs=[options])
        backend_wait.append(BACKEND_AUDIO)
        audio.start()
    else:
        audio = None
        log.info(
            'not starting video backend (playlist empty or keepalive_video not specified)'
        )

    log.info('waiting %ss for %r to be ready' % (60, backend_wait))
    if flyvr_shared_state.wait_for_backends(*backend_wait, timeout=60):

        if options.delay < 0:
            log.info('waiting for manual start signal')
            flyvr_shared_state.wait_for_start()
        elif options.delay >= 0:
            if options.delay > 0:
                log.info('delaying startup %ss' % options.delay)
                time.sleep(options.delay)
            log.info('sending start signal')
            flyvr_shared_state.signal_start()

        for i in itertools.count():
            try:
                inputimeout(
                    '\n---------------\nPress any key to finish\n---------------\n\n'
                    if i == 0 else '', 1)
                flyvr_shared_state.signal_stop().join(timeout=5)
                break
            except TimeoutOccurred:
                if flyvr_shared_state.is_stopped():
                    # stopped from elsewhere (gui)
                    break

    else:
        log.error(
            'not all required backends became ready - please check logs for '
            'error messages')
        flyvr_shared_state.signal_stop()

    log.info('stopped')

    for task in (ipc_bus, gui, hwio, daq, video, audio):
        if task is not None:
            log.debug('closing subprocess: %r' % task)
            task.close()

    log.info('finished')
Exemplo n.º 13
0
def run_video_server(options):
    from flyvr.common import SharedState, Randomizer
    from flyvr.common.logger import DatasetLogServerThreaded

    setup_logging(options)

    log = logging.getLogger('flyvr.video.main')

    startup_stim = None
    playlist_stim = None
    stim_playlist = options.playlist.get('video')

    if stim_playlist:
        option_item_defn = {}

        stims = []
        for item_def in stim_playlist:
            id_, defn = item_def.popitem()

            if id_ == Randomizer.IN_PLAYLIST_IDENTIFIER:
                option_item_defn = {id_: defn}
                continue

            stims.append(stimulus_factory(defn.pop('name'), identifier=id_, **defn))

        random = Randomizer.new_from_playlist_option_item(option_item_defn,
                                                          *[s.identifier for s in stims])
        paused = option_item_defn.pop('paused', None)

        playlist_stim = VideoStimPlaylist(*stims, random=random,
                                          paused=paused if paused is not None else getattr(options, 'paused', False),
                                          play_item=getattr(options, 'play_item', None))
        log.info('initialized video playlist: %r' % playlist_stim)

    elif getattr(options, 'play_stimulus', None):
        startup_stim = stimulus_factory(options.play_stimulus)
        log.info('selecting single visual stimulus: %s' % options.play_stimulus)

    with DatasetLogServerThreaded() as log_server:
        logger = log_server.start_logging_server(options.record_file.replace('.h5', '.video_server.h5'))
        state = SharedState(options=options, logger=logger, where=BACKEND_VIDEO)

        video_server = VideoServer(calibration_file=options.screen_calibration,
                                   shared_state=state,
                                   use_lightcrafter=not getattr(options, 'projector_disable', False))

        if playlist_stim is not None:
            video_server.queue.put(playlist_stim)
        elif startup_stim is not None:
            video_server.queue.put(startup_stim)

        ipc = threading.Thread(daemon=True, name='VideoIpcThread',
                               target=_ipc_main, args=(video_server.queue,))
        ipc.start()

        try:
            video_server.run()  # blocks
        except KeyboardInterrupt:
            video_server.quit()

    log.info('finished')
Exemplo n.º 14
0
class FlyVRStateGui(QWidget):

    STATE = [
        'FICTRAC_FRAME_NUM', 'SOUND_OUTPUT_NUM_SAMPLES_WRITTEN',
        'VIDEO_OUTPUT_NUM_FRAMES', 'DAQ_OUTPUT_NUM_SAMPLES_WRITTEN',
        'DAQ_INPUT_NUM_SAMPLES_READ'
    ]
    FPS = 30

    def __init__(self, app, quit_app_on_stop):
        # noinspection PyArgumentList
        super().__init__(parent=None)
        self._app = app
        self._quit_app_on_stop = quit_app_on_stop

        self._entries = {}

        self._tick = 0
        self._fn0 = self._t0 = 0

        self._lbl_backends = None
        self._lbl_started = None
        self._lbl_fps = None

        self._init_ui()

        self.flyvr_shared_state = SharedState(options=None,
                                              logger=None,
                                              where='gui')

        self._timer = QTimer()
        # noinspection PyUnresolvedReferences
        self._timer.timeout.connect(self._update_state)
        self._timer.start(1000 / FlyVRStateGui.FPS)

    def _update_state(self):
        for s in FlyVRStateGui.STATE:
            v = getattr(self.flyvr_shared_state, s)
            self._entries[s].setText(str(v or 0))

        self._lbl_backends.setText(', '.join(
            self.flyvr_shared_state.backends_ready))
        self._lbl_started.setText(str(self.flyvr_shared_state.is_started()))

        # every second-ish
        if (self._tick % self.FPS) == 0:
            fictrac_fps = (self.flyvr_shared_state.FICTRAC_FRAME_NUM -
                           self._fn0) / (time.time() - self._t0)
            self._lbl_fps.setText('%.1f' % fictrac_fps)

            self._fn0 = self.flyvr_shared_state.FICTRAC_FRAME_NUM
            self._t0 = time.time()

        self._tick += 1

        if self._quit_app_on_stop:
            if self.flyvr_shared_state.is_stopped():
                self._app.quit()

    def _clicked_clear(self):
        for s in FlyVRStateGui.STATE:
            self._entries[s].setText('')

    def _clicked_start(self):
        self.flyvr_shared_state.signal_start()

    def _clicked_stop(self):
        self.flyvr_shared_state.signal_stop().join(2)

    # noinspection PyUnresolvedReferences,PyArgumentList
    def _init_ui(self):
        self.setWindowTitle('FlyVR')

        layout = QGridLayout()

        # noinspection PyArgumentList
        def _build_label(_name, _row):
            _lbl = QLabel('&%s' % _name, self)
            _edt = QLineEdit(self)
            _edt.setReadOnly(True)
            _lbl.setBuddy(_edt)

            layout.addWidget(_lbl, _row, 0)
            layout.addWidget(_edt, _row, 1, 1, 2)

            return _edt

        row = 0
        for s in FlyVRStateGui.STATE:
            self._entries[s] = _build_label(s, row)
            row += 1

        self._lbl_fps = _build_label('FicTrac Framerate', row)
        row += 1

        self._lbl_backends = _build_label('Backends Ready', row)
        row += 1

        self._lbl_started = _build_label('Experiment Started', row)
        row += 1

        # clear = QPushButton('&Clear')
        # clear.clicked.connect(self._clicked_clear)
        # layout.addWidget(clear, row, 2)
        # row += 1

        start = QPushButton('&Start Experiment')
        start.clicked.connect(self._clicked_start)
        stop = QPushButton('&Stop FlyVR')
        stop.clicked.connect(self._clicked_stop)

        layout.addWidget(start, row, 1)
        layout.addWidget(stop, row, 2)

        row += 1

        self.setLayout(layout)