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