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
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
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 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)
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')
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)
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()
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')
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)
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)
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)
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')
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')