Example #1
0
    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()
Example #2
0
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)
Example #3
0
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()
Example #4
0
 def __init__(self, *args, **kwargs):
     QQuickItem.__init__(self, **kwargs)
     self._hwsoc = HWSOC()
     self._extension = 0
     self._index = Leaflet.next_available
     self._limit_travel = True
     Leaflet.next_available += 1
Example #5
0
 def __init__(self, parent=None):
     QQuickItem.__init__(self, parent)
     self._leaflets = []
     self._hwsoc = HWSOC()
     self.hw_linked = False
Example #6
0
def start_gui():
    parser = argparse.ArgumentParser(
        description=
        'SmallSOCC v{!s} - Frontend for interfacing with SOC hardware'.format(
            VERSION_FULL),
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-L',
                        '--loglevel',
                        type=str,
                        choices=[*logging._nameToLevel.keys()],
                        default='WARNING',
                        help='set the loglevel')
    parser.add_argument('--logconf',
                        type=str,
                        default=os.path.join(LIB_DIR, 'logging.conf.json'),
                        help='path to log configuration')
    args = parser.parse_args()

    # initialize logger
    soclog.init_logging(level=logging._nameToLevel.get(args.loglevel, None),
                        config_path=args.logconf)

    listmodel = sequence.SequenceListModel()
    if args.loglevel is not 'NOTSET' and logging._nameToLevel[
            args.loglevel] <= logging.DEBUG:
        # load example sequence, for rapid debugging
        try:
            listmodel = sequence.SequenceListModel.fromJson(
                os.path.join(TEST_FILES, 'test_output.json'))
        except Exception as e:
            logger.warning('FAILED TO READ DEBUG JSON FILE : {!s}'.format(e))
            # SAMPLE ITEMS FOR DEBUG
            from sequence import SequenceItem, SequenceItemType
            sample_sequenceitems = [
                SequenceItem(rot_couch_deg=5,
                             rot_gantry_deg=0,
                             timecode_ms=0,
                             datecreatedstr="2016 Oct 31 12:00:00",
                             type='Manual'),
                SequenceItem(rot_couch_deg=12,
                             rot_gantry_deg=120,
                             timecode_ms=1500,
                             description="descriptive text2",
                             type=SequenceItemType.Auto),
                SequenceItem(rot_couch_deg=24,
                             rot_gantry_deg=25,
                             timecode_ms=3000,
                             description="descriptive text3"),
                SequenceItem(rot_couch_deg=0,
                             rot_gantry_deg=45,
                             timecode_ms=4500,
                             description="descriptive text4"),
            ]
            listmodel = sequence.SequenceListModel(
                elements=sample_sequenceitems)

    HWSOC(8, HID=None)  # init singleton instance for controlling hardware

    # integrate qml logging with python logging
    QtCore.qInstallMessageHandler(qt_message_handler)
    # prevent qml caching
    os.environ['QML_DISABLE_DISK_CACHE'] = '1'

    # set QML visual style
    app = QGuiApplication(sys.argv + ['-style', 'default'])
    #  app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
    # register pre-exit hook
    app.aboutToQuit.connect(preExit)  # perform cleanup

    ### the order here matters greatly - must init context properties before loading main.qml
    engine = QQmlApplicationEngine()
    rootContext = engine.rootContext()

    ## compute scaling ratios to make views dpi-independent
    if logger.getEffectiveLevel() <= logging.DEBUG:
        screens = app.screens()
        for sidx, screen in enumerate(screens):
            geometry = screen.geometry()
            dpi = screen.logicalDotsPerInch()
            logger.debug(
                'Screen #{} ({}) - size: (w:{}, h:{}); DPI: {}'.format(
                    sidx, screen.name(), geometry.width(), geometry.height(),
                    dpi))
    screen = app.primaryScreen()
    geometry = screen.geometry()
    dpi = screen.logicalDotsPerInch()

    refDpi = 96
    refHeight = 1440
    refWidth = 2560
    _h = min(geometry.width(), geometry.height())
    _w = max(geometry.width(), geometry.height())
    sratio = min(_h / refHeight, _w / refWidth)  # element size scaling
    fratio = min(_h * refDpi / (dpi * refHeight),
                 _w * refDpi / (dpi * refWidth))  # font pointSize scaling
    logger.debug('Setting scaling ratios - general: {}; font: {}'.format(
        sratio, fratio))

    ## Set accessible properties/objects in QML Root Context
    rootContext.setContextProperty(
        "mainwindow_title", 'SOC Controller - {!s}'.format(VERSION_FULL))
    # make seq. list model accessible to qml-listview
    rootContext.setContextProperty("SequenceListModel", listmodel)
    pathhandler_instance = pathhandler.PathHandler()
    rootContext.setContextProperty("PathHandler", pathhandler_instance)
    rootContext.setContextProperty("sratio", sratio)
    rootContext.setContextProperty("fratio", fratio)

    # load layout
    engine.load(QtCore.QUrl(os.path.join(dirname(__file__), 'main.qml')))

    ## connect signals to slots - unnecessary, example of grabbing qml objects from py-code
    # listview buttons
    #  rootObject = engine.rootObjects()[0]
    #  btns = rootObject.findChildren(QQuickItem, "list_buttons", QtCore.Qt.FindChildrenRecursively)[0]
    #  btns.findChild(QQuickItem, 'btn_moveup').clicked.connect(lambda: print('moveup clicked'))
    return app.exec_()
Example #7
0
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")