def capture_trigger(self, capture): if self.cur_trigger == len(self.triggers): raise Exception('Iteration already complete') next_iteration = None detected_trigger = self.check_trigger(self.cur_trigger, capture.timestamp) if detected_trigger < 0: log('Extra trigger at {}! ignoring.'.format(capture.timestamp)) return detected_trigger, next_iteration elif detected_trigger == self.cur_trigger: self.captures[detected_trigger] = capture else: log('Missed trigger #{} at {}!'.format(self.cur_trigger, capture.timestamp)) if detected_trigger == 0: # First trigger of next iteration next_iteration = GageIteration(self.triggers, last_trigger=capture.timestamp) next_iteration.captures[0] = capture next_iteration.cur_trigger = 1 # TODO check for bug if nTriggers=1 (missed trigger detection is kind of pointless here...) else: self.captures[detected_trigger] = capture self.cur_trigger = detected_trigger + 1 if self.cur_trigger == len(self.triggers): # the next trigger is the first of the next iteration. Return a new empty iteration object, # initialized with the last_trigger next_iteration = GageIteration(self.triggers, last_trigger=self.last_trigger) return detected_trigger, next_iteration
def check_timeout(self, tolerance=2): if not self.last_trigger or self.cur_trigger >= len(self.triggers): return None _, timeout = self.triggers[self.cur_trigger] if timeout == 0 or self.cur_trigger == 0: return None now = datetime.datetime.now() expected_timestamp = self.last_trigger + datetime.timedelta(seconds=timeout) while (now - expected_timestamp).total_seconds() > tolerance: # If expected trigger is passed log('Missed trigger #{} at {}!'.format(self.cur_trigger, now)) self.last_trigger = expected_timestamp self.cur_trigger = self.cur_trigger + 1 if self.cur_trigger >= len(self.triggers): # Missed last trigger, return a new empty iteration return GageIteration(self.triggers, last_trigger=self.last_trigger) _, timeout = self.triggers[self.cur_trigger] expected_timestamp = self.last_trigger + datetime.timedelta(seconds=timeout) return None
def process_capture(self, capture): # Resample data log('Processing started', 7) capture.resample() self._process(capture) log('Processing completed', 7)
def run_status(self, running): runname = self.run_widget.getRunname() if running: log('Run ''{}'' started'.format(runname)) self.start_button.setEnabled(False) else: log('Run ''{}'' stopped'.format(runname)) self.start_button.setEnabled(True)
def _thread_finished(self): log('Worker thread finished', 5) # Manually disconnect this signal, otherwise it somehow remains connected within Qt, and the GageCapture objects # queue up in the void somewhere on the defunct worker object/thread, causing a memory leak self.capture_acquired.disconnect(self._worker.process_capture) self._worker.deleteLater() self._worker = None self._thread.deleteLater() self._thread = None
def _stop_acquisition(self): self._acquiring = False self.start_button.setText('Stopping...') self.gage.Abort() # Abort acquisition if self._thread is not None: # TODO make sure this doesn't ignore data in the Event queue!! self._thread.quit() self.state = GageState.IDLE log('Acquisition stopped')
def _save_iteration(self, iteration): if not self.run_widget.isRunning(): return filename, target_path = self.run_widget.getTargetH5() if not path.exists(target_path): os.makedirs(target_path) filepath = path.join(target_path, filename) iteration.save_h5(filepath) log('Output to {}'.format(filename), 1) self.run_widget.increment()
def _plot_capture(self, plot_data, line): # This slot is triggered by the plot_capture signal in the Worker, and plots each capture in the UI thread # after processing is finished log('Start plotting', 6) for cid, widget in self.channel_widgets.items(): if cid not in plot_data: continue filt_time, filt_data = plot_data[cid] widget.plot(filt_time, filt_data, line=line) log('Finished plotting', 6)
def on_acquired(self): timestamp = datetime.datetime.now() if not self._acquiring: return log('Acquired', 3) capture = GageCapture(channel_config, timestamp) capture.download(self.gage) log('Downloaded', 4) self.gage.Start() # Re-arm acquisition self.capture_acquired.emit(capture)
def _process(self, capture): # Save Data if self.run_widget.isRunning(): for cid, config in capture.channel_config.items(): filename, target_path = self.run_widget.getTarget(channel=cid) if not path.exists(target_path): os.makedirs(target_path) filepath = path.join(target_path, filename) capture.save_channel_sig(filepath, cid) log('Output to {}'.format(filename), 1) self.run_widget.increment() plot_data = capture.prepare_plot() self.plot_capture.emit(plot_data, 0)
def toggleStart(self): if self.start_button.isChecked(): self.start_button.setText('Starting...') if self.mode == GageMode.TRAD: self.sample_length = self.length_input.value() for config in channel_config: config.segments = [] self._worker = GageTradWorker(self.run_widget) elif self.mode == GageMode.SEG: self.sample_length = 0 for config in channel_config: cw = self.channel_widgets[config.id] config.segments = cw.get_segments() seg_ends = [seg[2] for seg in config.segments] if len(seg_ends) > 0: self.sample_length = max(self.sample_length, max(seg_ends)) self._worker = GageSegWorker(self.run_widget, self.triggers) self.sample_depth = int(sample_clk * self.sample_length / 1e3) for cid, cw in self.channel_widgets.items(): cw._pw.setXRange(0, self.sample_length * 1e-3) log('Starting acquisition for {:.1f} ms ({:d} samples)'.format(self.sample_length, self.sample_depth)) self._gage_configure() self._thread = QtCore.QThread() self._worker.moveToThread(self._thread) self.capture_acquired.connect(self._worker.process_capture) self._worker.plot_capture.connect(self._plot_capture) self._thread.started.connect(self._worker.started) self._thread.finished.connect(self._thread_finished) self._thread.start() self._acquiring = True self.gage.Start() # Arm acquisition self.state = GageState.ACQUIRE else: self._stop_acquisition()
def __del__(self): log('GageWorker Deleted', 7)
def __del__(self): log('GageCapture Deleted', 7)
def __del__(self): log('GageIteration Deleted', 7)