Пример #1
0
 def __init__(self,
              device,
              deviceName,
              channelName,
              globalDict,
              settings=None,
              outputUnit=''):
     #def __init__(self, device, deviceName, channelName, globalDict, settings=dict(), outputUnit=''):
     super(OutputChannel, self).__init__()
     self.device = device
     self.deviceName = deviceName
     self.channelName = channelName
     self.globalDict = globalDict
     self.expressionValue = ExpressionValue(self.name, self.globalDict,
                                            None)
     self.settings = settings if settings is not None else InstrumentSettings(
     )
     self.savedValue = None
     self.decimation = StaticDecimation()
     self.persistence = DBPersist()
     self.outputUnit = outputUnit
     self.setDefaults()
     self.expressionValue.string = self.settings.strValue
     self.expressionValue.value = self.settings.targetValue
     self.expressionValue.valueChanged.connect(self.onExpressionUpdate)
Пример #2
0
 def __init__(self, globalDict=dict()):
     self._globalDict = globalDict
     self._line = ExpressionValue(name="line",
                                  globalDict=globalDict,
                                  value=Q(0.0))
     self._lineValue = self._line.value
     self._lineGain = ExpressionValue(name="lineGain",
                                      globalDict=globalDict,
                                      value=Q(1.0))
     self._globalGain = ExpressionValue(name="globalGain",
                                        globalDict=globalDict,
                                        value=Q(1.0))
     self._line.valueChanged.connect(self.onLineExpressionChanged)
     self._lineGain.valueChanged.connect(self.onLineExpressionChanged)
     self._globalGain.valueChanged.connect(self.onLineExpressionChanged)
Пример #3
0
 def __init__(self,
              name='Count 0',
              states=None,
              minValue=0,
              maxValue=Q(0),
              globalDict=None):
     super().__init__()
     self.name = name
     self.states = sorted(list(states)) if states is not None else list()
     self.minValue = minValue if isinstance(
         minValue, ExpressionValue) else ExpressionValue(
             name=name, globalDict=globalDict, value=minValue)
     self.maxValue = maxValue if isinstance(
         maxValue, ExpressionValue) else ExpressionValue(
             name=name, globalDict=globalDict, value=maxValue)
     self.minValue.valueChanged.connect(self.onValueChanged)
     self.maxValue.valueChanged.connect(self.onValueChanged)
Пример #4
0
 def insertRow(self, position=0, index=QtCore.QModelIndex()):
     self.exprList.append(ExpressionValue(None, self.globalDict))
     self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())
     self.layoutChanged.emit()
     exprlen = len(self.exprList)
     self.exprList[exprlen - 1].valueChanged.connect(
         partial(self.valueChanged, exprlen - 1),
         QtCore.Qt.UniqueConnection)
     return range(exprlen - 1, exprlen)
Пример #5
0
 def __setstate__(self, state):
     state.setdefault('_globalDict', dict())
     state.pop('line', None)
     self.__dict__ = state
     if not isinstance(self._line, ExpressionValue):
         self._line = ExpressionValue(name="line",
                                      globalDict=self._globalDict,
                                      value=Q(self._line))
     if not isinstance(self._lineGain, ExpressionValue):
         self._lineGain = ExpressionValue(name='lineGain',
                                          globalDict=self._globalDict,
                                          value=Q(self._lineGain))
     if not isinstance(self._globalGain, ExpressionValue):
         self._globalGain = ExpressionValue(name='globalGain',
                                            globalDict=self._globalDict,
                                            value=Q(self._globalGain))
     self._lineValue = self._line.value
     self._line.valueChanged.connect(self.onLineExpressionChanged)
     self._lineGain.valueChanged.connect(self.onLineExpressionChanged)
     self._globalGain.valueChanged.connect(self.onLineExpressionChanged)
Пример #6
0
 def __init__(self, name="", path=None, gain=0, globalDict=None):
     self.name = name
     self.path = path
     self.gain = gain if isinstance(gain,
                                    ExpressionValue) else ExpressionValue(
                                        name, globalDict, gain)
     self._updateGainValue()
     self._solution = None
     self.solutionPath = None
     self.solutionHash = hash(None)
     self.gain.valueChanged.connect(self._updateGainValue)
Пример #7
0
 def __init__(self, globalDict):
     super().__init__()
     self.globalDict = globalDict
     self.exprList = [ExpressionValue(None, self.globalDict)]
     self.dataLookup = {
         (QtCore.Qt.DisplayRole):
         lambda index: self.exprList[index.row()].string if index.column(
         ) == 0 else self.displayGain(self.exprList[index.row()].value),
         (QtCore.Qt.EditRole):
         lambda index: self.exprList[index.row()].string if index.column()
         == 0 else self.displayGain(self.exprList[index.row()].value)
     }
     self.headerDataLookup = ['Expression', 'Value']
Пример #8
0
 def __init__(self, device, deviceName, channelName, globalDict, settings=None, outputUnit=''):
 #def __init__(self, device, deviceName, channelName, globalDict, settings=dict(), outputUnit=''):
     super(OutputChannel, self).__init__()
     self.device = device
     self.deviceName = deviceName
     self.channelName = channelName
     self.globalDict = globalDict
     self.expressionValue = ExpressionValue(self.name, self.globalDict, None)
     self.settings = settings if settings is not None else InstrumentSettings()
     self.savedValue = None
     self.decimation = StaticDecimation()
     self.persistence = DBPersist()
     self.outputUnit = outputUnit
     self.setDefaults()
     self.expressionValue.string = self.settings.strValue
     self.expressionValue.value = self.settings.targetValue
     self.expressionValue.valueChanged.connect(self.onExpressionUpdate)
Пример #9
0
 def __init__(self,
              adjType=None,
              name='',
              value=None,
              states=None,
              globalDict=None):
     self.adjType = adjType if adjType is not None else AdjustType.Shutter
     if isinstance(name, list):
         self._name = name
     else:
         self._name = [None, None, None, None]
         self.name = name
     self.states = sorted(list(states)) if states is not None else list()
     if isinstance(value, list):
         self._value = value
     else:
         self._value = [
             None, True,
             ExpressionValue(globalDict=globalDict), None
         ]  # Unused, Shutter value, Global value, Voltage_node value
         if value is not None:
             self.value = value
Пример #10
0
 def __init__(self, name=None, line=0, globalDict=None):
     ExpressionValue.__init__(self, name, globalDict)
     self.line = line
Пример #11
0
    def setupUi(self, parent):
        super(UserFunctionsEditor, self).setupUi(parent)
        self.configname = 'UserFunctionsEditor'
        self.fileTreeWidget.setHeaderLabels(['User Function Files'])
        self.populateTree()

        self.tableModel = EvalTableModel(self.globalDict)
        self.tableView.setModel(self.tableModel)
        self.tableView.setSortingEnabled(True)  # triggers sorting
        self.delegate = MagnitudeSpinBoxDelegate(self.globalDict)
        self.tableView.setItemDelegateForColumn(1, self.delegate)
        self.addEvalRow.clicked.connect(self.onAddRow)
        self.removeEvalRow.clicked.connect(self.onRemoveRow)

        #hot keys for copy/past and sorting
        self.filter = KeyListFilter(
            [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown])
        self.filter.keyPressed.connect(self.onReorder)
        self.tableView.installEventFilter(self.filter)
        QtWidgets.QShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Copy), self,
                            self.copy_to_clipboard)
        QtWidgets.QShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Paste), self,
                            self.paste_from_clipboard)

        #setup editor
        self.textEdit = PulseProgramSourceEdit()
        self.textEdit.setupUi(self.textEdit,
                              extraKeywords1=[],
                              extraKeywords2=[])
        self.textEdit.textEdit.currentLineMarkerNum = 9
        self.textEdit.textEdit.markerDefine(
            QsciScintilla.Background,
            self.textEdit.textEdit.currentLineMarkerNum
        )  #This is a marker that highlights the background
        self.textEdit.textEdit.setMarkerBackgroundColor(
            QtGui.QColor(0xd0, 0xff, 0xd0),
            self.textEdit.textEdit.currentLineMarkerNum)
        self.textEdit.setPlainText(self.script.code)
        self.splitterVertical.insertWidget(0, self.textEdit)

        #load file
        self.script.fullname = self.config.get(
            self.configname + '.script.fullname', '')
        self.tableModel.exprList = self.config.get(
            self.configname + '.evalstr',
            [ExpressionValue(None, self.globalDict)])
        if not isinstance(self.tableModel.exprList, list) or not isinstance(
                self.tableModel.exprList[0], ExpressionValue):
            self.tableModel.exprList = [ExpressionValue(None, self.globalDict)]
        self.tableModel.dataChanged.emit(QtCore.QModelIndex(),
                                         QtCore.QModelIndex())
        self.tableModel.layoutChanged.emit()
        self.tableModel.connectAllExprVals()
        if self.script.fullname != '' and os.path.exists(self.script.fullname):
            with open(self.script.fullname, "r") as f:
                self.script.code = f.read()
        else:
            self.script.code = ''

        #setup filename combo box
        self.recentFiles = self.config.get(self.configname + '.recentFiles',
                                           dict())
        self.recentFiles = {
            k: v
            for k, v in self.recentFiles.items() if os.path.exists(v)
        }  #removes files from dict if file paths no longer exist
        self.filenameComboBox.setInsertPolicy(1)
        self.filenameComboBox.setMaxCount(10)
        self.filenameComboBox.addItems([
            shortname for shortname, fullname in list(self.recentFiles.items())
            if os.path.exists(fullname)
        ])
        self.filenameComboBox.currentIndexChanged[str].connect(
            self.onFilenameChange)
        self.removeCurrent.clicked.connect(self.onRemoveCurrent)
        self.filenameComboBox.setValidator(QtGui.QRegExpValidator(
        ))  #verifies that files typed into combo box can be used
        self.updateValidator()

        #connect buttons
        self.actionOpen.triggered.connect(self.onLoad)
        self.actionSave.triggered.connect(self.onSave)
        self.actionNew.triggered.connect(self.onNew)

        self.fileTreeWidget.itemDoubleClicked.connect(self.onDoubleClick)
        self.loadFile(self.script.fullname)

        self.expandTree = QtWidgets.QAction("Expand All", self)
        self.collapseTree = QtWidgets.QAction("Collapse All", self)
        self.expandChild = QtWidgets.QAction("Expand Selected", self)
        self.collapseChild = QtWidgets.QAction("Collapse Selected", self)
        self.expandTree.triggered.connect(
            partial(self.onExpandOrCollapse, True, True))
        self.collapseTree.triggered.connect(
            partial(self.onExpandOrCollapse, True, False))
        self.expandChild.triggered.connect(
            partial(self.onExpandOrCollapse, False, True))
        self.collapseChild.triggered.connect(
            partial(self.onExpandOrCollapse, False, False))
        self.fileTreeWidget.addAction(self.expandTree)
        self.fileTreeWidget.addAction(self.collapseTree)
        self.fileTreeWidget.addAction(self.expandChild)
        self.fileTreeWidget.addAction(self.collapseChild)

        self.fileTreeWidget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

        self.setWindowTitle(self.configname)
        self.setWindowIcon(QtGui.QIcon(":/latex/icons/FuncIcon2.png"))
        self.statusLabel.setText("")
        self.tableModel.updateData()
Пример #12
0
 def testdeepcopy(self):
     expr = ExpressionValue(name='Count 3', value=Q(12, 'kHz'), globalDict=globalDict)
     c = copy.deepcopy(expr)
     self.assertEqual(expr, c)
     c.value = Q(123, 'MHz')
     c.string = '123 MHz'
Пример #13
0
    def setupUi(self, parent):
        super(UserFunctionsEditor, self).setupUi(parent)
        self.tableModel = EvalTableModel(self.globalDict)
        self.tableView.setModel(self.tableModel)
        self.tableView.setSortingEnabled(True)  # triggers sorting
        self.delegate = MagnitudeSpinBoxDelegate(self.globalDict)
        self.tableView.setItemDelegateForColumn(1, self.delegate)
        self.addEvalRow.clicked.connect(self.onAddRow)
        self.removeEvalRow.clicked.connect(self.onRemoveRow)

        #initialize default options
        self.optionsWindow = OptionsWindow(self.config,
                                           'UserFunctionsEditorOptions')
        self.optionsWindow.setupUi(self.optionsWindow)
        self.actionOptions.triggered.connect(self.onOpenOptions)
        self.optionsWindow.OptionsChangedSignal.connect(self.updateOptions)
        self.updateOptions()
        if self.optionsWindow.defaultExpand:
            onExpandOrCollapse(self.fileTreeWidget, True, True)

        #hot keys for copy/past and sorting
        self.filter = KeyListFilter(
            [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown])
        self.filter.keyPressed.connect(self.onReorder)
        self.tableView.installEventFilter(self.filter)
        QtWidgets.QShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Copy), self,
                            self.copy_to_clipboard)
        QtWidgets.QShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Paste), self,
                            self.paste_from_clipboard)

        #setup editor
        self.textEdit = PulseProgramSourceEdit()
        self.textEdit.setupUi(self.textEdit,
                              extraKeywords1=[],
                              extraKeywords2=[])
        self.textEdit.textEdit.currentLineMarkerNum = 9
        self.textEdit.textEdit.markerDefine(
            QsciScintilla.Background,
            self.textEdit.textEdit.currentLineMarkerNum
        )  #This is a marker that highlights the background
        self.textEdit.textEdit.setMarkerBackgroundColor(
            QtGui.QColor(0xd0, 0xff, 0xd0),
            self.textEdit.textEdit.currentLineMarkerNum)
        self.textEdit.setPlainText(self.script.code)
        self.splitterVertical.insertWidget(0, self.textEdit)

        #load recent files, also checks if data was saved correctly and if files still exist
        savedfiles = self.config.get(self.configname + '.recentFiles',
                                     OrderedList())
        self.initRecentFiles(savedfiles)
        self.initComboBox()

        self.tableModel.exprList = self.config.get(
            self.configname + '.evalstr',
            [ExpressionValue(None, self.globalDict)])
        if not isinstance(self.tableModel.exprList, list) or not isinstance(
                self.tableModel.exprList[0], ExpressionValue):
            self.tableModel.exprList = [ExpressionValue(None, self.globalDict)]
        self.tableModel.dataChanged.emit(QtCore.QModelIndex(),
                                         QtCore.QModelIndex())
        self.tableModel.layoutChanged.emit()
        self.tableModel.connectAllExprVals()

        #load last opened file
        self.script.fullname = self.config.get(
            self.configname + '.script.fullname', '')
        self.initLoad()

        #connect buttons
        self.actionOpen.triggered.connect(self.onLoad)
        self.actionSave.triggered.connect(self.onSave)
        self.actionNew.triggered.connect(self.onNew)

        self.setWindowTitle(self.configname)
        self.setWindowIcon(QtGui.QIcon(":/latex/icons/FuncIcon2.png"))
        self.statusLabel.setText("")
        self.tableModel.updateData()
Пример #14
0
 def testPickle(self):
     expr = ExpressionValue(name='Count 3', value=Q(12, 'kHz'))
     pickled = pickle.dumps(expr)
     unpickled = pickle.loads(pickled)
     self.assertEqual(expr, unpickled)
Пример #15
0
 def __init__(self, globalDict=None):
     self._globalDict = None
     self._voltage = ExpressionValue(None, self._globalDict)
     self.enabled = False
     self.name = ""
     self.resetAfterPP = False
Пример #16
0
 def __init__(self, name=None, line=0, globalDict=None):
     ExpressionValue.__init__(self, name, globalDict)
     self.line = line
Пример #17
0
class OutputChannel(QtCore.QObject):
    persistSpace = 'externalOutput'
    valueChanged = QtCore.pyqtSignal(object)
    targetChanged = QtCore.pyqtSignal(object)
    useTracker = UseTracker()

    def __init__(self,
                 device,
                 deviceName,
                 channelName,
                 globalDict,
                 settings=None,
                 outputUnit=''):
        #def __init__(self, device, deviceName, channelName, globalDict, settings=dict(), outputUnit=''):
        super(OutputChannel, self).__init__()
        self.device = device
        self.deviceName = deviceName
        self.channelName = channelName
        self.globalDict = globalDict
        self.expressionValue = ExpressionValue(self.name, self.globalDict,
                                               None)
        self.settings = settings if settings is not None else InstrumentSettings(
        )
        self.savedValue = None
        self.decimation = StaticDecimation()
        self.persistence = DBPersist()
        self.outputUnit = outputUnit
        self.setDefaults()
        self.expressionValue.string = self.settings.strValue
        self.expressionValue.value = self.settings.targetValue
        self.expressionValue.valueChanged.connect(self.onExpressionUpdate)

    def setDefaults(self):
        self.settings.__dict__.setdefault('value', Q(
            0, self.outputUnit))  # the current value
        self.settings.__dict__.setdefault('persistDelay',
                                          Q(60, 's'))  # delay for persistency
        self.settings.__dict__.setdefault(
            'strValue', None)  # requested value as string (formula)
        self.settings.__dict__.setdefault('targetValue', Q(
            0, self.outputUnit))  # requested value as string (formula)
        for d in self.device._channelParams.get(self.channelName, tuple()):
            self.settings.__dict__.setdefault(d['name'], d['value'])

    def onExpressionUpdate(self, name, value, string, origin):
        if origin == 'recalculate':
            self.setValue(value)
            self.targetChanged.emit(value)

    @property
    def name(self):
        return "{0}_{1}".format(
            self.deviceName,
            self.channelName) if self.channelName else self.deviceName

    @property
    def value(self):
        return self.settings.value

    def setValue(self, targetValue):
        """
        go stepsize towards the value. This function returns True if the value is reached. Otherwise
        it should return False. The user should call repeatedly until the intended value is reached
        and True is returned.
        """
        self.settings.targetValue = targetValue
        self.expressionValue.value = targetValue
        reportvalue = self.device.setValue(self.channelName, targetValue)
        self.settings.value = reportvalue
        self.valueChanged.emit(self.settings.value)
        return True

    def persist(self, channel, value):
        self.decimation.staticTime = self.settings.persistDelay
        decimationName = self.name if channel is None else self.name
        self.decimation.decimate(time.time(), value,
                                 partial(self.persistCallback, decimationName))

    def persistCallback(self, source, data):
        time, value, minval, maxval = data
        if is_Q(value):
            value, unit = value.m, "{:~}".format(value)
        else:
            value, unit = value, None
        self.persistence.persist(self.persistSpace, source, time, value,
                                 minval, maxval, unit)

    def saveValue(self, overwrite=True):
        """
        save current value
        """
        if self.savedValue is None or overwrite:
            self.savedValue = self.value
        return self.savedValue

    def restoreValue(self):
        """
        restore the value saved previously, this routine only goes stepsize towards this value
        if the stored value is reached returns True, otherwise False. Needs to be called repeatedly
        until it returns True in order to restore the saved value.
        """
        if self.expressionValue.hasDependency:
            self.expressionValue.recalculate()
            arrived = self.setValue(self.expressionValue.value)
        else:
            if self.savedValue is None:
                return True
            arrived = self.setValue(self.savedValue)
            if arrived:
                self.savedValue = None
        return arrived

    @property
    def externalValue(self):
        return self.device.getExternalValue(self.channelName)

    @property
    def dimension(self):
        return self.outputUnit

    @property
    def useExternalValue(self):
        return self.device.useExternalValue(self.channelName)

    @property
    def hasDependency(self):
        return self.expressionValue.hasDependency

    @property
    def targetValue(self):
        return self.settings.targetValue

    @targetValue.setter
    def targetValue(self, requestval):
        self.setValue(requestval)

    @property
    def string(self):
        return self.expressionValue.string

    @string.setter
    def string(self, s):
        self.settings.strValue = s
        self.expressionValue.string = s

    @property
    def strValue(self):
        return self.expressionValue.string

    @strValue.setter
    def strValue(self, s):
        self.settings.strValue = s
        self.expressionValue.string = s

    @property
    def parameter(self):
        # re-create the parameters each time to prevent a exception that says the signal is not connected
        self._parameter = Parameter.create(name=self.name,
                                           type='group',
                                           children=self.paramDef())
        self._parameter.sigTreeStateChanged.connect(self.update,
                                                    QtCore.Qt.UniqueConnection)
        return self._parameter

    def paramDef(self):
        """
        return the parameter definition used by pyqtgraph parametertree to show the gui
        """
        myparams = [{
            'name': 'persistDelay',
            'type': 'magnitude',
            'value': self.settings.persistDelay
        }]
        for d in self.device._channelParams.get(self.channelName, tuple()):
            p = dict(d)
            p['value'] = getattr(self.settings, d['name'])
            myparams.append(p)
        return myparams

    def update(self, param, changes):
        """
        update the parameter, called by the signal of pyqtgraph parametertree
        """
        for param, change, data in changes:
            if change == 'value':
                setattr(self.settings, param.name(), data)
Пример #18
0
class OutputChannel(QtCore.QObject):
    persistSpace = 'externalOutput'
    valueChanged = QtCore.pyqtSignal(object)
    targetChanged = QtCore.pyqtSignal(object)
    useTracker = UseTracker()

    def __init__(self, device, deviceName, channelName, globalDict, settings=None, outputUnit=''):
    #def __init__(self, device, deviceName, channelName, globalDict, settings=dict(), outputUnit=''):
        super(OutputChannel, self).__init__()
        self.device = device
        self.deviceName = deviceName
        self.channelName = channelName
        self.globalDict = globalDict
        self.expressionValue = ExpressionValue(self.name, self.globalDict, None)
        self.settings = settings if settings is not None else InstrumentSettings()
        self.savedValue = None
        self.decimation = StaticDecimation()
        self.persistence = DBPersist()
        self.outputUnit = outputUnit
        self.setDefaults()
        self.expressionValue.string = self.settings.strValue
        self.expressionValue.value = self.settings.targetValue
        self.expressionValue.valueChanged.connect(self.onExpressionUpdate)


    def setDefaults(self):
        self.settings.__dict__.setdefault('value', Q(0, self.outputUnit))  # the current value
        self.settings.__dict__.setdefault('persistDelay',Q(60, 's'))     # delay for persistency
        self.settings.__dict__.setdefault('strValue', None)                          # requested value as string (formula)
        self.settings.__dict__.setdefault('targetValue', Q(0, self.outputUnit) )  # requested value as string (formula)
        for d in self.device._channelParams.get(self.channelName, tuple()):
            self.settings.__dict__.setdefault(d['name'], d['value'])

    def onExpressionUpdate(self, name, value, string, origin):
        if origin == 'recalculate':
            self.setValue(value)
            self.targetChanged.emit(value)

    @property
    def name(self):
        return "{0}_{1}".format(self.deviceName, self.channelName) if self.channelName else self.deviceName
        
    @property
    def value(self):
        return self.settings.value
    
    def setValue(self, targetValue):
        """
        go stepsize towards the value. This function returns True if the value is reached. Otherwise
        it should return False. The user should call repeatedly until the intended value is reached
        and True is returned.
        """
        self.settings.targetValue = targetValue
        self.expressionValue.value = targetValue
        reportvalue = self.device.setValue(self.channelName, targetValue)
        self.settings.value = reportvalue
        self.valueChanged.emit(self.settings.value)
        return True
    
    def persist(self, channel, value):
        self.decimation.staticTime = self.settings.persistDelay
        decimationName = self.name if channel is None else self.name
        self.decimation.decimate(time.time(), value, partial(self.persistCallback, decimationName) )
        
    def persistCallback(self, source, data):
        time, value, minval, maxval = data
        if is_Q(value):
            value, unit = value.m, "{:~}".format(value)
        else:
            value, unit = value, None
        self.persistence.persist(self.persistSpace, source, time, value, minval, maxval, unit)
           
    def saveValue(self, overwrite=True):
        """
        save current value
        """
        if self.savedValue is None or overwrite:
            self.savedValue = self.value
        return self.savedValue

    def restoreValue(self):
        """
        restore the value saved previously, this routine only goes stepsize towards this value
        if the stored value is reached returns True, otherwise False. Needs to be called repeatedly
        until it returns True in order to restore the saved value.
        """
        if self.expressionValue.hasDependency:
            self.expressionValue.recalculate()
            arrived = self.setValue(self.expressionValue.value)
        else:
            if self.savedValue is None:
                return True
            arrived = self.setValue(self.savedValue)
            if arrived:
                self.savedValue = None
        return arrived
        
    @property
    def externalValue(self):
        return self.device.getExternalValue(self.channelName)
    
    @property
    def dimension(self):
        return self.outputUnit
    
    @property
    def useExternalValue(self):
        return self.device.useExternalValue(self.channelName)

    @property
    def hasDependency(self):
        return self.expressionValue.hasDependency
    
    @property
    def targetValue(self):
        return self.settings.targetValue

    @targetValue.setter
    def targetValue(self, requestval):
        self.setValue(requestval)

    @property
    def string(self):
        return self.expressionValue.string

    @string.setter
    def string(self, s):
        self.settings.strValue = s
        self.expressionValue.string = s
        
    @property
    def strValue(self):
        return self.expressionValue.string

    @strValue.setter
    def strValue(self, s):
        self.settings.strValue = s
        self.expressionValue.string = s

    @property
    def parameter(self):
        # re-create the parameters each time to prevent a exception that says the signal is not connected
        self._parameter = Parameter.create(name=self.name, type='group', children=self.paramDef())     
        self._parameter.sigTreeStateChanged.connect(self.update, QtCore.Qt.UniqueConnection)
        return self._parameter                
        
    def paramDef(self):
        """
        return the parameter definition used by pyqtgraph parametertree to show the gui
        """
        myparams = [{'name': 'persistDelay', 'type': 'magnitude', 'value': self.settings.persistDelay }]
        for d in self.device._channelParams.get(self.channelName, tuple()):
            p = dict(d)
            p['value'] = getattr(self.settings, d['name'])
            myparams.append(p)
        return myparams

    def update(self, param, changes):
        """
        update the parameter, called by the signal of pyqtgraph parametertree
        """
        for param, change, data in changes:
            if change=='value':
                setattr( self.settings, param.name(), data)