def main_sound_server(): import yaml import os.path from flyvr.common.build_arg_parser import build_argparser, parse_options from flyvr.audio.util import plot_playlist from zmq.utils.win32 import allow_interrupt parser = build_argparser() parser.add_argument('--print-devices', action='store_true', help='print available audio devices') parser.add_argument('--convert-playlist', help='convert a stimulus playlist to new format') parser.add_argument('--paused', action='store_true', help='start paused') parser.add_argument('--plot', action='store_true', help='plot the stimulus playlist') options = parse_options(parser.parse_args(), parser) if options.plot: setup_logging(options) if not options.playlist.get('audio'): return parser.error('Config file contains no audio playlist') plot_playlist(options, 'audio') return parser.exit(0) if options.convert_playlist: src = options.convert_playlist if os.path.isfile(src): pl = AudioStimPlaylist.from_legacy_filename(src) dest = options.convert_playlist + '.yml' with open(dest, 'wt') as f: yaml.dump({'playlist': {'audio': pl.describe()}}, f) return parser.exit(0, message='Wrote %s' % dest) else: return parser.error('Could not find %s' % src) if options.print_devices: SoundServer.list_supported_asio_output_devices() return parser.exit(0) quit_evt = threading.Event() # noinspection PyUnusedLocal def ctrlc(*args): quit_evt.set() with allow_interrupt(action=ctrlc): run_sound_server(options, quit_evt)
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 main_replay(): import argparse from flyvr.common.build_arg_parser import setup_logging parser = argparse.ArgumentParser() parser.add_argument('--fps', type=float, default=0, help='play back fictrac data at this fps ' '(0 = rate at which it was recorded)') parser.add_argument('-v', help='Verbose output', default=False, dest='verbose', action='store_true') parser.add_argument('h5file', nargs=1, metavar='PATH', help='path to h5 file of previous flyvr session') args = parser.parse_args() setup_logging(args) r = ReplayFictrac(args.h5file[0]) r.replay('auto' if args.fps <= 0 else args.fps)
def run_phidget_io(options): from flyvr.common.build_arg_parser import setup_logging setup_logging(options) io = PhidgetIO( tp_start=options.remote_start_2P_channel, tp_stop=options.remote_stop_2P_channel, tp_next=options.remote_next_2P_channel, tp_enable=not options.remote_2P_disable, signal_next_enable=not options.remote_2P_next_disable, start_after_next_delay=options.scanimage_next_start_delay, debug_led=getattr(options, 'debug_led', 2), remote_details=DEFAULT_REMOTE if options.phidget_network else None) io.run(options)
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 main_io(): from flyvr.common.build_arg_parser import build_argparser, parse_options, setup_logging from flyvr.audio.util import plot_playlist parser = build_argparser() parser.add_argument('--plot', action='store_true', help='plot the stimulus playlist') options = parse_options(parser.parse_args(), parser) if options.plot: setup_logging(options) if not options.playlist.get('daq'): return parser.error('Config file contains no daq playlist') plot_playlist(options, 'daq') return parser.exit(0) run_io(options)
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 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')