コード例 #1
0
class BasicWaveformWidget(BasicValueWidget):
    """
    Generic PyDM Widget for testing plugins. Contains a basic waveform Channel.
    """
    __pyqtSignals__ = (
        "send_waveform_signal(np.ndarray)",
        "waveform_updated_signal()",
    )

    send_waveform_signal = pyqtSignal(np.ndarray)
    waveform_updated_signal = pyqtSignal()

    def __init__(self, channel=None, parent=None):
        """
        Initialize channel and parent. Start value at "None".

        :param channel: string channel address to use
        :type channel:  str
        :param parent: parent QWidget
        :type parent:  QWidget or None
        """
        super(BasicWaveformWidget, self).__init__(channel=channel,
                                                  parent=parent)

    @pyqtSlot(np.ndarray)
    def recv_waveform(self, waveform):
        """
        Recieve waveform from plugin signal. Store in self.value.

        :param waveform: waveform
        :type waveform:  np.ndarray
        """
        self.value = waveform
        self.waveform_updated_signal.emit()

    @pyqtSlot(np.ndarray)
    def send_waveform(self, waveform):
        """
        Send desired waveform to plugin slot.

        :param value: waveform to send
        :type value: np.ndarray
        """
        self.send_waveform_signal.emit(waveform)

    def channels(self):
        """
        Return list of channels, in this case just a basic waveform channel.

        :rtyp: list of :class:Channel
        """
        return [
            Channel(address=self.channel,
                    waveform_slot=self.recv_waveform,
                    waveform_signal=self.send_waveform_signal)
        ]
コード例 #2
0
class LogWriter(QObject):
    """
    QObject to do the writing
    """
    terminator = '\n'
    write_trigger = pyqtSignal(str)

    def __init__(self, text_widget):
        super().__init__(parent=text_widget)
        self.text_widget = text_widget
        self.write_trigger.connect(self.write_log)

    def do_write(self, all_msg):
        self.write_trigger.emit(all_msg)

    @pyqtSlot(str)
    def write_log(self, all_msg):
        if self.text_widget is not None:
            split_msg = all_msg.split(self.terminator)
            for msg in reversed(split_msg):
                cursor = self.text_widget.cursorForPosition(QPoint(0, 0))
                cursor.insertText(msg + self.terminator)

    def log_close(self):
        self.text_widget = None
        self.write_trigger.disconnect(self.write_log)
コード例 #3
0
ファイル: ensemble_plugin.py プロジェクト: klauer/aerotech
class WriteOnlyParameter(QThread):
    new_data_signal = pyqtSignal(object)
    new_severity_signal = pyqtSignal(int)
    writable = True

    def __init__(self, connection, client, parameter, *, poll_rate=None):
        super().__init__()
        self.connection = connection
        self.client = client
        self.parameter = parameter
        self.to_write = []

    def run(self):
        try:
            loop = self.client.loop
            while self.to_write:
                comm = self.client.comm
                if comm is None:
                    logger.warning('Not writing %s; disconnected',
                                   self.parameter)
                    self.to_write.clear()
                    break

                with self.client.lock:
                    value = self.to_write.pop(0)
                    cmd = self.parameter.format(value=value)
                    coro = comm.write_read(cmd)
                    try:
                        result = loop.run_until_complete(coro)
                    except Exception as ex:
                        logger.exception('Write failed: %r', cmd)
                        self.new_severity_signal.emit(Severity.MAJOR)
                        self.to_write.clear()
                        break
                    else:
                        logger.info('Write result: %r => %s', cmd, result)
                        self.new_severity_signal.emit(Severity.NO_ALARM)
        except Exception:
            logger.exception('Write failed!')

    def write(self, value):
        logger.debug('%s write: %s', self.parameter, value)
        self.to_write.append(value)
        self.start()
コード例 #4
0
class PostInit(QObject):
    """
    Catch the visibility event for one last sequence of functions after pydm is
    fully initialized, which is later than we can do things inside __init__.
    """
    post_init = pyqtSignal()
    do_it = True

    def eventFilter(self, obj, event):
        if self.do_it and event.type() == QEvent.WindowActivate:
            self.do_it = False
            self.post_init.emit()
            return True
        return False
コード例 #5
0
ファイル: logdisplay.py プロジェクト: klauer/pydm
class GuiHandler(QObject, logging.Handler):
    """
    Handler for PyDM Applications

    A composite of a QObject and a logging handler. This can be added to a
    ``logging.Logger`` object just like any standard ``logging.Handler`` and
    will emit logging messages as pyqtSignals

    .. code:: python

        # Create a log and GuiHandler
        logger = logging.getLogger()
        ui_handler = GuiHandler(level=logging.INFO)
        # Attach our handler to the log
        logger.addHandler(ui_handler)
        # Publish log message via pyqtSignal
        ui_handler.message.connect(mySlot)

    Parameters
    ----------
    level: int
        Level of Handler

    parent: QObject, optional
    """
    message = pyqtSignal(str)

    def __init__(self, level=logging.NOTSET, parent=None):
        logging.Handler.__init__(self, level=level)
        QObject.__init__(self)
        # Set the parent widget
        self.setParent(parent)

    def emit(self, record):
        """Emit formatted log messages when received but only if level is set."""
        # Avoid garbage to be presented when master log is running with DEBUG.
        if self.level == logging.NOTSET:
            return
        self.message.emit(self.format(record))
コード例 #6
0
class QueueSlots(QObject):
    """
    Dummy object that contains a slot that puts signal results to a queue.
    Exists for the implementation of PyDMTest.signal_wait.
    """
    __pyqtSignals__ = ("got_value()",)
    got_value = pyqtSignal()

    def __init__(self, parent=None):
        """
        Set up QObject and create internal queue.
        """
        super(QueueSlots, self).__init__(parent=parent)
        self.queue = Queue.Queue()

    def get(self, timeout=None):
        """
        Retrieve queue value or None. Waits for timeout seconds.

        :param timeout: get timeout in seconds
        :type timeout:  float or int
        :rtyp: object or None
        """
        try:
            return self.queue.get(timeout)
        except Queue.Empty:
            return

    @pyqtSlot()
    @pyqtSlot(object)
    def put_to_queue(self, value=None):
        """
        Put incoming value into the queue and signal that we recieved data.

        :param value: Incoming value
        :type value:  object or None
        """
        self.queue.put(value)
        self.got_value.emit()
コード例 #7
0
class ValueWidget(BasicValueWidget):
    """
    Generic PyDM Widget for testing plugins. Contains a more thorough value
    Channel.
    """
    __pyqtSignals__ = (
        "send_value_signal([int], [float], [str])",
        "value_updated_signal()",
        "conn_updated_signal()",
        "sevr_updated_signal()",
        "rwacc_updated_signal()",
        "enums_updated_signal()",
        "units_updated_signal()",
        "prec_updated_signal()",
    )

    conn_updated_signal = pyqtSignal()
    sevr_updated_signal = pyqtSignal()
    rwacc_updated_signal = pyqtSignal()
    enums_updated_signal = pyqtSignal()
    units_updated_signal = pyqtSignal()
    prec_updated_signal = pyqtSignal()

    def __init__(self, channel=None, parent=None):
        """
        Initialize channel and parent. Start all fields as None.

        :param channel: string channel address to use
        :type channel:  str
        :param parent: parent QWidget
        :type parent:  QWidget or None
        """
        super(ValueWidget, self).__init__(channel=channel, parent=parent)
        self.conn = None
        self.sevr = None
        self.rwacc = None
        self.enums = None
        self.units = None
        self.prec = None

    @pyqtSlot(bool)
    def recv_conn(self, conn):
        """
        Get connection state signal

        :param conn: connection state
        :type conn:  bool
        """
        self.conn = conn
        self.conn_updated_signal.emit()

    @pyqtSlot(int)
    def recv_sevr(self, sevr):
        """
        Get alarm state signal

        :param sevr: alarm state
        :type sevr:  int
        """
        self.sevr = sevr
        self.sevr_updated_signal.emit()

    @pyqtSlot(bool)
    def recv_rwacc(self, rwacc):
        """
        Get write access signal

        :param rwacc: write access state
        :type rwacc:  bool
        """
        self.rwacc = rwacc
        self.rwacc_updated_signal.emit()

    @pyqtSlot(tuple)
    def recv_enums(self, enums):
        """
        Get enum strings signal

        :param enums: enum strings
        :type enums:  tuple of str
        """
        self.enums = enums
        self.enums_updated_signal.emit()

    @pyqtSlot(str)
    def recv_units(self, units):
        """
        Get units signal

        :param units: engineering units
        :type units:  str
        """
        self.units = units
        self.units_updated_signal.emit()

    @pyqtSlot(int)
    def recv_prec(self, prec):
        """
        Get precision signal

        :param prec: data precision
        :type prec:  int
        """
        self.prec = prec
        self.prec_updated_signal.emit()

    def channels(self):
        """
        Return list of channels, in this case one channel with every field
        filled except for the waveform fields.

        :rtyp: list of :class:Channel
        """
        return [
            Channel(address=self.channel,
                    value_slot=self.recv_value,
                    value_signal=self.send_value_signal,
                    connection_slot=self.recv_conn,
                    severity_slot=self.recv_sevr,
                    write_access_slot=self.recv_rwacc,
                    enum_strings_slot=self.recv_enums,
                    unit_slot=self.recv_units,
                    prec_slot=self.recv_prec)
        ]
コード例 #8
0
class WaveformWidget(ValueWidget):
    """
    Generic PyDM Widget for testing plugins. Contains a more thorough waveform
    Channel.

    Lots of copy/paste because pyqt multiple inheritance is broken.
    """
    __pyqtSignals__ = (
        "send_waveform_signal(np.ndarray)",
        "waveform_updated_signal()",
        "conn_updated_signal()",
        "sevr_updated_signal()",
        "rwacc_updated_signal()",
        "enums_updated_signal()",
        "units_updated_signal()",
        "prec_updated_signal()",
    )

    send_waveform_signal = pyqtSignal(np.ndarray)
    waveform_updated_signal = pyqtSignal()

    def __init__(self, channel=None, parent=None):
        super(WaveformWidget, self).__init__(channel=channel, parent=parent)

    @pyqtSlot(np.ndarray)
    def recv_waveform(self, waveform):
        """
        Recieve waveform from plugin signal. Store in self.value.

        :param waveform: waveform
        :type waveform:  np.ndarray
        """
        self.value = waveform
        self.waveform_updated_signal.emit()

    @pyqtSlot(np.ndarray)
    def send_waveform(self, waveform):
        """
        Send desired waveform to plugin slot.

        :param value: waveform to send
        :type value: np.ndarray
        """
        self.send_waveform_signal.emit(waveform)

    def channels(self):
        """
        Return list of channels, in this case one channel with every field
        filled except for the value fields.

        :rtyp: list of :class:Channel
        """
        return [
            Channel(address=self.channel,
                    waveform_slot=self.recv_waveform,
                    waveform_signal=self.send_waveform_signal,
                    connection_slot=self.recv_conn,
                    severity_slot=self.recv_sevr,
                    write_access_slot=self.recv_rwacc,
                    enum_strings_slot=self.recv_enums,
                    unit_slot=self.recv_units,
                    prec_slot=self.recv_prec)
        ]
コード例 #9
0
class BasicValueWidget(QWidget):
    """
    Generic PyDM Widget for testing plugins. Contains a basic value Channel.
    """
    __pyqtSignals__ = (
        "send_value_signal([int], [float], [str])",
        "value_updated_signal()",
    )

    send_value_signal = pyqtSignal([int], [float], [str])
    value_updated_signal = pyqtSignal()

    def __init__(self, channel=None, parent=None):
        """
        Initialize channel and parent. Start value at "None".

        :param channel: string channel address to use
        :type channel:  str
        :param parent: parent QWidget
        :type parent:  QWidget or None
        """
        super(BasicValueWidget, self).__init__(parent=parent)
        self.channel = channel
        self.value = None

    @pyqtSlot(int)
    @pyqtSlot(float)
    @pyqtSlot(str)
    def recv_value(self, value):
        """
        Recieve value from plugin signal. Store in self.value.

        :param value: value to store
        :type value:  int, float, or str
        """
        self.value = value
        self.value_updated_signal.emit()

    @pyqtSlot(int)
    @pyqtSlot(float)
    @pyqtSlot(str)
    def send_value(self, value):
        """
        Send desired value to plugin slot.

        :param value: value to send
        :type value: int, float, or str
        """
        self.send_value_signal[type(value)].emit(value)

    def channels(self):
        """
        Return list of channels, in this case just a basic value channel.

        :rtyp: list of :class:Channel
        """
        return [
            Channel(address=self.channel,
                    value_slot=self.recv_value,
                    value_signal=self.send_value_signal)
        ]
コード例 #10
0
class CamViewer(Display):
    #Emitted when the user changes the value.
    roi_x_signal = pyqtSignal(str)
    roi_y_signal = pyqtSignal(str)
    roi_w_signal = pyqtSignal(str)
    roi_h_signal = pyqtSignal(str)

    def __init__(self, display_manager_window):
        super(CamViewer, self).__init__(display_manager_window)

        #Set up the list of cameras, and all the PVs
        vcc_dict = {
            "image": "ca://CAMR:IN20:186:IMAGE",
            "max_width": "ca://CAMR:IN20:186:N_OF_COL",
            "max_height": "ca://CAMR:IN20:186:N_OF_ROW",
            "roi_x": None,
            "roi_y": None,
            "roi_width": None,
            "roi_height": None
        }
        c_iris_dict = {
            "image": "ca://CAMR:LR20:119:Image:ArrayData",
            "max_width": "ca://CAMR:LR20:119:MaxSizeX_RBV",
            "max_height": "ca://CAMR:LR20:119:MaxSizeY_RBV",
            "roi_x": "ca://CAMR:LR20:119:MinX",
            "roi_y": "ca://CAMR:LR20:119:MinY",
            "roi_width": "ca://CAMR:LR20:119:SizeX",
            "roi_height": "ca://CAMR:LR20:119:SizeY"
        }
        test_dict = {
            "image": "ca://MTEST:Image",
            "max_width": "ca://MTEST:ImageWidth",
            "max_height": "ca://MTEST:ImageWidth",
            "roi_x": None,
            "roi_y": None,
            "roi_width": None,
            "roi_height": None
        }
        self.cameras = {
            "VCC": vcc_dict,
            "C-Iris": c_iris_dict,
            "Test": test_dict
        }
        self._channels = []

        #Populate the camera combo box
        self.ui.cameraComboBox.clear()
        for camera in self.cameras:
            self.ui.cameraComboBox.addItem(camera)

        #Clear out any image data, reset width, get PVs ready for connection
        self.initializeCamera(self.ui.cameraComboBox.currentText())

        #When the camera combo box changes, disconnect from PVs, re-initialize, then reconnect.
        self.ui.cameraComboBox.activated[str].connect(self.cameraChanged)

        #Set up the color map combo box.
        self.ui.colorMapComboBox.clear()
        for map_name in self.ui.imageView.color_maps:
            self.ui.colorMapComboBox.addItem(map_name)
        self.ui.imageView.setColorMapToPreset(
            self.ui.colorMapComboBox.currentText())
        self.ui.colorMapComboBox.activated[str].connect(self.colorMapChanged)

        #Set up the color map limit sliders and line edits.
        #self._color_map_limit_sliders_need_config = True
        self.ui.colorMapMinSlider.valueChanged.connect(self.setColorMapMin)
        self.ui.colorMapMaxSlider.valueChanged.connect(self.setColorMapMax)
        self.ui.colorMapMinLineEdit.returnPressed.connect(
            self.colorMapMinLineEditChanged)
        self.ui.colorMapMaxLineEdit.returnPressed.connect(
            self.colorMapMaxLineEditChanged)

        #Set up the stuff for single-shot and average modes.
        self.ui.singleShotRadioButton.setChecked(True)
        self._average_mode_enabled = False
        self.ui.singleShotRadioButton.clicked.connect(
            self.enableSingleShotMode)
        self.ui.averageRadioButton.clicked.connect(self.enableAverageMode)
        self.ui.numShotsLineEdit.returnPressed.connect(self.numAverageChanged)

        #Add a plot for vertical lineouts
        self.yLineoutPlot = PlotWidget()
        self.yLineoutPlot.setMaximumWidth(80)
        self.yLineoutPlot.setSizePolicy(QSizePolicy.Minimum,
                                        QSizePolicy.Expanding)
        self.yLineoutPlot.getPlotItem().invertY()
        self.yLineoutPlot.hideAxis('bottom')
        #self.yLineoutPlot.setYLink(self.ui.imageView.getView())
        self.ui.imageGridLayout.addWidget(self.yLineoutPlot, 0, 0)
        self.yLineoutPlot.hide()
        #We do some mangling of the .ui file here and move the imageView over a cell, kind of ugly.
        self.ui.imageGridLayout.removeWidget(self.ui.imageView)
        self.ui.imageGridLayout.addWidget(self.ui.imageView, 0, 1)

        #Add a plot for the horizontal lineouts
        self.xLineoutPlot = PlotWidget()
        self.xLineoutPlot.setMaximumHeight(80)
        self.xLineoutPlot.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Minimum)
        self.xLineoutPlot.hideAxis('left')
        #self.xLineoutPlot.setXLink(self.ui.imageView.getView())
        self.ui.imageGridLayout.addWidget(self.xLineoutPlot, 1, 1)
        self.xLineoutPlot.hide()

        #Update the lineout plot ranges when the image gets panned or zoomed
        self.ui.imageView.getView().sigRangeChanged.connect(
            self.updateLineoutRange)

        #Instantiate markers.
        self.marker_dict = {1: {}, 2: {}, 3: {}, 4: {}}
        marker_size = QPointF(20., 20.)
        self.marker_dict[1]['marker'] = ImageMarker((0, 0),
                                                    size=marker_size,
                                                    pen=mkPen((100, 100, 255),
                                                              width=3))
        self.marker_dict[1]['button'] = self.ui.marker1Button
        self.marker_dict[1]['xlineedit'] = self.ui.marker1XPosLineEdit
        self.marker_dict[1]['ylineedit'] = self.ui.marker1YPosLineEdit

        self.marker_dict[2]['marker'] = ImageMarker((0, 0),
                                                    size=marker_size,
                                                    pen=mkPen((255, 100, 100),
                                                              width=3))
        self.marker_dict[2]['button'] = self.ui.marker2Button
        self.marker_dict[2]['xlineedit'] = self.ui.marker2XPosLineEdit
        self.marker_dict[2]['ylineedit'] = self.ui.marker2YPosLineEdit

        self.marker_dict[3]['marker'] = ImageMarker((0, 0),
                                                    size=marker_size,
                                                    pen=mkPen((60, 255, 60),
                                                              width=3))
        self.marker_dict[3]['button'] = self.ui.marker3Button
        self.marker_dict[3]['xlineedit'] = self.ui.marker3XPosLineEdit
        self.marker_dict[3]['ylineedit'] = self.ui.marker3YPosLineEdit

        self.marker_dict[4]['marker'] = ImageMarker((0, 0),
                                                    size=marker_size,
                                                    pen=mkPen((255, 60, 255),
                                                              width=3))
        self.marker_dict[4]['button'] = self.ui.marker4Button
        self.marker_dict[4]['xlineedit'] = self.ui.marker4XPosLineEdit
        self.marker_dict[4]['ylineedit'] = self.ui.marker4YPosLineEdit
        #Disable auto-ranging the image (it feels strange when the zoom changes as you move markers around.)
        self.ui.imageView.getView().disableAutoRange()
        for d in self.marker_dict:
            marker = self.marker_dict[d]['marker']
            marker.setZValue(20)
            marker.hide()
            marker.sigRegionChanged.connect(self.markerMoved)
            self.ui.imageView.getView().addItem(marker)
            self.marker_dict[d]['button'].toggled.connect(self.enableMarker)
            curvepen = QPen(marker.pen)
            curvepen.setWidth(1)
            self.marker_dict[d]['xcurve'] = self.xLineoutPlot.plot(
                pen=curvepen)
            self.marker_dict[d]['ycurve'] = self.yLineoutPlot.plot(
                pen=curvepen)
            self.marker_dict[d]['xlineedit'].returnPressed.connect(
                self.markerPositionLineEditChanged)
            self.marker_dict[d]['ylineedit'].returnPressed.connect(
                self.markerPositionLineEditChanged)

        #Set up zoom buttons
        self.ui.zoomInButton.clicked.connect(self.zoomIn)
        self.ui.zoomOutButton.clicked.connect(self.zoomOut)
        self.ui.zoomToActualSizeButton.clicked.connect(self.zoomToActualSize)

        #Set up ROI buttons
        self.ui.setROIButton.clicked.connect(self.setROI)
        self.ui.resetROIButton.clicked.connect(self.resetROI)

    @pyqtSlot()
    def zoomIn(self):
        self.ui.imageView.getView().scaleBy((0.5, 0.5))

    @pyqtSlot()
    def zoomOut(self):
        self.ui.imageView.getView().scaleBy((2.0, 2.0))

    @pyqtSlot()
    def zoomToActualSize(self):
        if len(self.image_data) == 0:
            return
        self.ui.imageView.getView().setRange(xRange=(0,
                                                     self.image_data.shape[0]),
                                             yRange=(0,
                                                     self.image_data.shape[1]),
                                             padding=0.0)

    def disable_all_markers(self):
        for d in self.marker_dict:
            self.marker_dict[d]['button'].setChecked(False)
            self.marker_dict[d]['marker'].setPos((0, 0))

    @pyqtSlot(bool)
    def enableMarker(self, checked):
        any_markers_visible = False
        for d in self.marker_dict:
            marker = self.marker_dict[d]['marker']
            button = self.marker_dict[d]['button']
            any_markers_visible = any_markers_visible or button.isChecked()
            marker.setVisible(button.isChecked())
            self.markerMoved(d)
            self.marker_dict[d]['xcurve'].setVisible(button.isChecked())
            self.marker_dict[d]['ycurve'].setVisible(button.isChecked())
            self.marker_dict[d]['xlineedit'].setEnabled(button.isChecked())
            self.marker_dict[d]['ylineedit'].setEnabled(button.isChecked())
        if any_markers_visible:
            self.xLineoutPlot.show()
            self.yLineoutPlot.show()
        else:
            self.xLineoutPlot.hide()
            self.yLineoutPlot.hide()

    @pyqtSlot()
    def markerPositionLineEditChanged(self):
        for d in self.marker_dict:
            marker = self.marker_dict[d]['marker']
            x_line_edit = self.marker_dict[d]['xlineedit']
            y_line_edit = self.marker_dict[d]['ylineedit']
            try:
                new_x = int(x_line_edit.text())
                new_y = int(y_line_edit.text())
                if new_x <= marker.maxBounds.width(
                ) and new_y <= marker.maxBounds.height():
                    marker.setPos((new_x, new_y))
                    return
            except:
                pass
            coords = marker.getPixelCoords()
            x_line_edit.setText(str(coords[0]))
            y_line_edit.setText(str(coords[1]))

    @pyqtSlot(object)
    def markerMoved(self, marker):
        self.updateLineouts()
        for marker_index in self.marker_dict:
            marker = self.marker_dict[marker_index]['marker']
            x_line_edit = self.marker_dict[marker_index]['xlineedit']
            y_line_edit = self.marker_dict[marker_index]['ylineedit']
            coords = marker.getPixelCoords()
            x_line_edit.setText(str(coords[0]))
            y_line_edit.setText(str(coords[1]))

    @pyqtSlot(object, object)
    def updateLineoutRange(self, view, new_ranges):
        self.ui.xLineoutPlot.setRange(xRange=new_ranges[0], padding=0.0)
        self.ui.yLineoutPlot.setRange(yRange=new_ranges[1], padding=0.0)

    def updateLineouts(self):
        for marker_index in self.marker_dict:
            marker = self.marker_dict[marker_index]['marker']
            xcurve = self.marker_dict[marker_index]['xcurve']
            ycurve = self.marker_dict[marker_index]['ycurve']
            if marker.isVisible():
                result, coords = marker.getArrayRegion(
                    self.image_data, self.ui.imageView.getImageItem())
                xcurve.setData(y=result[0], x=np.arange(len(result[0])))
                ycurve.setData(y=np.arange(len(result[1])), x=result[1])

    @pyqtSlot()
    def enableSingleShotMode(self):
        self._average_mode_enabled = False
        self._average_buffer = np.ndarray(0)

    @pyqtSlot()
    def enableAverageMode(self):
        self._average_mode_enabled = True

    @pyqtSlot(str)
    def cameraChanged(self, new_camera):
        new_camera = str(new_camera)
        if self.imageChannel == self.cameras[new_camera]["image"]:
            return
        self.display_manager_window.close_widget_connections(self)
        self.disable_all_markers()
        self.initializeCamera(new_camera)
        self.display_manager_window.establish_widget_connections(self)

    def initializeCamera(self, new_camera):
        new_camera = str(new_camera)
        self._color_map_limit_sliders_need_config = True
        self.times = np.zeros(10)
        self.old_timestamp = 0
        self.image_width = 0  #current width (width of ROI)
        self.image_max_width = 0  #full width.  Only used to reset ROI to full.
        self.image_max_height = 0  #full height.  Only used to reset ROI to full.
        self.image_data = np.zeros(0)
        self._average_counter = 0
        self._average_buffer = np.ndarray(0)
        self._needs_auto_range = True
        self.imageChannel = self.cameras[new_camera]["image"]
        self.widthChannel = self.cameras[new_camera][
            "roi_width"] or self.cameras[new_camera]["max_width"]
        self.maxWidthChannel = self.cameras[new_camera]["max_width"]
        self.maxHeightChannel = self.cameras[new_camera]["max_height"]
        self.roiXChannel = self.cameras[new_camera]["roi_x"]
        self.roiYChannel = self.cameras[new_camera]["roi_y"]
        self.roiWidthChannel = self.cameras[new_camera]["roi_width"]
        self.roiHeightChannel = self.cameras[new_camera]["roi_height"]

        self._channels = [
            PyDMChannel(address=self.imageChannel,
                        connection_slot=self.connectionStateChanged,
                        waveform_slot=self.receiveImageWaveform,
                        severity_slot=self.alarmSeverityChanged),
            PyDMChannel(address=self.widthChannel,
                        value_slot=self.receiveImageWidth),
            PyDMChannel(address=self.maxWidthChannel,
                        value_slot=self.receiveMaxWidth),
            PyDMChannel(address=self.maxHeightChannel,
                        value_slot=self.receiveMaxHeight)
        ]
        if self.roiXChannel and self.roiYChannel and self.roiWidthChannel and self.roiHeightChannel:
            self._channels.extend([
                PyDMChannel(address=self.roiXChannel,
                            value_slot=self.receiveRoiX,
                            value_signal=self.roi_x_signal,
                            write_access_slot=self.roiWriteAccessChanged),
                PyDMChannel(address=self.roiYChannel,
                            value_slot=self.receiveRoiY,
                            value_signal=self.roi_y_signal),
                PyDMChannel(address=self.roiWidthChannel,
                            value_slot=self.receiveRoiWidth,
                            value_signal=self.roi_w_signal),
                PyDMChannel(address=self.roiHeightChannel,
                            value_slot=self.receiveRoiHeight,
                            value_signal=self.roi_h_signal)
            ])
            self.ui.roiXLineEdit.setEnabled(True)
            self.ui.roiYLineEdit.setEnabled(True)
            self.ui.roiWLineEdit.setEnabled(True)
            self.ui.roiHLineEdit.setEnabled(True)
        else:
            self.ui.roiXLineEdit.clear()
            self.ui.roiXLineEdit.setEnabled(False)
            self.ui.roiYLineEdit.clear()
            self.ui.roiYLineEdit.setEnabled(False)
            self.ui.roiWLineEdit.clear()
            self.ui.roiWLineEdit.setEnabled(False)
            self.ui.roiHLineEdit.clear()
            self.ui.roiHLineEdit.setEnabled(False)

    @pyqtSlot()
    def setROI(self):
        self.roi_x_signal.emit(self.ui.roiXLineEdit.text())
        self.roi_y_signal.emit(self.ui.roiYLineEdit.text())
        self.roi_w_signal.emit(self.ui.roiWLineEdit.text())
        self.roi_h_signal.emit(self.ui.roiHLineEdit.text())

    @pyqtSlot()
    def resetROI(self):
        self.roi_x_signal.emit(str(0))
        self.roi_y_signal.emit(str(0))
        self.roi_w_signal.emit(str(self.image_max_width))
        self.roi_h_signal.emit(str(self.image_max_height))

    @pyqtSlot(str)
    def colorMapChanged(self, new_map_name):
        self.ui.imageView.setColorMapToPreset(new_map_name)

    def configureColorMapLimitSliders(self, max_int):
        self.ui.colorMapMinSlider.setMaximum(max_int)
        self.ui.colorMapMaxSlider.setMaximum(max_int)
        self.ui.colorMapMaxSlider.setValue(max_int)
        self.ui.colorMapMinSlider.setValue(0)
        self.setColorMapMin(0)
        self.setColorMapMax(max_int)
        self._color_map_limit_sliders_need_config = False

    @pyqtSlot()
    def colorMapMinLineEditChanged(self):
        try:
            new_min = int(self.ui.colorMapMinLineEdit.text())
        except:
            self.ui.colorMapMinLineEdit.setText(
                str(self.ui.colorMapMinSlider.value()))
            return
        if new_min < 0:
            new_min = 0
        if new_min > self.ui.colorMapMinSlider.maximum():
            new_min = self.ui.colorMapMinSlider.maximum()
        self.ui.colorMapMinSlider.setValue(new_min)

    @pyqtSlot(int)
    def setColorMapMin(self, new_min):
        if new_min > self.ui.colorMapMaxSlider.value():
            self.ui.colorMapMaxSlider.setValue(new_min)
            self.ui.colorMapMaxLineEdit.setText(str(new_min))
        self.ui.colorMapMinLineEdit.setText(str(new_min))
        self.ui.imageView.setColorMapLimits(new_min,
                                            self.ui.colorMapMaxSlider.value())

    @pyqtSlot()
    def colorMapMaxLineEditChanged(self):
        try:
            new_max = int(self.ui.colorMapMaxLineEdit.text())
        except:
            self.ui.colorMapMaxLineEdit.setText(
                str(self.ui.colorMapMaxSlider.value()))
            return
        if new_max < 0:
            new_max = 0
        if new_max > self.ui.colorMapMaxSlider.maximum():
            new_max = self.ui.colorMapMaxSlider.maximum()
        self.ui.colorMapMaxSlider.setValue(new_max)

    @pyqtSlot(int)
    def setColorMapMax(self, new_max):
        if new_max < self.ui.colorMapMinSlider.value():
            self.ui.colorMapMinSlider.setValue(new_max)
            self.ui.colorMapMinLineEdit.setText(str(new_max))
        self.ui.colorMapMaxLineEdit.setText(str(new_max))
        self.ui.imageView.setColorMapLimits(self.ui.colorMapMinSlider.value(),
                                            new_max)

    def createAverageBuffer(self, size, type, initial_val=[]):
        num_shots = 1
        try:
            num_shots = int(self.ui.numShotsLineEdit.text())
        except:
            self.ui.numShotsLineEdit.setText(str(num_shots))
        if num_shots < 1:
            num_shots = 1
            self.ui.numShotsLineEdit.setText(str(num_shots))
        if num_shots > 200:
            num_shots = 200
            self.ui.numShotsLineEdit.setText(str(num_shots))
        if len(initial_val) > 0:
            return np.full((num_shots, size), initial_val, dtype=type)
        else:
            return np.zeros(shape=(num_shots, size), dtype=type)

    @pyqtSlot()
    def numAverageChanged(self):
        self._average_buffer = np.zeros(0)

    @pyqtSlot(np.ndarray)
    def receiveImageWaveform(self, new_waveform):
        if not self.image_width:
            return

        #Calculate the average rate
        new_timestamp = time.time()
        if not (self.old_timestamp == 0):
            delta = new_timestamp - self.old_timestamp
            self.times = np.roll(self.times, 1)
            self.times[0] = delta
            avg_delta = np.mean(self.times)
            self.ui.dataRateLabel.setText("{:.1f} Hz".format(
                (1.0 / avg_delta)))
            self.ui.displayRateLabel.setText("{:.1f} Hz".format(
                (1.0 / avg_delta)))
        self.old_timestamp = new_timestamp

        #If this is the first image, set up the color map slider limits
        if self._color_map_limit_sliders_need_config:
            max_int = np.iinfo(new_waveform.dtype).max
            self.configureColorMapLimitSliders(max_int)

        #If we are in average mode, add this image to the circular averaging buffer, otherwise just display it.
        if self._average_mode_enabled:
            if len(self._average_buffer) == 0:
                self._average_buffer = self.createAverageBuffer(
                    len(new_waveform), new_waveform.dtype, new_waveform)
                self._average_counter = 0
            self._average_counter = (self._average_counter + 1) % len(
                self._average_buffer)
            #self._average_buffer = np.roll(self._average_buffer, 1, axis=0)
            self._average_buffer[self._average_counter] = new_waveform
            mean = np.mean(self._average_buffer,
                           axis=0).astype(new_waveform.dtype)
            self.image_data = mean.reshape((int(self.image_width), -1),
                                           order='F')
        else:
            self.image_data = new_waveform.reshape((int(self.image_width), -1),
                                                   order='F')
        self.setMarkerBounds()
        self.updateLineouts()
        self.ui.imageView.receiveImageWaveform(self.image_data)
        self.calculateStats()
        if self._needs_auto_range:
            self.ui.imageView.getView().autoRange(padding=0.0)
            current_range = self.ui.imageView.getView().viewRange()
            self._needs_auto_range = False

    def calculateStats(self):
        # Full image stats
        mean = np.mean(self.image_data)
        std = np.std(self.image_data)
        width = self.image_data.shape[0]
        height = self.image_data.shape[1]
        min_val = np.min(self.image_data)
        max_val = np.max(self.image_data)
        self.ui.imageStatsLabel.setText(
            "Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}"
            .format(mean, std, min_val, max_val, width, height))
        # Current view stats
        current_range = self.ui.imageView.getView().viewRange()
        view_x_min = int(max(0, current_range[0][0]))
        view_x_max = int(min(self.image_data.shape[0], current_range[0][1]))
        view_y_min = int(max(0, current_range[1][0]))
        view_y_max = int(min(self.image_data.shape[1], current_range[1][1]))
        view_slice = self.image_data[view_x_min:view_x_max,
                                     view_y_min:view_y_max]
        mean = np.mean(view_slice)
        std = np.std(view_slice)
        width = view_slice.shape[0]
        height = view_slice.shape[1]
        min_val = np.min(view_slice)
        max_val = np.max(view_slice)
        self.ui.viewStatsLabel.setText(
            "Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}"
            .format(mean, std, min_val, max_val, width, height))

    def setMarkerBounds(self):
        for marker_index in self.marker_dict:
            marker = self.marker_dict[marker_index]['marker']
            marker.maxBounds = QRectF(
                0, 0, self.image_data.shape[0] + marker.size()[0] - 1,
                self.image_data.shape[1] + marker.size()[1] - 1)

    @pyqtSlot(int)
    def receiveImageWidth(self, new_width):
        self.image_width = new_width
        self.ui.imageView.receiveImageWidth(self.image_width)

    @pyqtSlot(int)
    def receiveMaxWidth(self, new_max_width):
        self.image_max_width = new_max_width

    @pyqtSlot(int)
    def receiveMaxHeight(self, new_max_height):
        self.image_max_height = new_max_height

    @pyqtSlot(int)
    def receiveRoiX(self, new_roi_x):
        self.ui.roiXLineEdit.setText(str(new_roi_x))

    @pyqtSlot(int)
    def receiveRoiY(self, new_roi_y):
        self.ui.roiYLineEdit.setText(str(new_roi_y))

    @pyqtSlot(int)
    def receiveRoiWidth(self, new_roi_w):
        self.ui.roiWLineEdit.setText(str(new_roi_w))

    @pyqtSlot(int)
    def receiveRoiHeight(self, new_roi_h):
        self.ui.roiHLineEdit.setText(str(new_roi_h))

    # -2 to +2, -2 is LOLO, -1 is LOW, 0 is OK, etc.
    @pyqtSlot(int)
    def alarmStatusChanged(self, new_alarm_state):
        pass

    #0 = NO_ALARM, 1 = MINOR, 2 = MAJOR, 3 = INVALID
    @pyqtSlot(int)
    def alarmSeverityChanged(self, new_alarm_severity):
        pass

    @pyqtSlot(bool)
    def roiWriteAccessChanged(self, can_write_roi):
        self.ui.setROIButton.setEnabled(can_write_roi)
        self.ui.resetROIButton.setEnabled(can_write_roi)
        self.ui.roiXLineEdit.setReadOnly(not can_write_roi)
        self.ui.roiYLineEdit.setReadOnly(not can_write_roi)
        self.ui.roiWLineEdit.setReadOnly(not can_write_roi)
        self.ui.roiHLineEdit.setReadOnly(not can_write_roi)

    #false = disconnected, true = connected
    @pyqtSlot(bool)
    def connectionStateChanged(self, connected):
        self.ui.connectedLabel.setText({True: "Yes", False: "No"}[connected])

    def ui_filename(self):
        return 'camviewer.ui'

    def ui_filepath(self):
        return path.join(path.dirname(path.realpath(__file__)),
                         self.ui_filename())

    def channels(self):
        return self._channels
コード例 #11
0
ファイル: modbus_plugin.py プロジェクト: slaclab/pydm_modbus
class DataThread(QThread):
    new_data_signal = pyqtSignal([float], [int], [str])

    def __init__(self,
                 ip,
                 port,
                 slave_id,
                 designator,
                 addr,
                 length,
                 bit,
                 poll_interval=0.1):
        super(QThread, self).__init__()
        self.ip = ip
        self.port = port
        self.slave_id = slave_id
        self.designator = designator
        self.addr = addr
        self.length = length
        self.bit = bit
        self.poll_interval = poll_interval

        self.designator_map = {
            'HR': {
                'read': self.read_hr,
                'write': self.write_hr
            }
        }

        self.server = ModbusServer(self.ip, self.port)

        try:
            self.read_data = self.designator_map[self.designator]['read']
            self.write_data = self.designator_map[self.designator]['write']
        except IndexError:
            self.read_data = lambda *a, **k: None
            self.write_data = lambda *a, **k: None

    def run(self):
        while not self.isInterruptionRequested():
            data = self.read_data()
            if data is not None:
                self.new_data_signal.emit(data)
            self.msleep(int(self.poll_interval * 1000))

    def write(self, new_value):
        print("Write!")
        self.write_data(new_value)

    def read_hr(self):
        message = tcp.read_holding_registers(slave_id=self.slave_id,
                                             starting_address=self.addr,
                                             quantity=1)
        response = self.server.send_message(message)

        if response is not None:
            if self.bit is None:
                return response[0]
            else:

                def get_bit(decimal, N):
                    mask = 1 << N
                    if decimal & mask:
                        return 1
                    else:
                        return 0

                return (get_bit(response[0], self.bit))

        else:
            return None

    def write_hr(self, new_value):

        if self.bit is not None:
            message = tcp.read_holding_registers(slave_id=self.slave_id,
                                                 starting_address=self.addr,
                                                 quantity=1)
            response = self.server.send_message(message)
            current_value = response[0]

            if new_value:
                new_value = current_value | 1 << self.bit
            else:
                new_value = current_value & ~(1 << self.bit)

        message = tcp.write_multiple_registers(slave_id=self.slave_id,
                                               starting_address=self.addr,
                                               values=[int(new_value)])
        response = self.server.send_message(message)
        return response
コード例 #12
0
ファイル: ensemble_plugin.py プロジェクト: klauer/aerotech
class PollThread(QThread):
    new_data_signal = pyqtSignal(object)
    new_severity_signal = pyqtSignal(int)
    writable = False

    def __init__(self, connection, client, parameter, *, poll_rate=0.1):
        super().__init__()
        self.connection = connection
        self.poll_rate_ms = int(poll_rate * 1000)
        self.client = client
        self.parameter = parameter
        self.start()

    def run(self):
        loop = self.client.loop
        failed_rate = self.poll_rate_ms * 2
        while not self.isInterruptionRequested():
            if self.client.comm is None:
                self.new_severity_signal.emit(Severity.INVALID)
                self.msleep(failed_rate)
                continue

            with self.client.lock:
                sleep_ms = failed_rate
                comm = self.client.comm
                if comm is None:
                    self.new_severity_signal.emit(Severity.INVALID)
                else:
                    try:
                        data = self.query(comm, loop)
                        if asyncio.iscoroutine(data):
                            data = loop.run_until_complete(data)
                    except (BrokenPipeError, ConnectionResetError) as ex:
                        logger.error('Poll failed; connection lost')
                        self.client.comm = None
                        sleep_ms = failed_rate * 2
                        self.new_severity_signal.emit(Severity.INVALID)
                    except aerotech.FailureResponseException as ex:
                        logger.warning('Query failed: %s', self.parameter)
                        self.new_severity_signal.emit(Severity.MAJOR)
                    except aerotech.FaultResponseException as ex:
                        logger.warning('Query fault: %s', self.parameter)
                        self.new_severity_signal.emit(Severity.MAJOR)
                    except aerotech.TimeoutResponseException as ex:
                        logger.warning('Query timed out: %s', self.parameter)
                        self.new_severity_signal.emit(Severity.MINOR)
                    except Exception as ex:
                        logger.exception('Poll failed')
                        self.new_severity_signal.emit(Severity.MAJOR)
                    else:
                        sleep_ms = self.poll_rate_ms
                        self.new_severity_signal.emit(Severity.NO_ALARM)
                        data = self.fix_value(data)
                        logger.debug('%s => %s', self.parameter, data)
                        self.new_data_signal.emit(data)
            self.msleep(sleep_ms)

    def fix_value(self, value):
        try:
            return ast.literal_eval(value)
        except Exception:
            return value

    def query(self, comm, loop):
        # Return a coroutine that gets waited on above
        return comm.write_read(self.parameter)
コード例 #13
0
class DataThread(QThread):
    new_data_signal = pyqtSignal([float], [int], [str])

    def __init__(self, ip, port, module, addr, poll_interval=0.1):
        super(QThread, self).__init__()
        self.ip = ip
        self.port = port

        if module.find('S') != 0:
            module = "S" + module
        self.module_sn = module

        self.module = None
        self.moduleW = None
        self.addr = addr
        self.poll_interval = poll_interval

        self.server = Maq20Server(self.ip, self.port)

    def run(self):
        while not self.isInterruptionRequested():
            self.update_data()

            self.msleep(int(self.poll_interval * 1000))

    def update_data(self):
        if self.server.connected:
            data = self.read_data()
            if data is not None:
                self.new_data_signal.emit(data)

    def write(self, new_value):
        if self.server.connected:
            self.write_data(new_value)

    def read_data(self):
        self.server.mutex.lock()

        try:
            if self.module is None:
                print("read", self.module, self.ip, self.module_sn, self.addr)

                self.module = self.server.system.find(self.module_sn)

            if str(self.addr).find('r') == 0:
                addr = str(self.addr).replace("r", '')
                response = self.module.read_register(int(addr))
            else:
                if not self.module.has_range_information():
                    response = self.module.read_channel_data_counts(
                        int(self.addr))
                else:
                    self.module.load_channel_active_ranges()
                    response = self.module.read_channel_data(int(self.addr))

        except:
            self.module = None
            response = None
            try:
                self.server.system.time()
            except:
                self.server.connected = False
        finally:
            self.server.mutex.unlock()

        if response is not None:
            return response
        else:
            return None

    def write_data(self, new_value):
        self.server.mutexW.lock()
        try:
            if self.moduleW is None:
                self.moduleW = self.server.systemW.find(self.module_sn)
                print("Write", self.moduleW, self.ip, self.module_sn,
                      self.addr)

            if str(self.addr).find('r') == 0:
                print("reg")
                addr = str(self.addr).replace("r", '')
                response = self.module.write_register(int(addr), new_value)

            else:
                if not self.moduleW.has_range_information():
                    self.moduleW.write_register(1000 + int(self.addr),
                                                new_value)
                else:
                    self.moduleW.write_channel_data(int(self.addr), new_value)
        except:
            self.moduleW = None
            try:
                self.server.systemW.time()
            except:
                self.server.connectedW = False
        finally:
            self.server.mutexW.unlock()

            self.update_data()
コード例 #14
0
class SignalHolder(QObject):
    """
    Dummy QObject to let us use pyqtSignal
    """
    value_sig = pyqtSignal([int], [float], [str])
    empty_sig = pyqtSignal()