diff --git a/docs/src/binaryfileformat.rst b/docs/src/binaryfileformat.rst index 42b2a5657..e3657f246 100644 --- a/docs/src/binaryfileformat.rst +++ b/docs/src/binaryfileformat.rst @@ -359,6 +359,7 @@ Chip Test Board "Digital Flag": 0, "Digital Samples": 1000, "Dbit Offset": 0, + "Dbit Reorder": 1, "Dbit Bitset": 0, "Transceiver Mask": "0x3", "Transceiver Flag": 0, diff --git a/docs/src/masterfileattributes.rst b/docs/src/masterfileattributes.rst index cc1355553..5190ee647 100644 --- a/docs/src/masterfileattributes.rst +++ b/docs/src/masterfileattributes.rst @@ -345,6 +345,9 @@ Chip Test Board +-----------------------+-------------------------------------------------+ | Dbit Offset | Digital offset of valid data in bytes | +-----------------------+-------------------------------------------------+ + | Dbit Reorder | Reorder such that it groups each signal (0-63) | + | | from all the different samples together | + +-----------------------+-------------------------------------------------+ | Dbit Bitset | Digital 64 bit mask of bits enabled in receiver | +-----------------------+-------------------------------------------------+ | Transceiver Mask | Mask of channels enabled in Transceiver | diff --git a/pyctbgui/pyctbgui/services/Signals.py b/pyctbgui/pyctbgui/services/Signals.py index a06b9a412..856571e22 100644 --- a/pyctbgui/pyctbgui/services/Signals.py +++ b/pyctbgui/pyctbgui/services/Signals.py @@ -22,6 +22,7 @@ class SignalsTab(QtWidgets.QWidget): self.plotTab = None self.legend: LegendItem | None = None self.rx_dbitoffset = None + self.rx_dbitreorder = None self.rx_dbitlist = None def refresh(self): @@ -29,6 +30,7 @@ class SignalsTab(QtWidgets.QWidget): self.updateDigitalBitEnable() self.updateIOOut() self.getDBitOffset() + self.getDBitReorder() def connect_ui(self): for i in range(Defines.signals.count): @@ -49,6 +51,7 @@ class SignalsTab(QtWidgets.QWidget): partial(self.setIOOutRange, Defines.signals.half, Defines.signals.count)) self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg) self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset) + self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder) def setup_ui(self): self.plotTab = self.mainWindow.plotTab @@ -87,60 +90,79 @@ class SignalsTab(QtWidgets.QWidget): self.legend.addItem(plot, name) @recordOrApplyPedestal - def _processWaveformData(self, data, aSamples, dSamples, rx_dbitlist, isPlottedArray, rx_dbitoffset, romode, + def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, isPlottedArray, romode, nADCEnabled): - """ - transform raw waveform data into a processed numpy array - @param data: raw waveform data - """ - dbitoffset = rx_dbitoffset + + #transform raw waveform data into a processed numpy array + #@param data: raw waveform data + + start_digital_data = 0 if romode == 2: - dbitoffset += nADCEnabled * 2 * aSamples - digital_array = np.array(np.frombuffer(data, offset=dbitoffset, dtype=np.uint8)) - nbitsPerDBit = dSamples - if nbitsPerDBit % 8 != 0: - nbitsPerDBit += (8 - (dSamples % 8)) - offset = 0 - arr = [] - for i in rx_dbitlist: - # where numbits * numsamples is not a multiple of 8 - if offset % 8 != 0: - offset += (8 - (offset % 8)) - if not isPlottedArray[i]: - offset += nbitsPerDBit - return None - waveform = np.zeros(dSamples) - for iSample in range(dSamples): - # all samples for digital bit together from slsReceiver - index = int(offset / 8) - iBit = offset % 8 - bit = (digital_array[index] >> iBit) & 1 - waveform[iSample] = bit - offset += 1 - arr.append(waveform) + start_digital_data += nADCEnabled * 2 * aSamples + digital_array = np.array(np.frombuffer(data, offset=start_digital_data, dtype=np.uint8)) + if rx_dbitreorder: + samples_per_bit = np.empty((len(rx_dbitlist), dSamples), dtype=np.uint8) #stored per row all the corresponding signals of all samples + nbitsPerDBit = dSamples + if nbitsPerDBit % 8 != 0: + nbitsPerDBit += (8 - (dSamples % 8)) + bit_index = 0 + for idx, i in enumerate(rx_dbitlist): + # 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, :] = np.nan + continue + for iSample in range(dSamples): + # all samples for digital bit together from slsReceiver + index = int(bit_index / 8) + iBit = bit_index % 8 + bit = (digital_array[index] >> iBit) & 1 + samples_per_bit[idx,iSample] = bit + bit_index += 1 + return samples_per_bit + else: + nbitsPerSample = len(rx_dbitlist) if len(rx_dbitlist) % 8 == 0 else len(rx_dbitlist) + (8 - (len(rx_dbitlist) % 8)) + bits_per_sample = np.empty((dSamples, len(rx_dbitlist)), dtype=np.uint8) #store per row all selected bits of a sample + 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] = np.nan - return np.array(arr) + index = int(bit_index/8) + iBit = idx % 8 + bit = (digital_array[index] >> iBit) & 1 + bits_per_sample[iSample, idx] = bit + bit_index += 1 + return bits_per_sample.T.copy() + + def processWaveformData(self, data, aSamples, dSamples): - """ - view function - plots processed waveform data - data: raw waveform data - dsamples: digital samples - asamples: analog samples - """ + + #view function + #plots processed waveform data + #data: raw waveform data + #dsamples: digital samples + #asamples: analog samples + + 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_dbitlist, isPlottedArray, - self.rx_dbitoffset, self.mainWindow.romode.value, + digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, isPlottedArray, + self.mainWindow.romode.value, self.mainWindow.nADCEnabled) irow = 0 - for idx, i in enumerate(self.rx_dbitlist): + for idx, i in enumerate(self.rx_dbitlist): # bits enabled but not plotting - waveform = digital_array[idx] - if waveform is None: + waveform = digital_array[idx, :] + if np.isnan(waveform[0]): continue self.mainWindow.digitalPlots[i].setData(waveform) plotName = getattr(self.view, f"labelBIT{i}").text() @@ -151,8 +173,10 @@ class SignalsTab(QtWidgets.QWidget): irow += 1 else: self.mainWindow.digitalPlots[i].setY(0) + return waveforms + def initializeAllDigitalPlots(self): self.mainWindow.plotDigitalWaveform = pg.plot() self.mainWindow.plotDigitalWaveform.addLegend(colCount=Defines.colCount) @@ -360,14 +384,25 @@ class SignalsTab(QtWidgets.QWidget): self.view.spinBoxDBitOffset.setValue(self.rx_dbitoffset) self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset) + def getDBitReorder(self): + self.view.checkBoxDBitReorder.stateChanged.disconnect() + self.rx_dbitreorder = self.det.rx_dbitreorder + self.view.checkBoxDBitReorder.setChecked(self.rx_dbitreorder) + self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder) + + def setDbitOffset(self): self.det.rx_dbitoffset = self.view.spinBoxDBitOffset.value() + def setDbitReorder(self): + self.det.rx_dbitreorder = self.view.checkBoxDBitReorder.isChecked() + def saveParameters(self) -> list: commands = [] dblist = [str(i) for i in range(Defines.signals.count) if getattr(self.view, f"checkBoxBIT{i}DB").isChecked()] if len(dblist) > 0: commands.append(f"rx_dbitlist {', '.join(dblist)}") commands.append(f"rx_dbitoffset {self.view.spinBoxDBitOffset.value()}") + commands.append(f"rx_dbitreorder {self.view.checkBoxDBitReorder.isChecked()}") commands.append(f"patioctrl {self.view.lineEditPatIOCtrl.text()}") return commands diff --git a/pyctbgui/pyctbgui/ui/signals.ui b/pyctbgui/pyctbgui/ui/signals.ui index 231c0b92f..f34e357cb 100644 --- a/pyctbgui/pyctbgui/ui/signals.ui +++ b/pyctbgui/pyctbgui/ui/signals.ui @@ -6074,6 +6074,33 @@ QFrame::Raised + + + + + 150 + 32 + + + + + 150 + 32 + + + + + 10 + + + + background-color: rgb(255, 255, 255); + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + @@ -6086,6 +6113,36 @@ + + + + + 10 + + + + DBit Reorder + + + + + + + + 50 + 0 + + + + + 10 + + + + IO Control Register: + + + @@ -6133,50 +6190,18 @@ - - - + + + + Qt::Horizontal + + - 150 - 32 + 40 + 20 - - - 150 - 32 - - - - - 10 - - - - background-color: rgb(255, 255, 255); - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - 0 - - - - - 10 - - - - IO Control Register: - - + diff --git a/python/slsdet/detector.py b/python/slsdet/detector.py index 873485c88..ffcee461c 100755 --- a/python/slsdet/detector.py +++ b/python/slsdet/detector.py @@ -3463,6 +3463,16 @@ class Detector(CppDetectorApi): def rx_dbitoffset(self, value): ut.set_using_dict(self.setRxDbitOffset, value) + @property + @element + def rx_dbitreorder(self): + """[Ctb] Reorder digital data to group together all samples per signal. Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together.""" + return self.getRxDbitReorder() + + @rx_dbitreorder.setter + def rx_dbitreorder(self, value): + ut.set_using_dict(self.setRxDbitReorder, value) + @property @element def maxadcphaseshift(self): diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 2d2c224b7..5393cbf6e 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -1664,6 +1664,14 @@ void init_det(py::module &m) { (void (Detector::*)(int, sls::Positions)) & Detector::setRxDbitOffset, py::arg(), py::arg() = Positions{}); + CppDetectorApi.def("getRxDbitReorder", + (Result(Detector::*)(sls::Positions) const) & + Detector::getRxDbitReorder, + py::arg() = Positions{}); + CppDetectorApi.def("setRxDbitReorder", + (void (Detector::*)(bool, sls::Positions)) & + Detector::setRxDbitReorder, + py::arg(), py::arg() = Positions{}); CppDetectorApi.def("setDigitalIODelay", (void (Detector::*)(uint64_t, int, sls::Positions)) & Detector::setDigitalIODelay, diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index bf9773e71..d7f9e4f56 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -15,6 +15,7 @@ #include "loadPattern.h" #include +#include #include #include // usleep #ifdef VIRTUAL @@ -2258,11 +2259,23 @@ void *start_timer(void *arg) { int packetsPerFrame = ceil((double)imageSize / (double)dataSize); // Generate Data - char imageData[imageSize]; + char *imageData = (char *)malloc(imageSize); memset(imageData, 0, imageSize); + + if (imageData == NULL) { + LOG(logERROR, ("Can not allocate image Data RAM." + "Probable cause: Memory Leak.\n")); + return NULL; + } + /* for (int i = 0; i < imageSize; i += sizeof(uint16_t)) { *((uint16_t *)(imageData + i)) = i; } + */ + + for (int i = 0; i < imageSize; i += 2 * sizeof(uint64_t)) { + *((uint64_t *)(imageData + i)) = 0xffffffffffffffff; + } // Send data uint64_t frameNr = 0; @@ -2319,6 +2332,8 @@ void *start_timer(void *arg) { setNextFrameNumber(frameNr + numFrames); } + free(imageData); + closeUDPSocket(0); sharedMemory_setStatus(IDLE); diff --git a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh index 9345f192d..3ce858ee8 100644 --- a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh @@ -80,7 +80,7 @@ _sd() { local IS_PATH=0 -local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " +local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " __acquire() { FCN_RETURN="" return 0 @@ -2088,6 +2088,15 @@ fi fi return 0 } +__rx_dbitreorder() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="0 1" +fi +fi +return 0 +} __rx_discardpolicy() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then diff --git a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh index 9eaf07382..c59c1e4a3 100644 --- a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh @@ -4,7 +4,7 @@ _sd() { -local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " +local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " __acquire() { FCN_RETURN="" return 0 @@ -2012,6 +2012,15 @@ fi fi return 0 } +__rx_dbitreorder() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="0 1" +fi +fi +return 0 +} __rx_discardpolicy() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 95c4f0ca8..f33cf7be2 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -1412,6 +1412,18 @@ lock: function: setDetectorLock input_types: [ bool ] + +rx_dbitreorder: + help: "[0, 1]\n\t[Ctb] Reorder digital data such that it groups each signal (0-63) from all the different samples together . Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together." + inherit_actions: INTEGER_COMMAND_VEC_ID + actions: + GET: + function: getRxDbitReorder + PUT: + function: setRxDbitReorder + input_types: [ bool ] + + ################# INTEGER_COMMAND_VEC_ID_GET ################# master: diff --git a/slsDetectorSoftware/generator/extended_commands.yaml b/slsDetectorSoftware/generator/extended_commands.yaml index 908cc2dfb..6b9f72577 100644 --- a/slsDetectorSoftware/generator/extended_commands.yaml +++ b/slsDetectorSoftware/generator/extended_commands.yaml @@ -8305,6 +8305,48 @@ rx_dbitoffset: help: "[n_bytes]\n\t[Ctb] Offset in bytes in digital data to skip in receiver." infer_action: true template: true +rx_dbitreorder: + actions: + GET: + args: + - arg_types: [] + argc: 0 + cast_input: [] + check_det_id: false + convert_det_id: true + function: getRxDbitReorder + input: [] + input_types: [] + output: + - OutString(t) + require_det_id: true + store_result_in_t: true + PUT: + args: + - arg_types: + - bool + argc: 1 + cast_input: + - true + check_det_id: false + convert_det_id: true + function: setRxDbitReorder + input: + - args[0] + input_types: + - bool + output: + - args.front() + require_det_id: true + store_result_in_t: false + command_name: rx_dbitreorder + function_alias: rx_dbitreorder + help: "[0, 1]\n\t[Ctb] Reorder digital data such that it groups each signal (0-63)\ + \ from all the different samples together . Default is 1. Setting to 0 means 'do\ + \ not reorder' and to keep what the board spits out, which is that all signals\ + \ in a sample are grouped together." + infer_action: true + template: true rx_discardpolicy: actions: GET: diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index a58265324..eb679a578 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -1729,6 +1729,16 @@ class Detector { /** [CTB] Set number of bytes of digital data to skip in the Receiver */ void setRxDbitOffset(int value, Positions pos = {}); + /** [CTB] */ + Result getRxDbitReorder(Positions pos = {}) const; + + /** [CTB] Reorder digital data such that it groups each signal (0-63) + * from all the different samples together. + * Default is true. Setting to false means 'do not reorder' and to keep what + * the board spits out, which is that all signals in a sample are grouped + * together */ + void setRxDbitReorder(bool reorder, Positions pos = {}); + /** * [CTB] Set Digital IO Delay * cannot get diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index da761afa2..78a6f79d7 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -10700,6 +10700,68 @@ std::string Caller::rx_dbitoffset(int action) { return os.str(); } +std::string Caller::rx_dbitreorder(int action) { + + std::ostringstream os; + // print help + if (action == slsDetectorDefs::HELP_ACTION) { + os << R"V0G0N([0, 1] + [Ctb] Reorder digital data such that it groups each signal (0-63) from all the different samples together . Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together. )V0G0N" + << std::endl; + return os.str(); + } + + // check if action and arguments are valid + if (action == slsDetectorDefs::GET_ACTION) { + if (1 && args.size() != 0) { + throw RuntimeError("Wrong number of arguments for action GET"); + } + + if (args.size() == 0) { + } + + } + + else if (action == slsDetectorDefs::PUT_ACTION) { + if (1 && args.size() != 1) { + throw RuntimeError("Wrong number of arguments for action PUT"); + } + + if (args.size() == 1) { + try { + StringTo(args[0]); + } catch (...) { + throw RuntimeError("Could not convert argument 0 to bool"); + } + } + + } + + else { + + throw RuntimeError("INTERNAL ERROR: Invalid action: supported actions " + "are ['GET', 'PUT']"); + } + + // generate code for each action + if (action == slsDetectorDefs::GET_ACTION) { + if (args.size() == 0) { + auto t = det->getRxDbitReorder(std::vector{det_id}); + os << OutString(t) << '\n'; + } + } + + if (action == slsDetectorDefs::PUT_ACTION) { + if (args.size() == 1) { + auto arg0 = StringTo(args[0]); + det->setRxDbitReorder(arg0, std::vector{det_id}); + os << args.front() << '\n'; + } + } + + return os.str(); +} + std::string Caller::rx_discardpolicy(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index d7cfbdd02..3e1be13ac 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -236,6 +236,7 @@ class Caller { std::string rx_clearroi(int action); std::string rx_dbitlist(int action); std::string rx_dbitoffset(int action); + std::string rx_dbitreorder(int action); std::string rx_discardpolicy(int action); std::string rx_fifodepth(int action); std::string rx_frameindex(int action); @@ -582,6 +583,7 @@ class Caller { {"rx_clearroi", &Caller::rx_clearroi}, {"rx_dbitlist", &Caller::rx_dbitlist}, {"rx_dbitoffset", &Caller::rx_dbitoffset}, + {"rx_dbitreorder", &Caller::rx_dbitreorder}, {"rx_discardpolicy", &Caller::rx_discardpolicy}, {"rx_fifodepth", &Caller::rx_fifodepth}, {"rx_frameindex", &Caller::rx_frameindex}, diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 2e85c7c2c..f84e5fbb3 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -2277,6 +2277,14 @@ void Detector::setRxDbitOffset(int value, Positions pos) { pimpl->Parallel(&Module::setReceiverDbitOffset, pos, value); } +Result Detector::getRxDbitReorder(Positions pos) const { + return pimpl->Parallel(&Module::getReceiverDbitReorder, pos); +} + +void Detector::setRxDbitReorder(bool reorder, Positions pos) { + pimpl->Parallel(&Module::setReceiverDbitReorder, pos, reorder); +} + void Detector::setDigitalIODelay(uint64_t pinMask, int delay, Positions pos) { pimpl->Parallel(&Module::setDigitalIODelay, pos, pinMask, delay); } diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 5b535b92a..d1356c30f 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -2509,6 +2509,15 @@ void Module::setReceiverDbitOffset(int value) { sendToReceiver(F_SET_RECEIVER_DBIT_OFFSET, value, nullptr); } +bool Module::getReceiverDbitReorder() const { + return sendToReceiver(F_GET_RECEIVER_DBIT_REORDER); +} + +void Module::setReceiverDbitReorder(bool reorder) { + sendToReceiver(F_SET_RECEIVER_DBIT_REORDER, static_cast(reorder), + nullptr); +} + void Module::setDigitalIODelay(uint64_t pinMask, int delay) { uint64_t args[]{pinMask, static_cast(delay)}; sendToDetector(F_DIGITAL_IO_DELAY, args, nullptr); diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 18fbaa296..86c9e3d5f 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -510,6 +510,8 @@ class Module : public virtual slsDetectorDefs { void setReceiverDbitList(std::vector list); int getReceiverDbitOffset() const; void setReceiverDbitOffset(int value); + bool getReceiverDbitReorder() const; + void setReceiverDbitReorder(bool value); void setDigitalIODelay(uint64_t pinMask, int delay); bool getLEDEnable() const; void setLEDEnable(bool enable); diff --git a/slsDetectorSoftware/src/inferAction.cpp b/slsDetectorSoftware/src/inferAction.cpp index 56ff942cd..68c8638f1 100644 --- a/slsDetectorSoftware/src/inferAction.cpp +++ b/slsDetectorSoftware/src/inferAction.cpp @@ -2568,6 +2568,22 @@ int InferAction::rx_dbitoffset() { } } +int InferAction::rx_dbitreorder() { + + if (args.size() == 0) { + return slsDetectorDefs::GET_ACTION; + } + + if (args.size() == 1) { + return slsDetectorDefs::PUT_ACTION; + } + + else { + + throw RuntimeError("Could not infer action: Wrong number of arguments"); + } +} + int InferAction::rx_discardpolicy() { if (args.size() == 0) { diff --git a/slsDetectorSoftware/src/inferAction.h b/slsDetectorSoftware/src/inferAction.h index 35d1109ef..ffc6944d7 100644 --- a/slsDetectorSoftware/src/inferAction.h +++ b/slsDetectorSoftware/src/inferAction.h @@ -193,6 +193,7 @@ class InferAction { int rx_clearroi(); int rx_dbitlist(); int rx_dbitoffset(); + int rx_dbitreorder(); int rx_discardpolicy(); int rx_fifodepth(); int rx_frameindex(); @@ -527,6 +528,7 @@ class InferAction { {"rx_clearroi", &InferAction::rx_clearroi}, {"rx_dbitlist", &InferAction::rx_dbitlist}, {"rx_dbitoffset", &InferAction::rx_dbitoffset}, + {"rx_dbitreorder", &InferAction::rx_dbitreorder}, {"rx_discardpolicy", &InferAction::rx_discardpolicy}, {"rx_fifodepth", &InferAction::rx_fifodepth}, {"rx_frameindex", &InferAction::rx_frameindex}, diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 38fe14e86..508abc59d 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -956,6 +956,37 @@ TEST_CASE("rx_dbitoffset", "[.cmdcall][.rx]") { } } +TEST_CASE("rx_dbitreorder", "[.cmdcall][.rx]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxDbitReorder(); + { + std::ostringstream oss; + caller.call("rx_dbitreorder", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_dbitreorder 0\n"); + } + { + std::ostringstream oss; + caller.call("rx_dbitreorder", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_dbitreorder 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_dbitreorder", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_dbitreorder 1\n"); + } + REQUIRE_THROWS(caller.call("rx_dbitreorder", {"15"}, -1, PUT)); + for (int i = 0; i != det.size(); ++i) { + det.setRxDbitReorder(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_dbitreorder", {}, -1, GET)); + } +} + TEST_CASE("rx_jsonaddheader", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index a75a87d2f..f3de129b5 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -218,6 +218,8 @@ int ClientInterface::functionTable(){ flist[F_RECEIVER_SET_TRANSCEIVER_MASK] = &ClientInterface::set_transceiver_mask; flist[F_RECEIVER_SET_ROW] = &ClientInterface::set_row; flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column; + flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder; + flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_dbit_reorder; for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) { @@ -1789,4 +1791,25 @@ int ClientInterface::set_column(Interface &socket) { return socket.Send(OK); } +int ClientInterface::get_dbit_reorder(Interface &socket) { + if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD) + functionNotImplemented(); + int retval = impl()->getDbitReorder(); + LOG(logDEBUG1) << "Dbit reorder retval: " << retval; + return socket.sendResult(retval); +} + +int ClientInterface::set_dbit_reorder(Interface &socket) { + auto arg = socket.Receive(); + if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD) + functionNotImplemented(); + if (arg < 0) { + throw RuntimeError("Invalid dbit reorder: " + std::to_string(arg)); + } + verifyIdle(socket); + LOG(logDEBUG1) << "Setting Dbit reorder: " << arg; + impl()->setDbitReorder(arg); + return socket.Send(OK); +} + } // namespace sls diff --git a/slsReceiverSoftware/src/ClientInterface.h b/slsReceiverSoftware/src/ClientInterface.h index a6749e33f..665e0f396 100644 --- a/slsReceiverSoftware/src/ClientInterface.h +++ b/slsReceiverSoftware/src/ClientInterface.h @@ -164,6 +164,8 @@ class ClientInterface : private virtual slsDetectorDefs { int set_transceiver_mask(ServerInterface &socket); int set_row(ServerInterface &socket); int set_column(ServerInterface &socket); + int get_dbit_reorder(ServerInterface &socket); + int set_dbit_reorder(ServerInterface &socket); Implementation *impl() { if (receiver != nullptr) { diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index fd5f2456a..1956d3578 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -3,7 +3,7 @@ /************************************************ * @file DataProcessor.cpp * @short creates data processor thread that - * pulls pointers to memory addresses from fifos + * pulls pointers to memory addresses from fifos * and processes data stored in them & writes them to file ***********************************************/ @@ -23,6 +23,7 @@ #include #include #include +#include namespace sls { @@ -77,6 +78,8 @@ void DataProcessor::SetCtbDbitList(std::vector value) { void DataProcessor::SetCtbDbitOffset(int value) { ctbDbitOffset = value; } +void DataProcessor::SetCtbDbitReorder(bool value) { ctbDbitReorder = value; } + void DataProcessor::SetQuadEnable(bool value) { quadEnable = value; } void DataProcessor::SetFlipRows(bool fd) { @@ -213,8 +216,9 @@ std::string DataProcessor::CreateVirtualFile( "Skipping virtual hdf5 file since rx_roi is enabled."); } - bool gotthard25um = - (generalData->detType == GOTTHARD2 && (numModX * numModY) == 2); + bool gotthard25um = ((generalData->detType == GOTTHARD || + generalData->detType == GOTTHARD2) && + (numModX * numModY) == 2); // 0 for infinite files uint32_t framesPerFile = @@ -332,6 +336,7 @@ void DataProcessor::StopProcessing(char *buf) { void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size, size_t &firstImageIndex, char *data) { + uint64_t fnum = header.detHeader.frameNumber; LOG(logDEBUG1) << "DataProcessing " << index << ": fnum:" << fnum; currentFrameIndex = fnum; @@ -355,9 +360,15 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size, if (framePadding && nump < generalData->packetsPerFrame) PadMissingPackets(header, data); - // rearrange ctb digital bits (if ctbDbitlist is not empty) + // rearrange ctb digital bits if (!ctbDbitList.empty()) { - RearrangeDbitData(size, data); + ArrangeDbitData(size, data); + } else if (ctbDbitReorder) { + ctbDbitList.resize(64); + std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0); + ArrangeDbitData(size, data); + } else if (ctbDbitOffset > 0) { + RemoveTrailingBits(size, data); } // 'stream Image' check has to be done here before crop image @@ -519,11 +530,48 @@ void DataProcessor::PadMissingPackets(sls_receiver_header header, char *data) { } } +void DataProcessor::RemoveTrailingBits(size_t &size, char *data) { + + if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD || + generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) { + throw std::runtime_error("behavior undefined for detector " + + std::to_string(generalData->detType)); + } + + const size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes(); + const size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes(); + const size_t nTransceiverDataBytes = + generalData->GetNumberOfTransceiverDatabytes(); + + const size_t ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset; + + // no digital data + if (ctbDigitalDataBytes == 0) { + LOG(logWARNING) + << "No digital data for call back, yet ctbDbitOffset is non zero."; + return; + } + + // update size and copy data + memmove(data + nAnalogDataBytes, data + nAnalogDataBytes + ctbDbitOffset, + ctbDigitalDataBytes + nTransceiverDataBytes); + + size = nAnalogDataBytes + ctbDigitalDataBytes + nTransceiverDataBytes; +} + /** ctb specific */ -void DataProcessor::RearrangeDbitData(size_t &size, char *data) { - int nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes(); - int nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes(); - int nTransceiverDataBytes = generalData->GetNumberOfTransceiverDatabytes(); +void DataProcessor::ArrangeDbitData(size_t &size, char *data) { + + if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD || + generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) { + throw std::runtime_error("behavior undefined for detector " + + std::to_string(generalData->detType)); + } + + size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes(); + size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes(); + size_t nTransceiverDataBytes = + generalData->GetNumberOfTransceiverDatabytes(); // TODO! (Erik) Refactor and add tests int ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset; @@ -534,47 +582,101 @@ void DataProcessor::RearrangeDbitData(size_t &size, char *data) { return; } + char *source = (data + nAnalogDataBytes + ctbDbitOffset); + const int numDigitalSamples = (ctbDigitalDataBytes / sizeof(uint64_t)); - // const int numResult8Bits = ceil((numDigitalSamples * ctbDbitList.size()) - // / 8.00); - int numBitsPerDbit = numDigitalSamples; - if ((numBitsPerDbit % 8) != 0) - numBitsPerDbit += (8 - (numDigitalSamples % 8)); - const int totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size(); - std::vector result(totalNumBytes); + int totalNumBytes = + 0; // number of bytes for selected digital data given by dtbDbitList + + // store each selected bit from all samples consecutively + if (ctbDbitReorder) { + size_t numBitsPerDbit = + numDigitalSamples; // num bits per selected digital + // Bit for all samples + if ((numBitsPerDbit % 8) != 0) + numBitsPerDbit += (8 - (numDigitalSamples % 8)); + totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size(); + } + // store all selected bits from one sample consecutively + else { + size_t numBitsPerSample = + ctbDbitList.size(); // num bits for all selected bits per sample + if ((numBitsPerSample % 8) != 0) + numBitsPerSample += (8 - (numBitsPerSample % 8)); + totalNumBytes = (numBitsPerSample / 8) * numDigitalSamples; + } + + std::vector result(totalNumBytes, 0); uint8_t *dest = &result[0]; - auto *source = (uint64_t *)(data + nAnalogDataBytes + ctbDbitOffset); - - // loop through digital bit enable vector - int bitoffset = 0; - for (auto bi : ctbDbitList) { - // where numbits * numDigitalSamples is not a multiple of 8 - if (bitoffset != 0) { - bitoffset = 0; - ++dest; - } - - // loop through the frame digital data - for (auto *ptr = source; ptr < (source + numDigitalSamples);) { - // get selected bit from each 8 bit - uint8_t bit = (*ptr++ >> bi) & 1; - *dest |= bit << bitoffset; - ++bitoffset; - // extract destination in 8 bit batches - if (bitoffset == 8) { + if (ctbDbitReorder) { + // loop through digital bit enable vector + int bitoffset = 0; + for (auto bi : ctbDbitList) { + // where numbits * numDigitalSamples is not a multiple of 8 + if (bitoffset != 0) { bitoffset = 0; ++dest; } + + uint8_t byte_index = bi / 8; + + // loop through the frame digital data + for (auto *ptr = source + byte_index; + ptr < (source + 8 * numDigitalSamples); ptr += 8) { + // get selected bit from each 8 bit + uint8_t bit = (*ptr >> bi % 8) & 1; + *dest |= bit << bitoffset; // stored as least significant + ++bitoffset; + // extract destination in 8 bit batches + if (bitoffset == 8) { + bitoffset = 0; + ++dest; + } + } + } + } else { + // loop through the digital data + int bitoffset = 0; + for (auto *ptr = source; ptr < (source + 8 * numDigitalSamples); + ptr += 8) { + // where bit enable vector size is not a multiple of 8 + if (bitoffset != 0) { + bitoffset = 0; + ++dest; + } + + // loop through digital bit enable vector + for (auto bi : ctbDbitList) { + // get selected bit from each 64 bit + uint8_t byte_index = bi / 8; + + uint8_t bit = (*(ptr + byte_index) >> (bi % 8)) & 1; + *dest |= bit << bitoffset; + ++bitoffset; + // extract destination in 8 bit batches + if (bitoffset == 8) { + bitoffset = 0; + ++dest; + } + } } } + size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes + + nTransceiverDataBytes; + + // check if size changed, if so move transceiver data to avoid gap in memory + if (size != nAnalogDataBytes + nDigitalDataBytes + nTransceiverDataBytes) + memmove(data + nAnalogDataBytes + totalNumBytes * sizeof(uint8_t), + data + nAnalogDataBytes + nDigitalDataBytes, + nTransceiverDataBytes); + // copy back to memory and update size memcpy(data + nAnalogDataBytes, result.data(), totalNumBytes * sizeof(uint8_t)); - size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes + ctbDbitOffset + - nTransceiverDataBytes; + LOG(logDEBUG1) << "totalNumBytes: " << totalNumBytes << " nAnalogDataBytes:" << nAnalogDataBytes << " ctbDbitOffset:" << ctbDbitOffset diff --git a/slsReceiverSoftware/src/DataProcessor.h b/slsReceiverSoftware/src/DataProcessor.h index 29ea9e84c..16778ec23 100644 --- a/slsReceiverSoftware/src/DataProcessor.h +++ b/slsReceiverSoftware/src/DataProcessor.h @@ -47,6 +47,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { void SetFramePadding(bool enable); void SetCtbDbitList(std::vector value); void SetCtbDbitOffset(int value); + void SetCtbDbitReorder(bool value); void SetQuadEnable(bool value); void SetFlipRows(bool fd); void SetNumberofTotalFrames(uint64_t value); @@ -91,6 +92,20 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { size_t &, void *), void *arg); + protected: + /** + * Align corresponding digital bits together (CTB only if ctbDbitlist is not + * empty) + * set variable reorder to true if data should be rearranged such that + * it groups each signal (0-63) from all the different samples together + */ + void ArrangeDbitData(size_t &size, char *data); + + /** + * remove trailing bits in digital data stream + */ + void RemoveTrailingBits(size_t &size, char *data); + private: void RecordFirstIndex(uint64_t fnum); @@ -137,12 +152,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { void PadMissingPackets(sls_receiver_header header, char *data); - /** - * Align corresponding digital bits together (CTB only if ctbDbitlist is not - * empty) - */ - void RearrangeDbitData(size_t &size, char *data); - void CropImage(size_t &size, char *data); static const std::string typeName; @@ -164,8 +173,9 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { uint32_t currentFreqCount{0}; struct timespec timerbegin {}; bool framePadding; - std::vector ctbDbitList; - int ctbDbitOffset; + std::vector ctbDbitList{}; + int ctbDbitOffset{0}; + bool ctbDbitReorder{true}; std::atomic startedFlag{false}; std::atomic firstIndex{0}; bool quadEnable{false}; diff --git a/slsReceiverSoftware/src/GeneralData.h b/slsReceiverSoftware/src/GeneralData.h index 0425815a3..17a4ea7e5 100644 --- a/slsReceiverSoftware/src/GeneralData.h +++ b/slsReceiverSoftware/src/GeneralData.h @@ -60,8 +60,8 @@ class GeneralData { slsDetectorDefs::frameDiscardPolicy frameDiscardMode{ slsDetectorDefs::NO_DISCARD}; - GeneralData(){}; - virtual ~GeneralData(){}; + GeneralData() {}; + virtual ~GeneralData() {}; // Returns the pixel depth in byte, 4 bits being 0.5 byte float GetPixelDepth() { return float(dynamicRange) / 8; } @@ -443,6 +443,7 @@ class ChipTestBoardData : public GeneralData { nDigitalBytes = 0; nTransceiverBytes = 0; int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0; + uint64_t digital_bytes_reserved = 0; // analog channels (normal, analog/digital readout) if (readoutType == slsDetectorDefs::ANALOG_ONLY || @@ -461,7 +462,12 @@ class ChipTestBoardData : public GeneralData { readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL || readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) { nDigitalChans = NCHAN_DIGITAL; - nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples); + // allocate enough memory to support reordering of digital bits + uint32_t num_bytes_per_bit = (nDigitalSamples % 8 == 0) + ? nDigitalSamples / 8 + : nDigitalSamples / 8 + 1; + digital_bytes_reserved = 64 * num_bytes_per_bit; + nDigitalBytes = sizeof(uint64_t) * nDigitalSamples; LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans << " Databytes: " << nDigitalBytes; } @@ -480,7 +486,7 @@ class ChipTestBoardData : public GeneralData { nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans; dataSize = tengigaEnable ? 8144 : UDP_PACKET_DATA_BYTES; packetSize = headerSizeinPacket + dataSize; - imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes; + imageSize = nAnalogBytes + digital_bytes_reserved + nTransceiverBytes; packetsPerFrame = ceil((double)imageSize / (double)dataSize); LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX @@ -563,6 +569,7 @@ class XilinxChipTestBoardData : public GeneralData { nDigitalBytes = 0; nTransceiverBytes = 0; int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0; + uint64_t digital_bytes_reserved = 0; // analog channels (normal, analog/digital readout) if (readoutType == slsDetectorDefs::ANALOG_ONLY || @@ -580,7 +587,11 @@ class XilinxChipTestBoardData : public GeneralData { readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL || readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) { nDigitalChans = NCHAN_DIGITAL; - nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples); + uint32_t num_bytes_per_bit = (nDigitalSamples % 8 == 0) + ? nDigitalSamples / 8 + : nDigitalSamples / 8 + 1; + digital_bytes_reserved = 64 * num_bytes_per_bit; + nDigitalBytes = sizeof(uint64_t) * nDigitalSamples; LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans << " Databytes: " << nDigitalBytes; } @@ -598,7 +609,7 @@ class XilinxChipTestBoardData : public GeneralData { } nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans; - imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes; + imageSize = nAnalogBytes + digital_bytes_reserved + nTransceiverBytes; packetsPerFrame = ceil((double)imageSize / (double)dataSize); LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 8104e8c7a..e4385d9c0 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -202,6 +202,7 @@ void Implementation::SetupDataProcessor(int i) { dataProcessor[i]->SetFramePadding(framePadding); dataProcessor[i]->SetCtbDbitList(ctbDbitList); dataProcessor[i]->SetCtbDbitOffset(ctbDbitOffset); + dataProcessor[i]->SetCtbDbitReorder(ctbDbitReorder); dataProcessor[i]->SetQuadEnable(quadEnable); dataProcessor[i]->SetFlipRows(flipRows); dataProcessor[i]->SetNumberofTotalFrames(numberOfTotalFrames); @@ -991,7 +992,9 @@ void Implementation::StartMasterWriter() { : 0; masterAttributes.digitalSamples = generalData->nDigitalSamples; masterAttributes.dbitoffset = ctbDbitOffset; + masterAttributes.dbitreorder = ctbDbitReorder; masterAttributes.dbitlist = 0; + for (auto &i : ctbDbitList) { masterAttributes.dbitlist |= (static_cast(1) << i); } @@ -1766,6 +1769,15 @@ void Implementation::setDbitOffset(const int s) { LOG(logINFO) << "Dbit offset: " << ctbDbitOffset; } +bool Implementation::getDbitReorder() const { return ctbDbitReorder; } + +void Implementation::setDbitReorder(const bool reorder) { + ctbDbitReorder = reorder; + for (const auto &it : dataProcessor) + it->SetCtbDbitReorder(ctbDbitReorder); + LOG(logINFO) << "Dbit reorder: " << ctbDbitReorder; +} + uint32_t Implementation::getTransceiverEnableMask() const { return generalData->transceiverMask; } diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 70ceb4a54..79baa670b 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -252,6 +252,10 @@ class Implementation : private virtual slsDetectorDefs { int getDbitOffset() const; /* [Ctb] */ void setDbitOffset(const int s); + bool getDbitReorder() const; + /* [Ctb] */ + void setDbitReorder(const bool reorder); + uint32_t getTransceiverEnableMask() const; /* [Ctb] */ void setTransceiverEnableMask(const uint32_t mask); @@ -368,6 +372,7 @@ class Implementation : private virtual slsDetectorDefs { std::vector rateCorrections; std::vector ctbDbitList; int ctbDbitOffset{0}; + bool ctbDbitReorder{true}; // callbacks void (*startAcquisitionCallBack)(const startCallbackHeader, diff --git a/slsReceiverSoftware/src/MasterAttributes.cpp b/slsReceiverSoftware/src/MasterAttributes.cpp index dd85a0381..8420e31ad 100644 --- a/slsReceiverSoftware/src/MasterAttributes.cpp +++ b/slsReceiverSoftware/src/MasterAttributes.cpp @@ -551,6 +551,13 @@ void MasterAttributes::WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group) { dataset.write(&dbitoffset, H5::PredType::NATIVE_INT); } +void MasterAttributes::WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group) { + H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); + H5::DataSet dataset = group->createDataSet( + "Dbit Reorder", H5::PredType::NATIVE_INT, dataspace); + dataset.write(&dbitreorder, H5::PredType::NATIVE_INT); +} + void MasterAttributes::WriteHDF5DbitList(H5::H5File *fd, H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( @@ -744,6 +751,8 @@ void MasterAttributes::GetCtbBinaryAttributes( w->Uint(digitalSamples); w->Key("Dbit Offset"); w->Uint(dbitoffset); + w->Key("Dbit Reorder"); + w->Uint(dbitreorder); w->Key("Dbit Bitset"); w->Uint64(dbitlist); w->Key("Transceiver Mask"); @@ -766,6 +775,7 @@ void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd, MasterAttributes::WriteHDF5DigitalFlag(fd, group); MasterAttributes::WriteHDF5DigitalSamples(fd, group); MasterAttributes::WriteHDF5DbitOffset(fd, group); + MasterAttributes::WriteHDF5DbitReorder(fd, group); MasterAttributes::WriteHDF5DbitList(fd, group); MasterAttributes::WriteHDF5TransceiverMask(fd, group); MasterAttributes::WriteHDF5TransceiverFlag(fd, group); @@ -791,6 +801,8 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes( w->Uint(digitalSamples); w->Key("Dbit Offset"); w->Uint(dbitoffset); + w->Key("Dbit Reorder"); + w->Uint(dbitreorder); w->Key("Dbit Bitset"); w->Uint64(dbitlist); w->Key("Transceiver Mask"); @@ -812,6 +824,7 @@ void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd, MasterAttributes::WriteHDF5DigitalFlag(fd, group); MasterAttributes::WriteHDF5DigitalSamples(fd, group); MasterAttributes::WriteHDF5DbitOffset(fd, group); + MasterAttributes::WriteHDF5DbitReorder(fd, group); MasterAttributes::WriteHDF5DbitList(fd, group); MasterAttributes::WriteHDF5TransceiverMask(fd, group); MasterAttributes::WriteHDF5TransceiverFlag(fd, group); diff --git a/slsReceiverSoftware/src/MasterAttributes.h b/slsReceiverSoftware/src/MasterAttributes.h index 015c632c4..0e3c168ae 100644 --- a/slsReceiverSoftware/src/MasterAttributes.h +++ b/slsReceiverSoftware/src/MasterAttributes.h @@ -51,6 +51,7 @@ class MasterAttributes { uint32_t analogSamples{0}; uint32_t digital{0}; uint32_t digitalSamples{0}; + uint32_t dbitreorder{1}; uint32_t dbitoffset{0}; uint64_t dbitlist{0}; uint32_t transceiverMask{0}; @@ -104,6 +105,7 @@ class MasterAttributes { void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group); void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group); void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group); + void WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group); void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group); void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group); void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group); diff --git a/slsReceiverSoftware/src/receiver_defs.h b/slsReceiverSoftware/src/receiver_defs.h index ba9697706..ade363e79 100644 --- a/slsReceiverSoftware/src/receiver_defs.h +++ b/slsReceiverSoftware/src/receiver_defs.h @@ -19,8 +19,8 @@ namespace sls { // files // versions -#define HDF5_WRITER_VERSION (6.6) // 1 decimal places -#define BINARY_WRITER_VERSION (7.2) // 1 decimal places +#define HDF5_WRITER_VERSION (6.7) // 1 decimal places +#define BINARY_WRITER_VERSION (7.3) // 1 decimal places #define MAX_FRAMES_PER_FILE 20000 #define SHORT_MAX_FRAMES_PER_FILE 100000 diff --git a/slsReceiverSoftware/tests/CMakeLists.txt b/slsReceiverSoftware/tests/CMakeLists.txt index e656b51ad..9a9455408 100755 --- a/slsReceiverSoftware/tests/CMakeLists.txt +++ b/slsReceiverSoftware/tests/CMakeLists.txt @@ -3,6 +3,9 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp ) target_include_directories(tests PUBLIC "$") + +message(STATUS "Resolved path: ${CMAKE_CURRENT_SOURCE_DIR}/../src") \ No newline at end of file diff --git a/slsReceiverSoftware/tests/test-ArrangeDataBasedOnBitList.cpp b/slsReceiverSoftware/tests/test-ArrangeDataBasedOnBitList.cpp new file mode 100644 index 000000000..f65ff3e80 --- /dev/null +++ b/slsReceiverSoftware/tests/test-ArrangeDataBasedOnBitList.cpp @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2025 Contributors to the SLS Detector Package +/************************************************ + * @file test-ArrangeDataBasedOnBitList.cpp + * @short test case for DataProcessor rearrange functions, + ***********************************************/ + +#include "DataProcessor.h" +#include "GeneralData.h" +#include "catch.hpp" +#include + +namespace sls { + +// dummy GeneralData class for testing +class GeneralDataTest : public GeneralData { + + public: + GeneralDataTest() { detType = slsDetectorDefs::CHIPTESTBOARD; } + + int GetNumberOfAnalogDatabytes() { return nAnalogBytes; }; + + int GetNumberOfDigitalDatabytes() { return nDigitalBytes; }; + + int GetNumberOfTransceiverDatabytes() { return nTransceiverBytes; }; + + void SetNumberOfAnalogDatabytes(int value) { nAnalogBytes = value; } + + void SetNumberOfDigitalDatabytes(int value) { nDigitalBytes = value; } + + void SetNumberOfTransceiverDatabytes(int value) { + nTransceiverBytes = value; + } + + private: + int nAnalogBytes; + int nDigitalBytes; + int nTransceiverBytes; +}; + +// dummy DataProcessor class for testing +class DataProcessorTest : public DataProcessor { + public: + DataProcessorTest() : DataProcessor(0){}; + ~DataProcessorTest(){}; + void ArrangeDbitData(size_t &size, char *data) { + DataProcessor::ArrangeDbitData(size, data); + } + + void RemoveTrailingBits(size_t &size, char *data) { + DataProcessor::RemoveTrailingBits(size, data); + } +}; + +/** + * test fixture for Testing, + * num_analog_bytes = 1 byte has a value of 125 + * num_transceiver_bytes = 2 both bytes have a value of 125 + * num_digital_bytes is variable and is defined by number of samples + * default num sample is 5 + * all bytes in digital data take a value of 255 + */ +class DataProcessorTestFixture { + public: + DataProcessorTestFixture() { + // setup Test Fixture + dataprocessor = new DataProcessorTest; + generaldata = new GeneralDataTest; + + // set_num_samples(num_samples); + + generaldata->SetNumberOfAnalogDatabytes(num_analog_bytes); + generaldata->SetNumberOfTransceiverDatabytes(num_transceiver_bytes); + generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes + + num_random_offset_bytes); + + dataprocessor->SetGeneralData(generaldata); + } + + ~DataProcessorTestFixture() { + delete[] data; + delete dataprocessor; + delete generaldata; + } + + size_t get_size() const { + return num_analog_bytes + num_digital_bytes + num_transceiver_bytes + + num_random_offset_bytes; + } + + void set_num_samples(const size_t value) { + num_samples = value; + num_digital_bytes = num_samples * 8; // 64 (8 bytes) per sample + + generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes + + num_random_offset_bytes); + } + + void set_random_offset_bytes(const size_t value) { + num_random_offset_bytes = value; + generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes + + num_random_offset_bytes); + } + + void set_data() { + delete[] data; + uint64_t max_bytes_per_bit = + num_samples % 8 == 0 ? num_samples / 8 : num_samples / 8 + 1; + uint64_t reserved_size = + get_size() - num_digital_bytes + max_bytes_per_bit * 64; + data = new char[reserved_size]; + + // set testing data + memset(data, dummy_value, num_analog_bytes); // set to dummy value + memset(data + num_analog_bytes, 0, + num_random_offset_bytes); // set to zero + memset(data + num_analog_bytes + num_random_offset_bytes, 0xFF, + num_digital_bytes); // all digital bits are one + memset(data + num_digital_bytes + num_analog_bytes + + num_random_offset_bytes, + dummy_value, + num_transceiver_bytes); // set to dummy value + } + + DataProcessorTest *dataprocessor; + GeneralDataTest *generaldata; + const size_t num_analog_bytes = 1; + const size_t num_transceiver_bytes = 2; + const char dummy_value = static_cast(125); + size_t num_digital_bytes = 40; // num_samples * 8 = 5 * 8 = 40 + size_t num_random_offset_bytes = 0; + size_t num_samples = 5; + char *data = nullptr; +}; + +TEST_CASE_METHOD(DataProcessorTestFixture, "Remove Trailing Bits", + "[.dataprocessor][.bitoffset]") { + + const size_t num_random_offset_bytes = 3; + set_random_offset_bytes(num_random_offset_bytes); + set_data(); + + dataprocessor->SetCtbDbitOffset(num_random_offset_bytes); + + size_t expected_size = get_size() - num_random_offset_bytes; + + char *expected_data = new char[expected_size]; + memset(expected_data, dummy_value, num_analog_bytes); // set to 125 + memset(expected_data + num_analog_bytes, 0xFF, + num_digital_bytes); // set to 1 + memset(expected_data + num_digital_bytes + num_analog_bytes, dummy_value, + num_transceiver_bytes); // set to 125 + + size_t size = get_size(); + dataprocessor->RemoveTrailingBits(size, data); + + CHECK(size == expected_size); + + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +// parametric test tested with num_samples = 5, num_samples = 10, num_samples = +// 8 +TEST_CASE_METHOD(DataProcessorTestFixture, "Reorder all", + "[.dataprocessor][.reorder]") { + // parameters: num_samples, expected_num_digital_bytes, + // expected_digital_part + auto parameters = GENERATE( + std::make_tuple(5, 64, std::vector{0b00011111}), + std::make_tuple(10, 2 * 64, std::vector{0xFF, 0b00000011}), + std::make_tuple(8, 64, std::vector{0xFF})); + + size_t num_samples, expected_num_digital_bytes; + std::vector expected_digital_part; + std::tie(num_samples, expected_num_digital_bytes, expected_digital_part) = + parameters; + + // set number of samples for test fixture -> create data + set_num_samples(num_samples); + set_data(); + + std::vector bitlist(64); + std::iota(bitlist.begin(), bitlist.end(), 0); + dataprocessor->SetCtbDbitList(bitlist); + dataprocessor->SetCtbDbitReorder(true); // set reorder to true + + const size_t expected_size = + num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes; + + // create expected data + char *expected_data = new char[expected_size]; + + memset(expected_data, dummy_value, num_analog_bytes); // set to 125 + for (size_t bit = 0; bit < 64; ++bit) { + memcpy(expected_data + num_analog_bytes + + expected_digital_part.size() * bit, + expected_digital_part.data(), expected_digital_part.size()); + } + memset(expected_data + expected_num_digital_bytes + num_analog_bytes, + dummy_value, + num_transceiver_bytes); // set to 125 + + size_t size = get_size(); + dataprocessor->ArrangeDbitData(size, data); // call reorder + + CHECK(size == expected_size); + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +TEST_CASE_METHOD(DataProcessorTestFixture, + "Reorder all and remove trailing bits", + "[.dataprocessor][.reorder]") { + + // set number of samples for test fixture -> create data + const size_t num_random_offset_bytes = 3; + set_random_offset_bytes(num_random_offset_bytes); + set_data(); + + std::vector bitlist(64); + std::iota(bitlist.begin(), bitlist.end(), 0); + dataprocessor->SetCtbDbitList(bitlist); + dataprocessor->SetCtbDbitOffset(num_random_offset_bytes); + dataprocessor->SetCtbDbitReorder(true); // set reorder to true + + const size_t expected_num_digital_bytes = 64; + std::vector expected_digital_part{0b00011111}; + + const size_t expected_size = + num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes; + + // create expected data + char *expected_data = new char[expected_size]; + + memset(expected_data, dummy_value, num_analog_bytes); // set to 125 + for (size_t bit = 0; bit < 64; ++bit) { + memcpy(expected_data + num_analog_bytes + + expected_digital_part.size() * bit, + expected_digital_part.data(), expected_digital_part.size()); + } + memset(expected_data + expected_num_digital_bytes + num_analog_bytes, + dummy_value, + num_transceiver_bytes); // set to 125 + + size_t size = get_size(); + dataprocessor->ArrangeDbitData(size, data); // call reorder + + CHECK(size == expected_size); + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder false", + "[.dataprocessor][.retrievebitlist]") { + // parameters: num_samples, bitlist, expected_num_digital_bytes, + // expected_digital_part + auto parameters = GENERATE( + std::make_tuple(5, std::vector{1, 4, 5}, 5, + std::vector{0b00000111}), + std::make_tuple(5, std::vector{1, 5, 3, 7, 8, 50, 42, 60, 39}, 10, + std::vector{0xFF, 0b00000001}), + std::make_tuple(5, std::vector{1, 5, 3, 7, 8, 50, 42, 60}, 5, + std::vector{0xFF})); + + size_t num_samples, expected_num_digital_bytes; + std::vector expected_digital_part; + std::vector bitlist; + std::tie(num_samples, bitlist, expected_num_digital_bytes, + expected_digital_part) = parameters; + + dataprocessor->SetCtbDbitList(bitlist); + + dataprocessor->SetCtbDbitReorder(false); + + set_num_samples(num_samples); + set_data(); + + size_t expected_size = + num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes; + + // create expected data + char *expected_data = new char[expected_size]; + + memset(expected_data, dummy_value, num_analog_bytes); + + for (size_t sample = 0; sample < num_samples; ++sample) { + memcpy(expected_data + num_analog_bytes + + expected_digital_part.size() * sample, + expected_digital_part.data(), expected_digital_part.size()); + } + + memset(expected_data + expected_num_digital_bytes + num_analog_bytes, + dummy_value, num_transceiver_bytes); + + size_t size = get_size(); + dataprocessor->ArrangeDbitData(size, data); + + CHECK(size == expected_size); + + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true", + "[.dataprocessor][.retrievebitlist]") { + // parameters: num_samples, bitlist, expected_num_digital_bytes, + // expected_digital_part + auto parameters = GENERATE( + std::make_tuple(5, std::vector{1, 4, 5}, 3, + std::vector{0b00011111}), + std::make_tuple(10, std::vector{1, 4, 5}, 6, + std::vector{0xFF, 0b00000011}), + std::make_tuple(8, std::vector{1, 5, 3, 7, 8, 50, 42, 60, 39}, 9, + std::vector{0xFF})); + + size_t num_samples, expected_num_digital_bytes; + std::vector expected_digital_part; + std::vector bitlist; + std::tie(num_samples, bitlist, expected_num_digital_bytes, + expected_digital_part) = parameters; + + dataprocessor->SetCtbDbitList(bitlist); + + dataprocessor->SetCtbDbitReorder(true); + + set_num_samples(num_samples); + set_data(); + + size_t expected_size = + num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes; + + // create expected data + char *expected_data = new char[expected_size]; + + memset(expected_data, dummy_value, num_analog_bytes); + + for (size_t sample = 0; sample < bitlist.size(); ++sample) { + memcpy(expected_data + num_analog_bytes + + expected_digital_part.size() * sample, + expected_digital_part.data(), expected_digital_part.size()); + } + + memset(expected_data + expected_num_digital_bytes + num_analog_bytes, + dummy_value, num_transceiver_bytes); + + size_t size = get_size(); + dataprocessor->ArrangeDbitData(size, data); + + CHECK(size == expected_size); + + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +TEST_CASE_METHOD(DataProcessorTestFixture, + "Arrange bitlist and remove trailing bits", + "[.dataprocessor][.retrievebitlist]") { + + size_t num_random_offset_bytes = 3; + std::vector bitlist{1, 4, 5}; + + set_random_offset_bytes(num_random_offset_bytes); + set_data(); + + dataprocessor->SetCtbDbitList(bitlist); + + dataprocessor->SetCtbDbitReorder(false); + + dataprocessor->SetCtbDbitOffset(num_random_offset_bytes); + + std::vector expected_digital_part{0b00000111}; + const size_t expected_num_digital_bytes = 5; + + size_t expected_size = + num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes; + + // create expected data + char *expected_data = new char[expected_size]; + + memset(expected_data, dummy_value, num_analog_bytes); + + for (size_t sample = 0; sample < num_samples; ++sample) { + memcpy(expected_data + num_analog_bytes + + expected_digital_part.size() * sample, + expected_digital_part.data(), expected_digital_part.size()); + } + + memset(expected_data + expected_num_digital_bytes + num_analog_bytes, + dummy_value, num_transceiver_bytes); + + size_t size = get_size(); + dataprocessor->ArrangeDbitData(size, data); + + CHECK(size == expected_size); + + CHECK(memcmp(data, expected_data, expected_size) == 0); + + delete[] expected_data; +} + +} // namespace sls diff --git a/slsSupportLib/include/sls/sls_detector_funcs.h b/slsSupportLib/include/sls/sls_detector_funcs.h index 8a7ef3508..ec1c6d2f1 100755 --- a/slsSupportLib/include/sls/sls_detector_funcs.h +++ b/slsSupportLib/include/sls/sls_detector_funcs.h @@ -410,6 +410,8 @@ enum detFuncs { F_RECEIVER_SET_TRANSCEIVER_MASK, F_RECEIVER_SET_ROW, F_RECEIVER_SET_COLUMN, + F_GET_RECEIVER_DBIT_REORDER, + F_SET_RECEIVER_DBIT_REORDER, NUM_REC_FUNCTIONS }; @@ -816,7 +818,8 @@ const char* getFunctionNameFromEnum(enum detFuncs func) { case F_RECEIVER_SET_TRANSCEIVER_MASK: return "F_RECEIVER_SET_TRANSCEIVER_MASK"; case F_RECEIVER_SET_ROW: return "F_RECEIVER_SET_ROW"; case F_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN"; - + case F_GET_RECEIVER_DBIT_REORDER: return "F_GET_RECEIVER_DBIT_REORDER"; + case F_SET_RECEIVER_DBIT_REORDER: return "F_SET_RECEIVER_DBIT_REORDER"; case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS"; default: return "Unknown Function";