From 92da709bda88548b6602d1050aafde0e87df48b3 Mon Sep 17 00:00:00 2001 From: Alice Date: Fri, 6 Feb 2026 14:39:11 +0100 Subject: [PATCH 1/5] skip if not plotted --- pyctbgui/pyctbgui/services/Signals.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyctbgui/pyctbgui/services/Signals.py b/pyctbgui/pyctbgui/services/Signals.py index 856571e22..107eaa628 100644 --- a/pyctbgui/pyctbgui/services/Signals.py +++ b/pyctbgui/pyctbgui/services/Signals.py @@ -112,7 +112,7 @@ class SignalsTab(QtWidgets.QWidget): bit_index += (8 - (bit_index % 8)) if not isPlottedArray[i]: bit_index += nbitsPerDBit - samples_per_bit[idx, :] = np.nan + samples_per_bit[idx, :] = 0.0 continue for iSample in range(dSamples): # all samples for digital bit together from slsReceiver @@ -130,7 +130,7 @@ class SignalsTab(QtWidgets.QWidget): for idx, i in enumerate(rx_dbitlist): if not isPlottedArray[i]: bit_index += 1 - bits_per_sample[iSample, idx] = np.nan + bits_per_sample[iSample, idx] = 0.0 index = int(bit_index/8) iBit = idx % 8 @@ -161,9 +161,9 @@ class SignalsTab(QtWidgets.QWidget): irow = 0 for idx, i in enumerate(self.rx_dbitlist): # bits enabled but not plotting - waveform = digital_array[idx, :] - if np.isnan(waveform[0]): + if not isPlottedArray[i]: continue + waveform = digital_array[idx, :] self.mainWindow.digitalPlots[i].setData(waveform) plotName = getattr(self.view, f"labelBIT{i}").text() waveforms[plotName] = waveform From 7f5b26743f112a4d24af07999a520fe49fafb523 Mon Sep 17 00:00:00 2001 From: Alice Date: Fri, 6 Feb 2026 14:55:18 +0100 Subject: [PATCH 2/5] uff introduced another bug --- pyctbgui/pyctbgui/services/Signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyctbgui/pyctbgui/services/Signals.py b/pyctbgui/pyctbgui/services/Signals.py index 107eaa628..a836a41c6 100644 --- a/pyctbgui/pyctbgui/services/Signals.py +++ b/pyctbgui/pyctbgui/services/Signals.py @@ -163,7 +163,7 @@ class SignalsTab(QtWidgets.QWidget): # bits enabled but not plotting if not isPlottedArray[i]: continue - waveform = digital_array[idx, :] + waveform = digital_array[i, :] self.mainWindow.digitalPlots[i].setData(waveform) plotName = getattr(self.view, f"labelBIT{i}").text() waveforms[plotName] = waveform From 78044b2783864d3011fd6db398a95bb5f07ce6d1 Mon Sep 17 00:00:00 2001 From: Alice Date: Fri, 6 Feb 2026 16:41:04 +0100 Subject: [PATCH 3/5] always write all wave data & uncheck plot if digital bit unchecked --- pyctbgui/pyctbgui/services/Signals.py | 48 ++++++++++++--------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/pyctbgui/pyctbgui/services/Signals.py b/pyctbgui/pyctbgui/services/Signals.py index a836a41c6..c1eec01cb 100644 --- a/pyctbgui/pyctbgui/services/Signals.py +++ b/pyctbgui/pyctbgui/services/Signals.py @@ -36,16 +36,16 @@ class SignalsTab(QtWidgets.QWidget): for i in range(Defines.signals.count): getattr(self.view, f"checkBoxBIT{i}DB").stateChanged.connect(partial(self.setDigitalBitEnable, i)) getattr(self.view, f"checkBoxBIT{i}Out").stateChanged.connect(partial(self.setIOOut, i)) - getattr(self.view, f"checkBoxBIT{i}Plot").stateChanged.connect(partial(self.setEnableBitPlot, i)) + getattr(self.view, f"checkBoxBIT{i}Plot").stateChanged.connect(partial(self.setBitPlot, i)) getattr(self.view, f"pushButtonBIT{i}").clicked.connect(partial(self.selectBitColor, i)) self.view.checkBoxBIT0_31DB.stateChanged.connect( partial(self.setDigitalBitEnableRange, 0, Defines.signals.half)) self.view.checkBoxBIT32_63DB.stateChanged.connect( partial(self.setDigitalBitEnableRange, Defines.signals.half, Defines.signals.count)) - self.view.checkBoxBIT0_31Plot.stateChanged.connect(partial(self.setEnableBitPlotRange, 0, + self.view.checkBoxBIT0_31Plot.stateChanged.connect(partial(self.setBitPlotRange, 0, Defines.signals.half)) self.view.checkBoxBIT32_63Plot.stateChanged.connect( - partial(self.setEnableBitPlotRange, Defines.signals.half, Defines.signals.count)) + partial(self.setBitPlotRange, Defines.signals.half, Defines.signals.count)) self.view.checkBoxBIT0_31Out.stateChanged.connect(partial(self.setIOOutRange, 0, Defines.signals.half)) self.view.checkBoxBIT32_63Out.stateChanged.connect( partial(self.setIOOutRange, Defines.signals.half, Defines.signals.count)) @@ -90,7 +90,7 @@ class SignalsTab(QtWidgets.QWidget): self.legend.addItem(plot, name) @recordOrApplyPedestal - def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, isPlottedArray, romode, + def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, romode, nADCEnabled): #transform raw waveform data into a processed numpy array @@ -110,10 +110,7 @@ class SignalsTab(QtWidgets.QWidget): # where numbits * numsamples is not a multiple of 8 if bit_index % 8 != 0: bit_index += (8 - (bit_index % 8)) - if not isPlottedArray[i]: - bit_index += nbitsPerDBit - samples_per_bit[idx, :] = 0.0 - continue + for iSample in range(dSamples): # all samples for digital bit together from slsReceiver index = int(bit_index / 8) @@ -128,10 +125,6 @@ class SignalsTab(QtWidgets.QWidget): for iSample in range(dSamples): bit_index = nbitsPerSample * iSample for idx, i in enumerate(rx_dbitlist): - if not isPlottedArray[i]: - bit_index += 1 - bits_per_sample[iSample, idx] = 0.0 - index = int(bit_index/8) iBit = idx % 8 bit = (digital_array[index] >> iBit) & 1 @@ -154,16 +147,13 @@ class SignalsTab(QtWidgets.QWidget): waveforms = {} isPlottedArray = {i: getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in self.rx_dbitlist} - digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, isPlottedArray, + digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, self.mainWindow.romode.value, self.mainWindow.nADCEnabled) irow = 0 for idx, i in enumerate(self.rx_dbitlist): - # bits enabled but not plotting - if not isPlottedArray[i]: - continue - waveform = digital_array[i, :] + waveform = digital_array[idx, :] self.mainWindow.digitalPlots[i].setData(waveform) plotName = getattr(self.view, f"labelBIT{i}").text() waveforms[plotName] = waveform @@ -215,11 +205,11 @@ class SignalsTab(QtWidgets.QWidget): self.mainWindow.nDBitEnabled = len(list(retval)) for i in range(Defines.signals.count): self.getDigitalBitEnable(i, retval) - self.getEnableBitPlot(i) + self.EnableBitPlot(i) self.getEnableBitColor(i) self.plotTab.addSelectedDigitalPlots(i) self.getDigitalBitEnableRange(retval) - self.getEnableBitPlotRange() + self.EnableBitPlotRange() def setDigitalBitEnable(self, i): bitList = self.det.rx_dbitlist @@ -257,21 +247,27 @@ class SignalsTab(QtWidgets.QWidget): self.updateDigitalBitEnable() - def getEnableBitPlot(self, i): + def EnableBitPlot(self, i): + """ enables plot check box if bit is enabled, otherwise unchecks and disables plot check box """ + checkBox = getattr(self.view, f"checkBoxBIT{i}DB") checkBoxPlot = getattr(self.view, f"checkBoxBIT{i}Plot") + if(checkBoxPlot.isChecked()): + checkBoxPlot.setChecked(checkBox.isChecked()) + checkBoxPlot.setEnabled(checkBox.isChecked()) - def setEnableBitPlot(self, i): + def setBitPlot(self, i): + """ sets plot check box e.g. adds plots to plot tab """ pushButton = getattr(self.view, f"pushButtonBIT{i}") checkBox = getattr(self.view, f"checkBoxBIT{i}Plot") pushButton.setEnabled(checkBox.isChecked()) - self.getEnableBitPlotRange() + self.EnableBitPlotRange() self.plotTab.addSelectedDigitalPlots(i) self.updateLegend() - def getEnableBitPlotRange(self): + def EnableBitPlotRange(self): self.view.checkBoxBIT0_31Plot.stateChanged.disconnect() self.view.checkBoxBIT32_63Plot.stateChanged.disconnect() self.view.checkBoxBIT0_31Plot.setEnabled( @@ -286,12 +282,12 @@ class SignalsTab(QtWidgets.QWidget): all( getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in range(Defines.signals.half, Defines.signals.count))) - self.view.checkBoxBIT0_31Plot.stateChanged.connect(partial(self.setEnableBitPlotRange, 0, + self.view.checkBoxBIT0_31Plot.stateChanged.connect(partial(self.setBitPlotRange, 0, Defines.signals.half)) self.view.checkBoxBIT32_63Plot.stateChanged.connect( - partial(self.setEnableBitPlotRange, Defines.signals.half, Defines.signals.count)) + partial(self.setBitPlotRange, Defines.signals.half, Defines.signals.count)) - def setEnableBitPlotRange(self, start_nr, end_nr): + def setBitPlotRange(self, start_nr, end_nr): checkBox = getattr(self.view, f"checkBoxBIT{start_nr}_{end_nr - 1}Plot") enable = checkBox.isChecked() for i in range(start_nr, end_nr): From ec6a8b6d66e7498f942dbda210ff318b96a7ce4f Mon Sep 17 00:00:00 2001 From: Alice Date: Mon, 9 Feb 2026 12:42:35 +0100 Subject: [PATCH 4/5] added range update --- pyctbgui/pyctbgui/services/Signals.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pyctbgui/pyctbgui/services/Signals.py b/pyctbgui/pyctbgui/services/Signals.py index c1eec01cb..459a4bddc 100644 --- a/pyctbgui/pyctbgui/services/Signals.py +++ b/pyctbgui/pyctbgui/services/Signals.py @@ -89,6 +89,11 @@ class SignalsTab(QtWidgets.QWidget): for plot, name in self.getEnabledPlots(): self.legend.addItem(plot, name) + def updatePlotRange(self): + vb = self.mainWindow.plotDigitalWaveform.getViewBox() + vb.enableAutoRange(enable=True) # Enable auto-range + vb.updateAutoRange() # Force immediate update + @recordOrApplyPedestal def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, romode, nADCEnabled): @@ -145,7 +150,6 @@ class SignalsTab(QtWidgets.QWidget): self.refresh() waveforms = {} - isPlottedArray = {i: getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in self.rx_dbitlist} digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, self.mainWindow.romode.value, @@ -163,7 +167,9 @@ class SignalsTab(QtWidgets.QWidget): irow += 1 else: self.mainWindow.digitalPlots[i].setY(0) - + + self.updatePlotRange() # Call after all data is set + return waveforms @@ -266,6 +272,8 @@ class SignalsTab(QtWidgets.QWidget): self.EnableBitPlotRange() self.plotTab.addSelectedDigitalPlots(i) self.updateLegend() + self.updatePlotRange() + def EnableBitPlotRange(self): self.view.checkBoxBIT0_31Plot.stateChanged.disconnect() From 3f4df445f1ad4f62b15ea3a41055cbfe92d91099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=B6jdh?= Date: Mon, 9 Feb 2026 13:50:35 +0100 Subject: [PATCH 5/5] send back the result of the SPI write (#1387) --- python/src/detector.cpp | 4 ++-- .../src/slsDetectorServer_funcs.c | 15 ++++++++++----- slsDetectorSoftware/include/sls/Detector.h | 2 +- slsDetectorSoftware/src/Detector.cpp | 4 ++-- slsDetectorSoftware/src/Module.cpp | 7 ++++++- slsDetectorSoftware/src/Module.h | 2 +- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/python/src/detector.cpp b/python/src/detector.cpp index d3e6be8b3..7bad555c0 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -2206,8 +2206,8 @@ void init_det(py::module &m) { py::arg() = Positions{}); CppDetectorApi.def( "writeSpi", - (void (Detector::*)(int, int, const std::vector &, - sls::Positions)) & + (Result>(Detector::*)( + int, int, const std::vector &, sls::Positions)) & Detector::writeSpi, py::arg(), py::arg(), py::arg(), py::arg() = Positions{}); ; diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 174af28a8..49427f02f 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -11375,7 +11375,10 @@ int spi_write(int file_des){ local_tx[i+1] = data[i]; #ifdef VIRTUAL - // For the virtual detector we have nothing to do + // For the virtual detector copy the data from local_tx to local_rx + for (int i=0; i < n_bytes+1; i++){ + local_rx[i] = local_tx[i]; + } #else int spifd = open("/dev/spidev2.0", O_RDWR); LOG(logINFO, ("SPI Read: opened spidev2.0 with fd=%d\n", spifd)); @@ -11397,11 +11400,13 @@ int spi_write(int file_des){ close(spifd); #endif + ret = OK; + LOG(logDEBUG1, ("SPI Write Complete\n")); + Server_SendResult(file_des, INT32, NULL, 0); + sendData(file_des, local_rx+1, n_bytes, OTHER); + free(data); free(local_tx); free(local_rx); - - ret = OK; - LOG(logDEBUG1, ("SPI Write Complete\n")); - return Server_SendResult(file_des, INT32, NULL, 0); + return ret; } \ No newline at end of file diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 958e64dc5..fb7c32b29 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -2250,7 +2250,7 @@ class Detector { Result> readSpi(int chip_id, int register_id, int n_bytes, Positions pos = {}) const; - void writeSpi(int chip_id, int register_id, + Result> writeSpi(int chip_id, int register_id, const std::vector &data, Positions pos = {}); private: diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 1960fd858..619619e09 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -2961,9 +2961,9 @@ Result> Detector::readSpi(int chip_id, int register_id, n_bytes); } -void Detector::writeSpi(int chip_id, int register_id, +Result> Detector::writeSpi(int chip_id, int register_id, const std::vector &data, Positions pos){ - pimpl->Parallel(&Module::writeSpi, pos, chip_id, register_id, data); + return pimpl->Parallel(&Module::writeSpi, pos, chip_id, register_id, data); } diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index b0dc43211..216a491fd 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -4097,7 +4097,7 @@ std::vector Module::readSpi(int chip_id, int register_id, } -void Module::writeSpi(int chip_id, int register_id, +std::vector Module::writeSpi(int chip_id, int register_id, const std::vector &data){ auto client = DetectorSocket(shm()->hostname, shm()->controlPort); client.Send(F_SPI_WRITE); @@ -4113,6 +4113,11 @@ void Module::writeSpi(int chip_id, int register_id, << " returned error: " << client.readErrorMessage(); throw DetectorError(os.str()); } + + // Read the output from the SPI write. This contains the data before the write. + std::vector ret(data.size()); + client.Receive(ret); + return ret; } } // namespace sls diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 2e4fb5684..cc692cdef 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -610,7 +610,7 @@ class Module : public virtual slsDetectorDefs { std::vector readSpi(int chip_id, int register_id, int n_bytes) const; - void writeSpi(int chip_id, int register_id, const std::vector &data); + std::vector writeSpi(int chip_id, int register_id, const std::vector &data); private: std::string getReceiverLongVersion() const;