def _clear_flag(self, flag, wait=False, timeout=10): """Clear flag whose information is in :attr:`._bit_flags`""" # Gather our flag information flag_info = self._bit_flags[flag] bit = flag_info['readback'] mask = flag_info.get('mask', 1) # Create a callback function to check for bit def flag_is_cleared(value=None, **kwargs): return not bool((int(value) >> bit) & mask) # Check that we need to actually set the flag if flag_is_cleared(value=self.bit_status.get()): logger.debug("%s flag is not currently active", flag) st = DeviceStatus(self) st.set_finished() return st # Issue our command logger.info('Clearing %s flag ...', flag) self.seq_seln.put(flag_info['clear']) # Generate a status st = SubscriptionStatus(self.bit_status, flag_is_cleared) if wait: status_wait(st, timeout=timeout) return st
def trigger(self): "Trigger one acquisition." if not self._staged: raise RuntimeError("This detector is not ready to trigger." "Call the stage() method before triggering.") self._save_started = False self._status = DeviceStatus(self) self._desired_number_of_sets = self.number_of_sets.get() self._plugin.num_capture.put(self._desired_number_of_sets) self.dispatch(self._image_name, ttime.time()) # reset the proc buffer, this needs to be generalized self.proc.reset_filter.put(1) self._plugin.capture.put(1) # Now the TIFF plugin is capturing. return self._status
def kickoff(self): '''Start collection Returns ------- DeviceStatus This will be set to done when acquisition has begun ''' # Put scaler in fly mode # self.scaler_mode.put(1, wait=True) # Set monochromator speed self.fly_motor_speed.put(self._speed, wait=True) # Set encoder step size for accumulating counts self.encoder_steps.put(self._encoder_step_counts, wait=True) # Reset scaler array waveform self.scaler_reset.put(1, wait=True) # Reset scaler counter self.scaler_preset.put(0, wait=True) # Wait For HC10E scaler reset ttime.sleep(.2) # Indicators self._start_time = ttime.time() self._acquiring = True self._paused = False # Put scaler in fly mode self.scaler_mode.put(1, wait=True) # Start motor motion to target_position asynchronously _th = self.energyToTheta(self._target_energy) self.fly_motor.put(_th, wait=False) ttime.sleep(0.2) thread = threading.Thread(target=self.checkMotor, daemon=True) thread.start() # make status object, Indicate flying has started self.kickoff_status = DeviceStatus(self) self.kickoff_status._finished(success=True) self.complete_status = DeviceStatus(self) return self.kickoff_status
def move(self, position, wait=True, timeout=None, moved_cb=None): """ Move to a specified position, optionally waiting for motion to complete. Checks for the motor step, and ask the user for confirmation if movement step is greater than default one. """ try: return super().move(position, wait=wait, timeout=timeout, moved_cb=moved_cb) except KappaMoveAbort as exc: logger.warning('Aborting moving for safety.') status = DeviceStatus(self) status.set_exception(exc) return status
def trigger(self): """ Trigger the EventSequencer This method reconfigures the EventSequencer to take a new reading. This means: * Stopping the EventSequencer if it is already running * Restarting the EventSequencer The returned status object will indicate different behavior based on the configuration of the EventSequencer itself. If set to "Run Forever", the status object merely indicates that we have succesfully started our sequence. Otherwise, the status object will be completed when the sequence we have set it to play is complete. """ # Stop the Sequencer if it is already running self.stop() # Fire the EventSequencer self.start() # If we are running forever, count this is as triggered if self.play_mode.get() == 2: logger.debug("EventSequencer is set to run forever, " "trigger is complete") return DeviceStatus(self, done=True, success=True) # Create our status def done(*args, value=None, old_value=None, **kwargs): return value == 2 and old_value == 0 # Create our status object return SubscriptionStatus(self.play_status, done, run=True)
def move(self, new_position, moved_cb=None, **kwargs): print(np.abs(self.position - new_position), .2, self.position, new_position) if np.abs(self.position - new_position) < .2: if moved_cb is not None: moved_cb(obj=self) return DeviceStatus(self, done=True, success=True) return super().move(new_position, moved_cb=moved_cb, **kwargs)
def trigger_internal(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self.settings.erase.put(1) self._acquisition_signal.put(1, wait=False) self._dispatch_channels(trigger_time=time.time()) return self._status
def test_status_with_name(hw): from ophyd.status import DeviceStatus st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) st._finished() st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) assert pbar.delay_draw == 0.2 time.sleep(0.25) st._finished()
def insert(self, timeout=None, finished_cb=None): """ Insert the device into the beampath """ # Complete request self.status = Status.inserted # Run subscriptions to device state self._run_subs(obj=self, sub_type=self._default_sub) # Return complete status object return DeviceStatus(self, done=True, success=True)
def remove(self, wait=False, timeout=None, finished_cb=None): """ Remove the device from the beampath """ # Complete request self.status = Status.removed # Run subscriptions to device state self._run_subs(obj=self, sub_type=self._default_sub) # Return complete status object return DeviceStatus(self, done=True, success=True)
def move(self, position, wait=True, timeout=None, moved_cb=None): """ Move to a specified position, optionally waiting for motion to complete. Checks for the motor step, and ask the user for confirmation if movement step is greater than default one. """ if self.check_motor_step(position.e_eta, position.e_chi, position.e_phi): return super().move(position, wait=wait, timeout=timeout, moved_cb=moved_cb) else: logger.warning('Aborting moving for safety.') status = DeviceStatus(self) status.set_exception(ValueError('Unsafe Kappa move aborted!')) return status
def set(self, val): if self._set_st is not None: raise RuntimeError('trying to set while a set is in progress') cmd_map = { self.open_str: self.open_cmd, self.close_str: self.close_cmd } target_map = { self.open_str: self.open_val, self.close_str: self.close_val } cmd_sig = cmd_map[val] target_val = target_map[val] st = self._set_st = DeviceStatus(self) enums = self.status.enum_strs def shutter_cb(value, timestamp, **kwargs): value = enums[int(value)] if value == target_val: self._set_st._finished() self._set_st = None self.status.clear_sub(shutter_cb) cmd_enums = cmd_sig.enum_strs count = 0 def cmd_retry_cb(value, timestamp, **kwargs): nonlocal count value = cmd_enums[int(value)] # ts = datetime.datetime.fromtimestamp(timestamp).strftime(_time_fmtstr) # print('sh', ts, val, st) count += 1 if count > 5: cmd_sig.clear_sub(cmd_retry_cb) st._finished(success=False) if value == 'None': if not st.done: time.sleep(.5) cmd_sig.set(1) ts = datetime.datetime.fromtimestamp(timestamp).strftime( _time_fmtstr) print( '** ({}) Had to reactuate shutter while {}ing'.format( ts, val)) else: cmd_sig.clear_sub(cmd_retry_cb) cmd_sig.subscribe(cmd_retry_cb, run=False) cmd_sig.set(1) self.status.subscribe(shutter_cb) return st
def trigger_external(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self._status._finished() if self.mode_settings.scan_type.get() != 'fly': self._dispatch_channels(trigger_time=time.time()) # fly-scans take care of dispatching on their own return self._status
def new_acquire_status(self): """ Create, remember, and return a Status object that will be marked as `finished` when acquisition is done (see _acquire_changed). The intention is that this Status will be used by another object, for example a RunEngine. Returns ------- DeviceStatus """ self._acquire_status = DeviceStatus(self) return self._acquire_status
def trigger(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self._acquisition_signal.put(1, wait=False) trigger_time = ttime.time() for sn in self.read_attrs: if sn.startswith('channel') and '.' not in sn: ch = getattr(self, sn) self.dispatch(ch.name, trigger_time) self._abs_trigger_count += 1 return self._status
def test_status_with_name(hw): from ophyd.status import DeviceStatus st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) st._finished() st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) assert pbar.delay_draw == 0.2 time.sleep(0.25) st._finished()
def set(self, value, **kwargs): """interface to use bps.mv()""" if value != 1: return working_status = DeviceStatus(self) started = False def execute_scan_cb(value, timestamp, **kwargs): value = int(value) if started and value == 0: working_status._finished() self.execute_scan.subscribe(execute_scan_cb) self.execute_scan.set(1) started = True return working_status
def trigger(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self.settings.erase.put(1) self._acquisition_signal.put(1, wait=False) trigger_time = ttime.time() if self._mode is TESMode.step: for sn in self.read_attrs: if sn.startswith("channel") and "." not in sn: ch = getattr(self, sn) self.dispatch(ch.name, trigger_time) elif self._mode is TESMode.fly: self.dispatch("fluor", trigger_time) else: raise Exception(f"unexpected mode {self._mode}") self._abs_trigger_count += 1 return self._status
def complete(self): """ Complete the EventSequencer's current sequence. The result of this method varies on the mode that the EventSequencer is configured. If the EventSequencer is either set to 'Run Once' or 'Run N Times' this method allows the current sequence to complete and returns a status object that indicates a successful completion. However, this mode of operation does not make sense if the EventSequencer is in 'Run Forever' mode. In this case, the EventSequencer is stopped immediately and a completed status object is returned. Returns ------- status : DeviceStatus or SubscriptionStatus Status indicating completion of sequence. Notes ----- If you want to stop the sequence from running regardless of configuration use the :meth:`.stop` command. """ # Clear the monitor subscriptions super().complete() # If we are running forever we can stop whenever if self.play_mode.get() == 2: logger.debug("EventSequencer is set to run forever, " "stopping immediately") self.stop() return DeviceStatus(self, done=True, success=True) # Otherwise we should wait for the sequencer to end def done(*args, value=None, old_value=None, timestamp=0, **kwargs): return all((value == 0, old_value == 2, timestamp > self.play_control.timestamp)) # Create a SubscriptionStatus logger.debug("EventSequencer has a determined stopping point, " " waiting for sequence to complete") st = SubscriptionStatus(self.play_status, done, run=True) return st
def trigger_hide(self): if self._staged != Staged.yes: raise RuntimeError("not staged") import epics #t = '{:%H:%M:%S.%f}'.format(datetime.datetime.now()) #print('tr1 {} '.format(t)) self._status = DeviceStatus(self) self.cam.acquire.put(1, wait=False) trigger_time = ttime.time() #t = '{:%H:%M:%S.%f}'.format(datetime.datetime.now()) #print('tr2 {} '.format(t)) for sn in self.read_attrs: if sn.startswith('channel') and '.' not in sn: ch = getattr(self, sn) self.dispatch(ch.name, trigger_time) #t = '{:%H:%M:%S.%f}'.format(datetime.datetime.now()) #print('tr3 {} '.format(t)) self._abs_trigger_count += 1 return self._status
def set(self, value): #self.done_signal.value=1 st = DeviceStatus(self) # these arg sames matter #def am_done(old_value, value, **kwargs): def am_done(old_value,value, **kwargs): #if old_value == 1 and value == 0: #print("running",old_value,value,self.done_signal.value) #print("done_signal: ",smtr.done_signal.value) """ if self.done_signal.value==1: if self.last_value==0: st._finished() self.last_value=1 else: self.last_value=0 """ if old_value==0 and value==1: st._finished() self.done_signal.subscribe(am_done, run=False) self.user_setpoint.set(value) return st
def set(self, new_position, **kwargs): if np.abs(self.position - new_position) < .2: return DeviceStatus(self, done=True, success=True) return super().set(new_position, **kwargs)
def test_others(self): DeviceStatus(None)
def trigger(self): status = DeviceStatus(self) self._thread = threading.Thread(target=self.take_image, args=[status]) self._thread.start() return status
class HxnXspressTrigger(HxnModalBase, BlueskyInterface): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._status = None self._acquisition_signal = self.settings.acquire self._abs_trigger_count = 0 def unstage(self): ret = super().unstage() try: self._acquisition_signal.clear_sub(self._acquire_changed) except KeyError: pass return ret def _acquire_changed(self, value=None, old_value=None, **kwargs): "This is called when the 'acquire' signal changes." if self._status is None: return if (old_value == 1) and (value == 0): # Negative-going edge means an acquisition just finished. self._status._finished() def mode_internal(self): self._abs_trigger_count = 0 self.stage_sigs[self.external_trig] = False self.stage_sigs[self.settings.acquire_time] = self.count_time.get() self._acquisition_signal.subscribe(self._acquire_changed) def mode_external(self): ms = self.mode_settings # NOTE: these are used in Xspress3Filestore.stage self.stage_sigs[self.external_trig] = True self.stage_sigs[self.total_points] = ms.total_points.get() self.stage_sigs[self.spectra_per_point] = 1 self.stage_sigs[self.settings.acquire_time] = 0.001 # NOTE: these are taken care of in Xspress3Filestore # self.stage_sigs[self.settings.trigger_mode] = 'TTL Veto Only' # self.stage_sigs[self.settings.num_images] = total_capture def _dispatch_channels(self, trigger_time): self._abs_trigger_count += 1 channels = self._channels.values() for sn in self.read_attrs: ch = getattr(self, sn) if ch in channels: self.dispatch(ch.name, trigger_time) def trigger_internal(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self.settings.erase.put(1) self._acquisition_signal.put(1, wait=False) self._dispatch_channels(trigger_time=time.time()) return self._status def trigger_external(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self._status._finished() if self.mode_settings.scan_type.get() != 'fly': self._dispatch_channels(trigger_time=time.time()) # fly-scans take care of dispatching on their own return self._status def stage(self): staged = super().stage() mode = self.mode_settings.mode.get() if mode == 'external': # In external triggering mode, the devices is only triggered once # at stage self.settings.erase.put(1, wait=True) self._acquisition_signal.put(1, wait=False) return staged
class DCMFlyer(Device): """DCM flyer with HC10E counter board :PV fly_motor : monochromator theta1 :PV fly_motor_speed : monochromator speed [deg/sec] :PV fly_motor_stop : Stop monochromator theta :PV fly_motor_done_move : Done moving when value is '1', '0' : moving :PV scaler_mode : change mode. '0' : normal mode, '1' : fly(trigger) mode :PV encoder_steps : Flyer will accumulate counts during specified encoder steps :PV scaler_preset : set to '0' will result in measured values to reset :PV scaler_reset : reset array waveform :PV enc_waveform : encoder waveform :PV I0_waveform : I0 waveform :PV It_waveform : It waveform :PV If_waveform : If waveform :PV Ir_waveform : Ir waveform """ fly_motor = Cpt(EpicsSignal, pv_names['DCM']["mono_theta"]) fly_motor_speed = Cpt(EpicsSignal, pv_names['DCM']["mono_theta_speed"]) fly_motor_stop = Cpt(EpicsSignal, pv_names['DCM']["mono_theta_stop"]) fly_motor_done_move = Cpt(EpicsSignalRO, pv_names['DCM']["mono_theta_dmov"]) fly_motor_eres = Cpt(EpicsSignalRO, pv_names['DCM']["mono_enc_resolution"]) scaler_mode = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Mode"]) encoder_steps = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_TrigStep"]) scaler_preset = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Preset"]) scaler_reset = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Reset"]) enc_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_ENC_WF"]) I0_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_I0_WF"]) It_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_It_WF"]) If_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_If_WF"]) Ir_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_Ir_WF"]) def __init__(self, *args, target_energy=None, speed=None, encoder_steps=None, stream_names=None, **kwargs): super().__init__(*args, **kwargs) self.complete_status = None self._acquiring = False self._paused = False self.stream_names = stream_names self._collected_data = None self._start_energy = 8333 # Flyer motor target position if target_energy is None: self._target_energy = 9300 else: self._target_energy = target_energy # Flyer motor speed self._speed = speed # Encoder step size for accumulating counts self._encoder_step_counts = encoder_steps # Number of scan points to read self._num_of_counts = int(100) def energyToTheta(self, energy): _th = np.rad2deg(np.arcsin(_hc / (2. * _si_111 * energy))) return _th def pause(self): # Stop motor motion self.fly_motor_stop.put(1, wait=True) def resume(self): # Resume without erasing _th = self.energyToTheta(self._target_energy) self.fly_motor.put(_th, wait=True) def setStartEnergy(self, energy): self._start_energy = energy def setTargetEnergy(self, energy): self._target_energy = energy def setSpeed(self, speed): """Set Scan Speed""" self._speed = speed def setEncSteps(self, steps): self._encoder_step_counts = steps def setNumOfCounts(self, counts): self._num_of_counts = int(counts) def checkMotor(self): """check motor motion on a separated thread""" # Wait for completion while True: if self.fly_motor_done_move.get() == 0: # logger.error("fly_motor : {}".format(self.fly_motor_done_move.get())) ttime.sleep(0.1) else: # logger.error("fly_motor : {}".format(self.fly_motor_done_move.get())) break # logger.error("Done fly") # After the wait, we declare success self._acquiring = False self.complete_status._finished(success=True) def kickoff(self): '''Start collection Returns ------- DeviceStatus This will be set to done when acquisition has begun ''' # Put scaler in fly mode # self.scaler_mode.put(1, wait=True) # Set monochromator speed self.fly_motor_speed.put(self._speed, wait=True) # Set encoder step size for accumulating counts self.encoder_steps.put(self._encoder_step_counts, wait=True) # Reset scaler array waveform self.scaler_reset.put(1, wait=True) # Reset scaler counter self.scaler_preset.put(0, wait=True) # Wait For HC10E scaler reset ttime.sleep(.2) # Indicators self._start_time = ttime.time() self._acquiring = True self._paused = False # Put scaler in fly mode self.scaler_mode.put(1, wait=True) # Start motor motion to target_position asynchronously _th = self.energyToTheta(self._target_energy) self.fly_motor.put(_th, wait=False) ttime.sleep(0.2) thread = threading.Thread(target=self.checkMotor, daemon=True) thread.start() # make status object, Indicate flying has started self.kickoff_status = DeviceStatus(self) self.kickoff_status._finished(success=True) self.complete_status = DeviceStatus(self) return self.kickoff_status def complete(self): '''Wait for flying to be complete''' if self.complete_status is None: raise RuntimeError('No collection in progress') return self.complete_status def describe_collect(self): d = dict(source="HC10E", dtype="number", shape=(1, )) return {'primary': {"ENC": d, "I0": d, "It": d, "If": d, "Ir": d}} def collect(self): # Put scaler in normal mode self.scaler_mode.put(0, wait=False) # '''Retrieve all collected data''' if self._acquiring: raise RuntimeError('Acquisition still in progress. Call complete()' ' first.') self.complete_status = None # Retrive waveforms from epics PVs ENC = self.enc_waveform.get() if isinstance(ENC, type(None)): ENC = self.enc_waveform.get() I0 = self.I0_waveform.get() if isinstance(I0, type(None)): I0 = self.I0_waveform.get() It = self.It_waveform.get() if isinstance(It, type(None)): It = self.It_waveform.get() If = self.If_waveform.get() if isinstance(If, type(None)): If = self.If_waveform.get() Ir = self.Ir_waveform.get() if isinstance(Ir, type(None)): Ir = self.Ir_waveform.get() if self._num_of_counts > len(ENC): self._num_of_counts = len(ENC) # logger.error("ENC : {}".format(ENC)) # logger.error("num_of_counts : {}".format(self._num_of_counts)) # for idx in range(len(ENC)): for idx in range(int(self._num_of_counts)): t = ttime.time() enc = ENC[idx] _i0 = I0[idx] _it = It[idx] _if = If[idx] _ir = Ir[idx] d = dict(time=t, data=dict(ENC=enc, I0=_i0, It=_it, If=_if, Ir=_ir), timestamps=dict(ENC=t, I0=t, It=t, If=t, Ir=t)) yield d
def test_status_others(): DeviceStatus(None)
def trigger_external(self): self._status = DeviceStatus(self) self._status._finished() return self._status
class HxnTriggeringScaler(HxnModalBase, StruckScaler): def __init__(self, prefix, *, scan_type_triggers=None, **kwargs): super().__init__(prefix, **kwargs) if scan_type_triggers is None: scan_type_triggers = {'step': [], 'fly': [], } self.scan_type_triggers = dict(scan_type_triggers) # Scaler 1 should be in output mode 1 to properly trigger self.stage_sigs[self.output_mode] = 'Mode 1' # Ensure that the scaler isn't counting in mcs mode for any reason self.stage_sigs[self.stop_all] = 1 # Ensure that the scaler isn't counting self.stage_sigs[self.count] = 0 self.external_signals = [self.erase_start, self.start_all, self.input_mode, self.channel_advance, self.nuse_all, self.preset_real, self.dwell] def mode_internal(self): super().mode_internal() settings = self.mode_settings # ensure that no external signals are in the stage sigs list: for ext_sig in self.external_signals: if ext_sig in self.stage_sigs: del self.stage_sigs[ext_sig] scan_type = settings.scan_type.get() triggers = self.scan_type_triggers[scan_type] settings.triggers.put(list(triggers)) self.stop_all.put(1, wait=True) self.count.put(0, wait=True) self.stage_sigs[self.preset_time] = self.count_time.get() def mode_external(self): super().mode_external() if self.preset_time in self.stage_sigs: del self.stage_sigs[self.preset_time] self.stage_sigs[self.preset_real] = 0.0 self.stage_sigs[self.dwell] = 0.0 self.stage_sigs[self.channel_advance] = 'External' self.stage_sigs[self.input_mode] = 'Mode 2' self.stage_sigs[self.nuse_all] = self.mode_settings.total_points.get() self.stage_sigs[self.erase_start] = 1 self.stage_sigs.move_to_end(self.erase_start) def trigger(self): if self._staged != Staged.yes: raise RuntimeError("This detector is not ready to trigger." "Call the stage() method before triggering.") mode = self.mode_settings.mode.get() mode_trigger = getattr(self, 'trigger_{}'.format(mode)) return mode_trigger() def trigger_internal(self): return super().trigger() def trigger_external(self): self._status = DeviceStatus(self) self._status._finished() return self._status
class ContinuousAcquisitionTrigger(BlueskyInterface): """ This trigger mixin class records images when it is triggered. It expects the detector to *already* be acquiring, continously. """ def __init__(self, *args, plugin_name=None, image_name=None, **kwargs): if plugin_name is None: raise ValueError("plugin name is a required keyword argument") super().__init__(*args, **kwargs) self._plugin = getattr(self, plugin_name) if image_name is None: image_name = '_'.join([self.name, 'image']) self._plugin.stage_sigs[self._plugin.auto_save] = 'No' self.cam.stage_sigs[self.cam.image_mode] = 'Continuous' self._plugin.stage_sigs[self._plugin.file_write_mode] = 'Capture' self._image_name = image_name self._status = None self._num_captured_signal = self._plugin.num_captured self._num_captured_signal.subscribe(self._num_captured_changed) self._save_started = False def stage(self): if self.cam.acquire.get() != 1: raise RuntimeError("The ContinuousAcuqisitionTrigger expects " "the detector to already be acquiring.") return super().stage() # put logic to look up proper dark frame # die if none is found def trigger(self): "Trigger one acquisition." if not self._staged: raise RuntimeError("This detector is not ready to trigger." "Call the stage() method before triggering.") self._save_started = False self._status = DeviceStatus(self) self._desired_number_of_sets = self.number_of_sets.get() self._plugin.num_capture.put(self._desired_number_of_sets) self.dispatch(self._image_name, ttime.time()) # reset the proc buffer, this needs to be generalized self.proc.reset_filter.put(1) self._plugin.capture.put(1) # Now the TIFF plugin is capturing. return self._status def _num_captured_changed(self, value=None, old_value=None, **kwargs): "This is called when the 'acquire' signal changes." if self._status is None: return if value == self._desired_number_of_sets: # This is run on a thread, so exceptions might pass silently. # Print and reraise so they are at least noticed. try: self.tiff.write_file.put(1) except Exception as e: print(e) raise self._save_started = True if value == 0 and self._save_started: self._status._finished() self._status = None self._save_started = False