mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-06 10:00:40 +02:00
* added empty c extension * added rotation to the decoding * added color map, options and findex * minor * move checks to before acquisition * added pixel map based decoder * cleanup * no thread creation for single thread processing * added rotation and test to compare * allow high and low water mark for zmq (also buffer size) for fast readouts * removed roatation during decoding * added Transpose to image and invert Y False to invert it * retains the zoomed state after the first image of gui, catch and display exception if no detector connected * moved start frame to dockable widget, removed extra frame number label, moved current measurement also to dockable widget, hide frame plot entirely when showing patternviewer * first image dependin on which plot * remember settings of main window size and position, dockewidget if docked, its size and posisiotn as well, then update it next time the gui is opened * change in comment * using c decoder for moench 04 and matterhorn * catch exception from invalid image from decoder * clean up * update row and col when choosing image type, neeeded to show values * fix for previous PR * disable resetting colormap values keep the range selected for every new acquisition * fix typos + tested on virtual matterhorn * minor print * refactored Slow ADCs Tab * refactored DAC tab * refactored power supplies * refactored signals tab * refactored transceiver tab * fix typo * fix typo2 * remove commented code * delete commented code * delete commented code * delete commented signals code * remove commented code for transceiver tab * refactor adc tab * refactor Pattern Tab * Refactor transceivers tab (PR#5) (#118) * refactored transceiver tab * remove commented code for transceiver tab --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> * refactor adc tab (PR#6) (#119) * refactor adc tab * refactored Plot and Acquisition Tabs * fix the regression issue * restructure project files * applying singleton and renaming tabs to services * working install using pip * applies singleton to tab classes and remove CI erros * added pyzmq and pillow * remove the singleton implementation and keep changes * fix merge errors in mainWindow * moved misplaced init file * rename service to tab * reorganize imports * iterate over tabs * reorder tabs * add slowadc to the list * saving changes (buggy) power supply ui not showing in the gui * split power supply tab * fixed tests * add hardcoded values to defines file * fix error * separate power supply * fix errors for powerSuppliesTab * split dacs * split slow adcs * split signals tab * added tests for bit_utils * add slowAdc class to defines * split transceiver ui file * split adc.ui * split pattern ui file * split plot and acquisition ui file * added basic test for parsing bit names * removed redundant code in read_alias_file * fix dacs ui position * testing for correct exception * cmd and args at split * group radio buttons * fix comments from PR#1 * show legend * added python version and dev requirements to setup.py * fix dac issue * moved _decoder into pkg * added inplace build * removed clear * fixed dependencies * make tests run without slsdet * updated name of action * define colcount * fixed loading of alias file * add yapf and ruff * apply formatting * fix E and F rules * add more ruff rules * change variable name * squashing gh debugging commits and add pre-commit * update label values to mv units * add hook for yapf * reconfigure yapf precommit hook * add format and check_format to makefile * change gh actions * update readme * added check_format * WIP * added linting in github action * updated readme] * add more control for color choice * remove useless file * fix un-updated line after refactoring Defines BIT0_31_MASK is not found in Defines.signals * visually improve the interface * fix last commit * add only selected plots for legend * add hide legend button * change hide legend to show legend checkbox show legend is checked by default * add support for saving in numpy * solve conversations * fix acq index offset * fix browse button in pattern error * fix other browse button errors * finish tests and add usage.md * remove buffer * add file,numpy-like interface and tests * remove useless .npy files * subscriptible npz files * remove useless files * remove repetetive tests * save changes * add mode r+, add with support,remove logging * remove offset of acqIndex between raw and numpy saving * fix only saving last frame * save signals of multiple devices * add comments and move condition for clearer code * fix bug when vieweing pattern file * iterate over enabled and plotted plots * add padestal substraction to transceiver and analog data * init pedestal frames to detector.frames * restore old exception * add pedestal substraction for digital signals * remove frames spinbox from plotTab * remove comments and use str instead of Path * avoid saving all frames * correct exception and log error's trace * add gui tests * add waveform test * add pedestal test * refactor by using fixtures * add tests for moench analog and pattern * add pytest-qt to dependencies * add save and load gui parameters * remove nohup file * fix old bug IndexError * save plot type * a * handle canceling load, loading matterhorn pedestal for moench * remove comparing .png files for pattern test * save plot type * red error on status bar when shape mismatch for loaded pedestal * fix makefile and docstrings * fix PRs conversation * move code into different function * fix wrong function names for power supply * removed old ctbgui * removed unnecessary files --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> Co-authored-by: Braham Bechir <braham_b@pc11979.psi.ch> Co-authored-by: Bechir <bechir.braham@psi.ch> Co-authored-by: Bechir <bechir.brahem420@gmail.com>
274 lines
12 KiB
Python
274 lines
12 KiB
Python
from functools import partial
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
from PyQt5 import QtWidgets, uic
|
|
import pyqtgraph as pg
|
|
from pyqtgraph import LegendItem
|
|
|
|
from pyctbgui.utils import decoder
|
|
from pyctbgui.utils.defines import Defines
|
|
|
|
from pyctbgui.utils.bit_utils import bit_is_set, manipulate_bit
|
|
import pyctbgui.utils.pixelmap as pm
|
|
from pyctbgui.utils.recordOrApplyPedestal import recordOrApplyPedestal
|
|
|
|
|
|
class TransceiverTab(QtWidgets.QWidget):
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(parent)
|
|
uic.loadUi(Path(__file__).parent.parent / 'ui' / "transceiver.ui", parent)
|
|
self.view = parent
|
|
self.mainWindow = None
|
|
self.det = None
|
|
self.plotTab = None
|
|
self.legend: LegendItem | None = None
|
|
self.acquisitionTab = None
|
|
|
|
def setup_ui(self):
|
|
self.plotTab = self.mainWindow.plotTab
|
|
self.acquisitionTab = self.mainWindow.acquisitionTab
|
|
for i in range(Defines.transceiver.count):
|
|
self.setTransceiverButtonColor(i, self.plotTab.getRandomColor())
|
|
self.initializeAllTransceiverPlots()
|
|
|
|
self.legend = self.mainWindow.plotTransceiverWaveform.getPlotItem().legend
|
|
self.legend.clear()
|
|
|
|
# subscribe to toggle legend
|
|
self.plotTab.subscribeToggleLegend(self.updateLegend)
|
|
|
|
def connect_ui(self):
|
|
for i in range(Defines.transceiver.count):
|
|
getattr(self.view, f"checkBoxTransceiver{i}").stateChanged.connect(partial(self.setTransceiverEnable, i))
|
|
getattr(self.view,
|
|
f"checkBoxTransceiver{i}Plot").stateChanged.connect(partial(self.setTransceiverEnablePlot, i))
|
|
getattr(self.view, f"pushButtonTransceiver{i}").clicked.connect(partial(self.selectTransceiverColor, i))
|
|
self.view.lineEditTransceiverMask.editingFinished.connect(self.setTransceiverEnableReg)
|
|
|
|
def refresh(self):
|
|
self.updateTransceiverEnable()
|
|
|
|
def getEnabledPlots(self):
|
|
"""
|
|
return plots that are shown (checkBoxTransceiver{i}Plot is checked)
|
|
"""
|
|
enabledPlots = []
|
|
self.legend.clear()
|
|
for i in range(Defines.transceiver.count):
|
|
if getattr(self.view, f'checkBoxTransceiver{i}Plot').isChecked():
|
|
plotName = getattr(self.view, f"labelTransceiver{i}").text()
|
|
enabledPlots.append((self.mainWindow.transceiverPlots[i], plotName))
|
|
return enabledPlots
|
|
|
|
def updateLegend(self):
|
|
"""
|
|
update the legend for the transceiver waveform plot
|
|
should be called after checking or unchecking plot checkbox
|
|
"""
|
|
if not self.mainWindow.showLegend:
|
|
self.legend.clear()
|
|
else:
|
|
for plot, name in self.getEnabledPlots():
|
|
self.legend.addItem(plot, name)
|
|
|
|
@recordOrApplyPedestal
|
|
def _processWaveformData(self, data, dSamples, romode, nDBitEnabled, nTransceiverEnabled):
|
|
"""
|
|
model function
|
|
processes raw receiver waveform data
|
|
@param data: raw receiver waveform data
|
|
@param dSamples: digital samples
|
|
@param romode: readout mode value
|
|
@param nDBitEnabled: number of digital bits enabled
|
|
@param nTransceiverEnabled: number of transceivers enabled
|
|
@return: processed transceiver data
|
|
"""
|
|
transceiverOffset = 0
|
|
if romode == 4:
|
|
nbitsPerDBit = dSamples
|
|
if dSamples % 8 != 0:
|
|
nbitsPerDBit += (8 - (dSamples % 8))
|
|
transceiverOffset += nDBitEnabled * (nbitsPerDBit // 8)
|
|
trans_array = np.array(np.frombuffer(data, offset=transceiverOffset, dtype=np.uint16))
|
|
return trans_array.reshape(-1, nTransceiverEnabled)
|
|
|
|
def processWaveformData(self, data, dSamples):
|
|
"""
|
|
plots raw waveform data
|
|
data: raw waveform data
|
|
dsamples: digital samples
|
|
tsamples: transceiver samples
|
|
"""
|
|
waveforms = {}
|
|
trans_array = self._processWaveformData(data, dSamples, self.mainWindow.romode.value,
|
|
self.mainWindow.nDBitEnabled, self.nTransceiverEnabled)
|
|
idx = 0
|
|
for i in range(Defines.transceiver.count):
|
|
checkBoxPlot = getattr(self.view, f"checkBoxTransceiver{i}Plot")
|
|
checkBoxEn = getattr(self.view, f"checkBoxTransceiver{i}")
|
|
if checkBoxEn.isChecked() and checkBoxPlot.isChecked():
|
|
waveform = trans_array[:, idx]
|
|
idx += 1
|
|
self.mainWindow.transceiverPlots[i].setData(waveform)
|
|
plotName = getattr(self.view, f"labelTransceiver{i}").text()
|
|
waveforms[plotName] = waveform
|
|
return waveforms
|
|
|
|
@recordOrApplyPedestal
|
|
def _processImageData(self, data, dSamples, romode, nDBitEnabled):
|
|
"""
|
|
processes raw image data
|
|
@param data:
|
|
@param dSamples:
|
|
@param romode:
|
|
@param nDBitEnabled:
|
|
@return:
|
|
"""
|
|
transceiverOffset = 0
|
|
if romode == 4:
|
|
nbitsPerDBit = dSamples
|
|
if dSamples % 8 != 0:
|
|
nbitsPerDBit += (8 - (dSamples % 8))
|
|
transceiverOffset += nDBitEnabled * (nbitsPerDBit // 8)
|
|
trans_array = np.array(np.frombuffer(data, offset=transceiverOffset, dtype=np.uint16))
|
|
return decoder.decode(trans_array, pm.matterhorn_transceiver())
|
|
|
|
def processImageData(self, data, dSamples):
|
|
"""
|
|
view function
|
|
plots transceiver image
|
|
dSamples: digital samples
|
|
data: raw image data
|
|
"""
|
|
# get zoom state
|
|
viewBox = self.mainWindow.plotTransceiverImage.getView()
|
|
state = viewBox.getState()
|
|
try:
|
|
self.mainWindow.transceiver_frame = self._processImageData(data, dSamples, self.mainWindow.romode.value,
|
|
self.mainWindow.nDBitEnabled)
|
|
self.plotTab.ignoreHistogramSignal = True
|
|
self.mainWindow.plotTransceiverImage.setImage(self.mainWindow.transceiver_frame)
|
|
except Exception:
|
|
self.mainWindow.statusbar.setStyleSheet("color:red")
|
|
message = f'Warning: Invalid size for Transceiver Image. Expected' \
|
|
f' {self.mainWindow.nTransceiverRows * self.mainWindow.nTransceiverCols} size,' \
|
|
f' got {self.mainWindow.transceiver_frame.size} instead.'
|
|
self.acquisitionTab.updateCurrentFrame('Invalid Image')
|
|
self.mainWindow.statusbar.showMessage(message)
|
|
print(message)
|
|
|
|
self.plotTab.setFrameLimits(self.mainWindow.transceiver_frame)
|
|
|
|
# keep the zoomed in state (not 1st image)
|
|
if self.mainWindow.firstTransceiverImage:
|
|
self.mainWindow.firstTransceiverImage = False
|
|
else:
|
|
viewBox.setState(state)
|
|
return self.mainWindow.transceiver_frame
|
|
|
|
def initializeAllTransceiverPlots(self):
|
|
self.mainWindow.plotTransceiverWaveform = pg.plot()
|
|
self.mainWindow.plotTransceiverWaveform.addLegend(colCount=Defines.colCount)
|
|
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotTransceiverWaveform, 5)
|
|
self.mainWindow.transceiverPlots = {}
|
|
waveform = np.zeros(1000)
|
|
for i in range(Defines.transceiver.count):
|
|
pen = pg.mkPen(color=self.getTransceiverButtonColor(i), width=1)
|
|
legendName = getattr(self.view, f"labelTransceiver{i}").text()
|
|
self.mainWindow.transceiverPlots[i] = self.mainWindow.plotTransceiverWaveform.plot(waveform,
|
|
pen=pen,
|
|
name=legendName)
|
|
self.mainWindow.transceiverPlots[i].hide()
|
|
|
|
self.mainWindow.plotTransceiverImage = pg.ImageView()
|
|
self.mainWindow.nTransceiverRows = 0
|
|
self.mainWindow.nTransceiverCols = 0
|
|
self.mainWindow.transceiver_frame = np.zeros(
|
|
(self.mainWindow.nTransceiverRows, self.mainWindow.nTransceiverCols))
|
|
self.mainWindow.plotTransceiverImage.setImage(self.mainWindow.transceiver_frame)
|
|
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotTransceiverImage, 6)
|
|
|
|
cm = pg.colormap.get('CET-L9') # prepare a linear color map
|
|
self.mainWindow.plotTransceiverImage.setColorMap(cm)
|
|
|
|
def getTransceiverEnableReg(self):
|
|
retval = self.det.transceiverenable
|
|
self.view.lineEditTransceiverMask.editingFinished.disconnect()
|
|
self.view.lineEditTransceiverMask.setText("0x{:08x}".format(retval))
|
|
self.view.lineEditTransceiverMask.editingFinished.connect(self.setTransceiverEnableReg)
|
|
return retval
|
|
|
|
def setTransceiverEnableReg(self):
|
|
self.view.lineEditTransceiverMask.editingFinished.disconnect()
|
|
try:
|
|
mask = int(self.view.lineEditTransceiverMask.text(), 16)
|
|
self.det.transceiverenable = mask
|
|
except Exception as e:
|
|
QtWidgets.QMessageBox.warning(self.mainWindow, "Transceiver Enable Fail", str(e), QtWidgets.QMessageBox.Ok)
|
|
pass
|
|
# TODO: handling double event exceptions
|
|
self.view.lineEditTransceiverMask.editingFinished.connect(self.setTransceiverEnableReg)
|
|
self.updateTransceiverEnable()
|
|
|
|
def getTransceiverEnable(self, i, mask):
|
|
checkBox = getattr(self.view, f"checkBoxTransceiver{i}")
|
|
checkBox.stateChanged.disconnect()
|
|
checkBox.setChecked(bit_is_set(mask, i))
|
|
checkBox.stateChanged.connect(partial(self.setTransceiverEnable, i))
|
|
|
|
def updateTransceiverEnable(self):
|
|
retval = self.getTransceiverEnableReg()
|
|
self.nTransceiverEnabled = bin(retval).count('1')
|
|
for i in range(4):
|
|
self.getTransceiverEnable(i, retval)
|
|
self.getTransceiverEnablePlot(i)
|
|
self.getTransceiverEnableColor(i)
|
|
self.plotTab.addSelectedTransceiverPlots(i)
|
|
|
|
def setTransceiverEnable(self, i):
|
|
checkBox = getattr(self.view, f"checkBoxTransceiver{i}")
|
|
try:
|
|
enableMask = manipulate_bit(checkBox.isChecked(), self.det.transceiverenable, i)
|
|
self.det.transceiverenable = enableMask
|
|
except Exception as e:
|
|
QtWidgets.QMessageBox.warning(self.mainWindow, "Transceiver Enable Fail", str(e), QtWidgets.QMessageBox.Ok)
|
|
pass
|
|
|
|
self.updateTransceiverEnable()
|
|
|
|
def getTransceiverEnablePlot(self, i):
|
|
checkBox = getattr(self.view, f"checkBoxTransceiver{i}")
|
|
checkBoxPlot = getattr(self.view, f"checkBoxTransceiver{i}Plot")
|
|
checkBoxPlot.setEnabled(checkBox.isChecked())
|
|
|
|
def setTransceiverEnablePlot(self, i):
|
|
pushButton = getattr(self.view, f"pushButtonTransceiver{i}")
|
|
checkBox = getattr(self.view, f"checkBoxTransceiver{i}Plot")
|
|
pushButton.setEnabled(checkBox.isChecked())
|
|
self.plotTab.addSelectedTransceiverPlots(i)
|
|
self.updateLegend()
|
|
|
|
def getTransceiverEnableColor(self, i):
|
|
checkBox = getattr(self.view, f"checkBoxTransceiver{i}Plot")
|
|
pushButton = getattr(self.view, f"pushButtonTransceiver{i}")
|
|
pushButton.setEnabled(checkBox.isEnabled() and checkBox.isChecked())
|
|
|
|
def selectTransceiverColor(self, i):
|
|
pushButton = getattr(self.view, f"pushButtonTransceiver{i}")
|
|
self.plotTab.showPalette(pushButton)
|
|
pen = pg.mkPen(color=self.getTransceiverButtonColor(i), width=1)
|
|
self.mainWindow.transceiverPlots[i].setPen(pen)
|
|
|
|
def getTransceiverButtonColor(self, i):
|
|
pushButton = getattr(self.view, f"pushButtonTransceiver{i}")
|
|
return self.plotTab.getActiveColor(pushButton)
|
|
|
|
def setTransceiverButtonColor(self, i, color):
|
|
pushButton = getattr(self.view, f"pushButtonTransceiver{i}")
|
|
return self.plotTab.setActiveColor(pushButton, color)
|
|
|
|
def saveParameters(self):
|
|
return ["transceiverenable {}".format(self.view.lineEditTransceiverMask.text())]
|