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