class LeafletAssembly(QQuickItem): """Base class for all leaflet assembly types""" # Q_CLASSINFO('DefaultProperty', 'leaflets') def __init__(self, parent=None): QQuickItem.__init__(self, parent) self._leaflets = [] self._hwsoc = HWSOC() def componentComplete(self): QQuickItem.componentComplete(self) self.enableHWLink() leafletsChanged = pyqtSignal([QQmlListProperty], arguments=['leaflets']) @pyqtProperty(QQmlListProperty, notify=leafletsChanged) def leaflets(self): return QQmlListProperty(Leaflet, self, self._leaflets) def publishToHW(self, index=None): poslist = [lf.extension for lf in self._leaflets] logger.debug('publishing all to HW - [{}]'.format(', '.join(str(x) for x in poslist))) self._hwsoc.set_all_positions(poslist) @pyqtSlot() def enableHWLink(self): self.onLeafletReleased.connect(self.publishToHW) @pyqtSlot() def disableHWLink(self): self.onLeafletReleased.disconnect(self.publishToHW)
class LeafletAssembly(QQuickItem): """Base class for all leaflet assembly types""" # Q_CLASSINFO('DefaultProperty', 'leaflets') def __init__(self, parent=None): QQuickItem.__init__(self, parent) self._leaflets = [] self._hwsoc = HWSOC() self.hw_linked = False def componentComplete(self): QQuickItem.componentComplete(self) self.enableHWLink() leafletsChanged = pyqtSignal([QQmlListProperty], arguments=['leaflets']) @pyqtProperty(QQmlListProperty, notify=leafletsChanged) def leaflets(self): return QQmlListProperty(Leaflet, self, self._leaflets) @pyqtSlot() @pyqtSlot(int) def publishToHW(self, index=None): poslist = [lf.extension for lf in self._leaflets] logger.debug('publishing all to HW - [{}]'.format(', '.join( str(x) for x in poslist))) self._hwsoc.set_all_positions(poslist) @pyqtSlot() def setCalibration(self): self._hwsoc.set_calibration() @pyqtSlot() def enableHWLink(self): if not self.hw_linked: self.onLeafletReleased.connect(self.publishToHW) self.hw_linked = True @pyqtSlot() def disableHWLink(self): if self.hw_linked: self.onLeafletReleased.disconnect(self.publishToHW) self.hw_linked = False # pre-defined leaflet configurations @pyqtSlot() def setClosed(self): """Move leaflets to 'closed' position""" for ii, leaf in enumerate(self._leaflets): leaf.extension = leaf.max_extension if ii < 4 else 0 self.publishToHW() @pyqtSlot() def setOpened(self): """Move leaflets to 'closed' position""" for ii, leaf in enumerate(self._leaflets): leaf.extension = 0 self.publishToHW()
class TreatmentManager(QObject): def __init__(self, sequencelistmodel, parent=None, *args): super().__init__(parent=parent, *args) self.seqlist = sequencelistmodel self._hwsoc = HWSOC() self.mark = 0 self._steps = 0 self._sequence_cache = None # thread locks self.lock_running = QMutex() self.lock_waiting = QMutex() self.lock_waitcond = QWaitCondition() self.lock_steps = QMutex() # state variables self.state_paused = False self.state_running = False self.state_waitinghwok = False self.startTreatment.connect(self._startTreatment) self.stopTreatment.connect(self._stopTreatment) self.restartTreatment.connect(self._restartTreatment) self.abortTreatment.connect(self._abortTreatment) self.setHWOK.connect(self._sethwok) # create QThread and move this object to it self.thread = QThread() self.moveToThread(self.thread) self.thread.start() onTreatmentStarted = pyqtSignal() onTreatmentStopped = pyqtSignal(int) onTreatmentAborted = pyqtSignal(int) onTreatmentCompleted = pyqtSignal(int) onTreatmentAdvance = pyqtSignal(int) onTreatmentSkip = pyqtSignal(int, float) # cross-thread control via signals startTreatment = pyqtSignal([int]) stopTreatment = pyqtSignal() restartTreatment = pyqtSignal() abortTreatment = pyqtSignal() setHWOK = pyqtSignal() onStepsChanged = pyqtSignal([int]) @pyqtProperty(int, notify=onStepsChanged) def steps(self): self.lock_steps.lock() v = self._steps self.lock_steps.unlock() return v @steps.setter def steps(self, v): self.lock_steps.lock() self._steps = v self.lock_steps.unlock() onWaitingChanged = pyqtSignal([bool]) @pyqtProperty(bool, notify=onWaitingChanged) def waitinghwok(self): self.lock_waiting.lock() v = self.state_waitinghwok self.lock_waiting.unlock() return v @waitinghwok.setter def waitinghwok(self, v): self.lock_waiting.lock() self.state_waitinghwok = v self.lock_waiting.unlock() onRunningChanged = pyqtSignal([bool]) @pyqtProperty(bool, notify=onRunningChanged) def running(self): self.lock_running.lock() v = self.state_running self.lock_running.unlock() return v @running.setter def running(self, v): self.lock_running.lock() self.state_running = v self.lock_running.unlock() def deliverAll(self): while self.mark < len(self._sequence_cache) and self.running: duration = self.deliverOne() # advance to next segment? if self.running: if self.mark < len(self.seqlist) - 1: self.mark += 1 self.steps += 1 # if duration >= 1000: # self.onTreatmentAdvance.emit(self.mark) # only updates UI self.onTreatmentAdvance.emit(self.mark) # only updates UI else: self._stopTreatment() self.state_paused = False self.onTreatmentCompleted.emit(self.mark) #update ui def deliverOne(self): """Run timer for a single beam""" seg = self._sequence_cache[self.mark] extension_list = seg._members['extension_list'].value duration = float(seg._members['timecode_ms'].value) if duration <= 0: self.waitinghwok = True self.onTreatmentSkip.emit(self.mark, duration) else: self.waitinghwok = True self._hwsoc.set_all_positions(extension_list) while self.waitinghwok: # spin event loop until hwok signal is recieved after delivery of prev. segment QCoreApplication.processEvents() t1 = time.perf_counter() while (time.perf_counter() - t1) < duration * 0.001: # catch signals every 250ms while delivering if (time.perf_counter() - t1) % 0.25: QCoreApplication.processEvents() if not self.state_running: # early exit from UI break return duration def _sethwok(self): self.waitinghwok = False @pyqtSlot(int) def _startTreatment(self, index): """Start the treatment at specified index""" self.mark = index self._sequence_cache = self.seqlist._items.copy() if not self.state_paused: self.steps = 1 self.running = True self.onTreatmentStarted.emit() logger.debug("Treatment started") self.deliverAll() def _stopTreatment(self): self.state_paused = True self.running = False self.onTreatmentStopped.emit(self.mark) logger.debug("Treatment stopped") def _restartTreatment(self): self.steps = 0 self.state_paused = False self._startTreatment(0) logger.debug("Treatment restarted") def _abortTreatment(self): self.running = False self.state_paused = False self.onTreatmentAborted.emit(self.mark) logger.debug("Treatment aborted")