Merge branch 'developer' into jf_h5reader

This commit is contained in:
hinger_v 2024-10-11 17:15:33 +02:00
commit f3a3fb09bf
201 changed files with 62621 additions and 30645 deletions

View File

@ -148,7 +148,6 @@ set(SLS_INTERNAL_QWT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/qwt-6.1.5)
set(ClangFormat_EXCLUDE_PATTERNS "build/"
"libs/"
"slsDetectorCalibration/"
"ctbGui/"
"manual/"
"python/"
"sample/"
@ -318,7 +317,7 @@ if (SLS_USE_PYTHON)
endif(SLS_USE_PYTHON)
if (SLS_USE_CTBGUI)
add_subdirectory(ctbGui)
add_subdirectory(pyctbgui)
endif(SLS_USE_CTBGUI)
configure_file( .clang-tidy

View File

@ -1,90 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
find_package(ROOT CONFIG REQUIRED COMPONENTS Core Gui)
find_package(TIFF REQUIRED)
target_include_directories(ROOT::Core INTERFACE "${ROOT_INCLUDE_DIRS}")
add_library(ROOT::Flags_CXX IMPORTED INTERFACE)
separate_arguments(ROOT_CXX_FLAGS)
target_compile_options(ROOT::Flags_CXX INTERFACE ${ROOT_CXX_FLAGS})
separate_arguments(ROOT_DEFINITIONS)
target_compile_definitions(ROOT::Flags_CXX INTERFACE ${ROOT_DEFINITIONS})
# This fixes a bug in the linker flags
string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
separate_arguments(ROOT_EXE_LINKER_FLAGS)
# Stuck into using old property method due to separate -L and -l arguments
# (A full path to -l is better!)
set_property(TARGET ROOT::Flags_CXX PROPERTY
INTERFACE_LINK_LIBRARIES ${ROOT_EXE_LINKER_FLAGS})
set_property(TARGET ROOT::Core PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${ROOT_INCLUDE_DIRS}")
add_executable(ctbGui
ctbGui.cpp
ctbMain.cpp
ctbDacs.cpp
ctbPowers.cpp
ctbSlowAdcs.cpp
ctbSignals.cpp
ctbAdcs.cpp
ctbPattern.cpp
ctbAcquisition.cpp
${CMAKE_SOURCE_DIR}/slsDetectorCalibration/tiffio/src/tiffIO.cpp
)
#TODO! Replace with target
target_include_directories(ctbGui PRIVATE
${CMAKE_SOURCE_DIR}/slsDetectorCalibration/dataStructures
${CMAKE_SOURCE_DIR}/slsDetectorCalibration/interpolations
${CMAKE_SOURCE_DIR}/slsDetectorCalibration/
${CMAKE_SOURCE_DIR}/slsDetectorCalibration/tiffio/include/
)
# Headders needed for ROOT dictionary generation
set( HEADERS
ctbDefs.h
ctbMain.h
ctbDacs.h
ctbPattern.h
ctbSignals.h
ctbAdcs.h
ctbAcquisition.h
ctbPowers.h
ctbSlowAdcs.h
)
#set(ROOT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# ROOT dictionary generation
root_generate_dictionary(ctbDict ${HEADERS} LINKDEF ctbLinkDef.h)
add_library(ctbRootLib SHARED ctbDict.cxx)
target_include_directories(ctbRootLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(ctbRootLib PUBLIC
ROOT::Core
slsDetectorShared
${ROOT_LIBRARIES}
${ROOT_EXE_LINKER_FLAGS}
)
set_target_properties(
ctbRootLib PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
target_link_libraries(ctbGui PUBLIC
slsDetectorShared
ctbRootLib
${TIFF_LIBRARIES}
)
set_target_properties(ctbGui PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)

View File

@ -1,46 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
INCS=ctbMain.h ctbDacs.h ctbPattern.h ctbSignals.h ctbAdcs.h ctbAcquisition.h ctbPowers.h ctbSlowAdcs.h
SRC= $(INCS:.h=.cpp) ctbDict.cpp
LINKDEF=ctbLinkDef.h
ZMQLIB=../slsReceiverSoftware/include
LIBRARYCBF=$(CBFLIBDIR)/lib/*.o
INCDIR=-I../slsReceiverSoftware/include/ -I../slsDetectorSoftware/include/ -I../slsSupportLib/include/ -I../slsDetectorCalibration -I../slsDetectorCalibration/dataStructures -I$(CBFLIBDIR)/include -I../slsDetectorCalibration/interpolations
LDFLAG=-L../build/bin -lSlsDetector -lSlsSupport -L/usr/lib64/ -lpthread -lm -lstdc++ -lzmq -pthread -lrt -ltiff -L$(ZMQLIB) -L$(CBFLIBDIR)/lib/ -std=c++11
#
MAIN=ctbGui.cpp
DESTDIR?=../build/bin
OBJS = $(SRC:.cpp=.o) $(MAIN:.cpp=.o)
all: $(DESTDIR)/ctbGui
doc:
cd manual && make DESTDIR=$(DESTDIR)
htmldoc:
cd manual && make html DESTDIR=$(DESTDIR)
ctbDict.cpp: $(INCS) $(LINKDEF)
rootcint -f ctbDict.cpp -c $(INCS) $(LINKDEF)
%.o : %.cpp
echo $@
g++ -DMYROOT `root-config --cflags --glibs` -lMinuit -DCTB $(LDFLAG) -o $@ -c $< $(INCDIR)
#$(CXX) -o $@ -c $< $(INCLUDES) $(DFLAGS) -fPIC $(EPICSFLAGS) -lpthread #$(FLAGS)
$(DESTDIR)/ctbGui: $(OBJS) $(LINKDEF)
g++ -DMYROOT `root-config --cflags --glibs` -lMinuit -DCTB $(LDFLAG) -o ctbGui $(INCDIR) $(OBJS) ../slsDetectorCalibration/tiffIO.cpp
mv ctbGui $(DESTDIR)
clean:
rm -f $(DESTDIR)/ctbGui *.o ctbDict.* $(OBJS)

View File

@ -1,48 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
INCS=ctbMain.h ctbDacs.h ctbPattern.h ctbSignals.h ctbAdcs.h ctbAcquisition.h ctbPowers.h ctbSlowAdcs.h
SRC= $(INCS:.h=.cpp) ctbDict.cpp
LINKDEF=ctbLinkDef.h
#ctbActions.h
ZMQLIB=../slsReceiverSoftware/include
LIBRARYCBF=$(CBFLIBDIR)/lib/*.o
INCDIR=-I../slsReceiverSoftware/include/ -I../slsDetectorSoftware/include/ -I../slsSupportLib/include/ -I../slsDetectorCalibration -I../slsDetectorCalibration/dataStructures -I$(CBFLIBDIR)/include -I../slsDetectorCalibration/interpolations
LDFLAG=-L../build/bin -lSlsDetector -lSlsSupport -L/usr/lib64/ -lpthread -lm -lstdc++ -lzmq -pthread -lrt -ltiff -L$(ZMQLIB) -L$(CBFLIBDIR)/lib/ -std=c++11
#
MAIN=ctbGui.cpp
DESTDIR?=../build/bin
OBJS = $(SRC:.cpp=.o) $(MAIN:.cpp=.o)
all: $(DESTDIR)/ctbGui
doc:
cd manual && make DESTDIR=$(DESTDIR)
htmldoc:
cd manual && make html DESTDIR=$(DESTDIR)
ctbDict.cpp: $(INCS) $(LINKDEF)
rootcling -f ctbDict.cpp -c $(INCS) $(LINKDEF)
%.o : %.cpp
echo $@
g++ -DMYROOT `source root-config --cflags --glibs` -lMinuit -DCTB $(LDFLAG) -o $@ -c $< $(INCDIR)
#$(CXX) -o $@ -c $< $(INCLUDES) $(DFLAGS) -fPIC $(EPICSFLAGS) -lpthread #$(FLAGS)
$(DESTDIR)/ctbGui: $(OBJS) $(LINKDEF)
g++ -DMYROOT `source root-config --cflags --glibs` -lMinuit -DCTB $(LDFLAG) -o ctbGui $(INCDIR) $(OBJS) ../slsDetectorCalibration/tiffIO.cpp
mv ctbGui $(DESTDIR)
clean:
rm -f $(DESTDIR)/ctbGui *.o ctbDict.* $(OBJS)

File diff suppressed because it is too large Load Diff

View File

@ -1,248 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBACQUISITION_H
#define CTBACQUISITION_H
#include <TGFrame.h>
#include "ctbAdcs.h"
#include "ctbSignals.h"
#include "ctbPattern.h"
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TGCheckButton;
class TThread;
class TGraph;
class TMultiGraph;
class THStack;
class TGButtonGroup;
class TGRadioButton;
class TGComboBox;
class TTimer;
class TCanvas;
class TH2F;
class TH1F;
class TGLabel;
class TGTextButton;
namespace sls
{
class Detector;
class detectorData;
};
template <class dataType> class slsDetectorData;
class singlePhotonDetector;
//class singlePhotonDetector;
class commonModeSubtraction;
#include <string>
#include <stdint.h>
using namespace std;
class ctbAcquisition : public TGGroupFrame {
enum {DESERIALIZER, MOENCH04, MOENCH02, MOENCH03, IMAGE32B, IMAGE16B, ADCSAR2, MYTHEN301, MYTHEN302};
private:
TGTextEntry *eOutdir;
TGTextEntry *eFname;
TGNumberEntry *eFindex;
TGCheckButton *cFileSave;
TGNumberEntry *eSerOff;
TGNumberEntry *eDynRange;
TGNumberEntry *eNumCount;
TGNumberEntry *ePixX;
TGNumberEntry *ePixY;
TGNumberEntry *eFitADC;
TGNumberEntry *eBitPlot;
TGNumberEntry *eMinRaw;
TGNumberEntry *eMaxRaw;
TGNumberEntry *eMinPedSub;
TGNumberEntry *eMaxPedSub;
TGCheckButton *cMinMaxRaw;
TGCheckButton *cMinMaxPedSub;
TGNumberEntry *eMeasurements;
TGTextButton *bStatus;
// TGTextButton
TGCheckButton *cCompile;
TGTextButton *cLoad;
// TGCheckButton *cRun;
TThread *acqThread;
THStack *adcStack;
THStack *bitStack;
THStack *countsStack;
TH1F *adcHisto[NADCS];
TH1F *countsHisto[NADCS];
TH1F *bitHisto[NSIGNALS];
float bitOffset[NSIGNALS];
// int enableFlag[NADCS+4];
int roMode;
int dBitOffset;
TH1F *adcFit;
TH1F *bitPlot;
TH1F *countsFit;
TH2F *h2DMapAn; // for 2D detectors
TH2F *h2DMapDig; // for 2D detectors
TH1F *h1DMap; //for 1D detectors
// TH2F *h2Scan; // for 2D detectors
// TMultiGraph *mgAdcs;
// TH1I *plotAdc[NADCS];
sls::Detector* myDet;
int plotFlag[NADCS];
int bitPlotFlag[NSIGNALS];
int ip;
// int nChannels;
// int chanEnable;
//int nADCs;
std::vector <int> dbitlist;
std::vector <int> adclist;
TGButtonGroup *bgPlot;// = new TGVButtonGroup(main_frame);
TGRadioButton *rbPlotOff;
TGRadioButton *rbWaveform;
TGRadioButton *rbDistribution;
TGRadioButton *rb2D;
// TGRadioButton *rbScan;
TGComboBox *cbDetType;
TGCheckButton *cbGetPedestal;
TGCheckButton *cbSubtractPedestal;
TGCheckButton *cbCommonMode;
TGTextButton *bResetPedestal;
TGLabel *lClickX;
TGLabel *lClickY;
TGLabel *lClickValue;
TCanvas *myCanvas;
TTimer *plotTimer;
char patternFile[10000];
char patternCompiler[10000];
int globalPlot;
int adcPlot;
int dbitPlot;
int tenG;
int nAnalogSamples, nDigitalSamples;
// int iScanStep;
slsDetectorData<uint16_t> *dataStructure;
singlePhotonDetector *photonFinder;
//singlePhotonDetector *photonFinder;
commonModeSubtraction *commonMode;
int cmSub;
int stop;
uint64_t dBitMask;
int deserializer;
public:
ctbAcquisition(TGVerticalFrame*, sls::Detector*);
void setOutdir();
void setFname();
void setMeasurements();
void setFsave(Bool_t);
void changePlot(Int_t);
void changeDetector(Int_t);
void changePlot();
void changeDetector();
void setFindex();
void Draw();
void setCanvas(TCanvas*);
void toggleAcquisition();
void loadPattern();
static void* ThreadHandle(void *arg);
void update();
void acquisitionFinished();
// string getParameters();
void setGraph (int i ,int en, Pixel_t col);
void setBitGraph (int i ,int en, Pixel_t col);
void startAcquisition();
static void progressCallback(double,void*);
static void dataCallback(sls::detectorData*, long unsigned int, unsigned int, void*);
int StopFlag;
int plotData(sls::detectorData*, int);
void setPatternFile(const char* t);
void setPatternCompiler(const char* t);
void setAnalogSamples(int);
void setDigitalSamples(int);
void setADCEnable(Int_t);
void setDbitEnable(Int_t);
void setReadoutMode(int);
void updateChans();
void resetPedestal();
void ToggleCommonMode(Bool_t);
void TogglePedSub(Bool_t);
void ChangeHistoLimitsPedSub(Long_t );
void ChangeHistoLimitsRaw(Long_t);
void ChangeHistoLimitsPedSub( );
void ChangeHistoLimitsRaw();
void ChangeHistoLimitsPedSub(Bool_t );
void ChangeHistoLimitsRaw(Bool_t);
void ChangeSerialOffset();
void ChangeSerialOffset(Long_t);
void ChangeNumberOfChannels();
void ChangeNumberOfChannels(Long_t);
void ChangeDynamicRange();
void ChangeDynamicRange(Long_t);
void ChangeImagePixels();
void ChangeImagePixels(Long_t);
void canvasClicked();
void FitADC();
void plotBit();
ClassDef(ctbAcquisition,0)
};
#endif

View File

@ -1,616 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <TApplication.h>
#include <TGClient.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TRandom.h>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <TGButtonGroup.h>
#include <TGNumberEntry.h>
#include <TGLabel.h>
#include <TList.h>
#include <TGFileDialog.h>
#include <TGComboBox.h>
#include <TH2F.h>
#include <TColor.h>
#include <TH1F.h>
#include <TGraphErrors.h>
#include <TGColorSelect.h>
#include <THStack.h>
#include <TGTab.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "ctbAdcs.h"
#include "ctbDefs.h"
#include "sls/Detector.h"
using namespace std;
ctbAdc::ctbAdc(TGVerticalFrame *page, int i, sls::Detector *det)
: TGHorizontalFrame(page, 800,800), id(i), myDet(det) {
TGHorizontalFrame *hframe=this;
char tit[100];
page->AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
sprintf(tit, "ADC%d", id);
sAdcLabel= new TGLabel(hframe, tit);
hframe->AddFrame(sAdcLabel,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sAdcLabel->MapWindow();
sAdcLabel->SetTextJustify(kTextLeft);
sAdcInvert= new TGCheckButton(hframe, "Inv");
hframe->AddFrame( sAdcInvert,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sAdcInvert->MapWindow();
sAdcInvert->Connect("Toggled(Bool_t)","ctbAdc",this,"ToggledInvert(Bool_t)");
sAdcEnable= new TGCheckButton(hframe, "En");
hframe->AddFrame( sAdcEnable,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sAdcEnable->MapWindow();
// sAdcEnable->SetOn(kTRUE);
// sAdcEnable->SetEnabled(kFALSE);
sAdcEnable->Connect("Toggled(Bool_t)","ctbAdc",this,"ToggledEnable(Bool_t)");
sAdcPlot= new TGCheckButton(hframe, "Plot");
hframe->AddFrame( sAdcPlot,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sAdcPlot->MapWindow();
sAdcPlot->Connect("Toggled(Bool_t)","ctbAdc",this,"ToggledPlot(Bool_t)");
fColorSel = new TGColorSelect(hframe, id+1, 0);
fColorSel->Connect("ColorSelected(Pixel_t)","ctbAdc",this,"ColorChanged(Pixel_t)");
hframe->AddFrame(fColorSel, new TGLayoutHints(kLHintsTop |
kLHintsLeft, 2, 0, 2, 2));
fColorSel->SetColor(TColor::Number2Pixel(id+1));
// sprintf(tit,"adc%d",id);
// gADC=new TGraph();
// gADC->SetName(tit);
// gADC->SetLineColor(id+1);
// gADC->SetMarkerColor(id+1);
};
Pixel_t ctbAdc::getColor(){
return fColorSel->GetColor();
}
Bool_t ctbAdc::getEnabled(){
return getPlot();
}
Bool_t ctbAdc::getPlot(){
return sAdcPlot->IsOn();
}
Bool_t ctbAdc::getInverted(){
return sAdcInvert->IsOn();
}
Bool_t ctbAdc::getEnable(){
return sAdcEnable->IsOn();
}
void ctbAdc::setInverted(Bool_t b){
// cout << id << "set enabled " << b << endl;
if (b)
sAdcInvert->SetOn(kTRUE,kTRUE);
else
sAdcInvert->SetOn(kFALSE,kTRUE);
}
void ctbAdc::setEnable(Bool_t b){
// cout << id << "set enabled " << b << endl;
if (b)
sAdcEnable->SetOn(kTRUE,kFALSE);
else
sAdcEnable->SetOn(kFALSE,kFALSE);
}
void ctbAdc::setAdcAlias(char *tit, int plot, int color) {
if (tit)
sAdcLabel->SetText(tit);
if (plot>0)
sAdcPlot->SetOn(kTRUE,kTRUE);
else if (plot==0)
sAdcPlot->SetOn(kFALSE,kTRUE);
if (color>=0)
fColorSel->SetColor(color);
fColorSel->SetEnabled(sAdcPlot->IsOn());
}
string ctbAdc::getAdcAlias() {
char line[1000];
sprintf(line,"ADC%d %s %d %lx\n",id,sAdcLabel->GetText()->Data(),sAdcPlot->IsOn(),fColorSel->GetColor());
return string(line);
}
void ctbAdc::update() {
//Emit("ToggledAdcEnable(Int_t)", id);
}
void ctbAdc::ToggledPlot(Bool_t b){
// Long_t mask=b<<id;
// ToggledAdcPlot(mask);
cout << "Colsel " << id << " enable " << b << endl;
if (b)
fColorSel->SetEnabled(kTRUE);
else
fColorSel->SetEnabled(kFALSE);
// fColorSel->SetEnabled(sAdcPlot->IsOn());
Emit("ToggledAdcPlot(Int_t)", id);
}
void ctbAdc::ToggledInvert(Bool_t b){
// fColorSel->SetEnabled(sAdcPlot->IsOn());
Emit("ToggledAdcInvert(Int_t)", id);
}
void ctbAdc::ToggledEnable(Bool_t b){
fColorSel->SetEnabled(sAdcPlot->IsOn());
Emit("ToggledAdcEnable(Int_t)", id);
}
void ctbAdc::ColorChanged(Pixel_t) {
Emit("ToggledAdcPlot(Int_t)", id);
}
void ctbAdc::ToggledAdcPlot(Int_t b){
Emit("ToggledAdcPlot(Int_t)", id);
}
void ctbAdc::ToggledAdcInvert(Int_t b){
Emit("ToggledAdcInvert(Int_t)", id);
}
void ctbAdc::ToggledAdcEnable(Int_t b){
Emit("ToggledAdcEnable(Int_t)", id);
}
void ctbAdc::setEnabled(Bool_t b){
// cout << id << "set enabled " << b << endl;
if (b)
sAdcPlot->SetOn(kTRUE,kFALSE);
else
sAdcPlot->SetOn(kFALSE,kFALSE);
}
void ctbAdc::setPlot(Bool_t b){
// cout << id << "set enabled " << b << endl;
if (b)
sAdcPlot->SetOn(kTRUE,kTRUE);
else
sAdcPlot->SetOn(kFALSE,kTRUE);
}
ctbAdcs::ctbAdcs(TGVerticalFrame *page, sls::Detector *det)
: TGGroupFrame(page,"Adcs",kVerticalFrame), myDet(det) {
SetTitlePos(TGGroupFrame::kLeft);
page->AddFrame(this,new TGLayoutHints( kLHintsTop | kLHintsExpandX , 10,10,10,10));
MapWindow();
TGHorizontalFrame* hframe=new TGHorizontalFrame(this, 800,800);
AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
int idac=0;
TGHorizontalFrame* hhframe=new TGHorizontalFrame(this, 800,800);
AddFrame(hhframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hhframe->MapWindow();
TGVerticalFrame *vframe;
for (idac=0; idac<NADCS; idac++) {
if (idac%16==0) {
vframe=new TGVerticalFrame(hhframe, 400,800);
hhframe->AddFrame(vframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
vframe->MapWindow();
}
sAdc[idac]=new ctbAdc(vframe,idac,myDet);
sAdc[idac]->Connect("ToggledAdcPlot(Int_t)","ctbAdcs",this,"ToggledAdcPlot(Int_t)");
sAdc[idac]->Connect("ToggledAdcInvert(Int_t)","ctbAdcs",this,"ToggledAdcInvert(Int_t)");
sAdc[idac]->Connect("ToggledAdcEnable(Int_t)","ctbAdcs",this,"ToggledAdcEnable(Int_t)");
}
hframe=new TGHorizontalFrame(this, 800,800);
AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
bCheckHalf[0]=new TGTextButton(hframe, "All 0-15");
hframe->AddFrame(bCheckHalf[0],new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
bCheckHalf[0]->MapWindow();
bCheckHalf[0]->Connect("Clicked()","ctbAdcs",this,"CheckHalf0()");
bRemoveHalf[0]=new TGTextButton(hframe, "None 0-15");
hframe->AddFrame(bRemoveHalf[0],new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 5, 5, 5, 5));
bRemoveHalf[0]->MapWindow();
bRemoveHalf[0]->Connect("Clicked()","ctbAdcs",this,"RemoveHalf0()");
bCheckHalf[1]=new TGTextButton(hframe, "All 16-23");
hframe->AddFrame(bCheckHalf[1],new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
bCheckHalf[1]->MapWindow();
bCheckHalf[1]->Connect("Clicked()","ctbAdcs",this,"CheckHalf1()");
// bCheckAll->Connect("Clicked()","ctbAdcs",this,"CheckAll()");
bRemoveHalf[1]=new TGTextButton(hframe, "None 16-23");
hframe->AddFrame(bRemoveHalf[1],new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 5, 5, 5, 5));
bRemoveHalf[1]->MapWindow();
bRemoveHalf[1]->Connect("Clicked()","ctbAdcs",this,"RemoveHalf1()");
// bRemoveAll->Connect("Clicked()","ctbAdcs",this,"RemoveAll()");
hframe=new TGHorizontalFrame(this, 800,800);
AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
bCheckAll=new TGTextButton(hframe, "All");
hframe->AddFrame(bCheckAll,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
bCheckAll->MapWindow();
bCheckAll->Connect("Clicked()","ctbAdcs",this,"CheckAll()");
bRemoveAll=new TGTextButton(hframe, "None");
hframe->AddFrame(bRemoveAll,new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 5, 5, 5, 5));
bRemoveAll->MapWindow();
bRemoveAll->Connect("Clicked()","ctbAdcs",this,"RemoveAll()");
hframe=new TGHorizontalFrame(this, 800,50);
AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
TGLabel *label= new TGLabel(hframe, "Inversion mask: ");
hframe->AddFrame(label,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
label->MapWindow();
label->SetTextJustify(kTextLeft);
eInversionMask = new TGNumberEntry(hframe, 0, 16,999, TGNumberFormat::kNESHex,
TGNumberFormat::kNEANonNegative,
TGNumberFormat::kNELNoLimits);
hframe->AddFrame(eInversionMask,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1));
eInversionMask->MapWindow();
eInversionMask->Resize(150,30);
eInversionMask->SetState(kFALSE);
hframe=new TGHorizontalFrame(this, 800,50);
AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
label= new TGLabel(hframe, "Enable mask: ");
hframe->AddFrame(label,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
label->MapWindow();
label->SetTextJustify(kTextLeft);
eEnableMask = new TGNumberEntry(hframe, 0, 16,999, TGNumberFormat::kNESHex,
TGNumberFormat::kNEANonNegative,
TGNumberFormat::kNELNoLimits);
hframe->AddFrame(eEnableMask,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1));
eEnableMask->MapWindow();
eEnableMask->Resize(150,30);
eEnableMask->SetState(kFALSE);
}
int ctbAdcs::setEnable(int reg) {
try {
if (reg > -1) {
myDet->setADCEnableMask(reg);
}
auto retval = myDet->getADCEnableMask().tsquash("Different values");
eEnableMask->SetHexNumber(retval);
return retval;
} CATCH_DISPLAY ("Could not set/get adc enablemask.", "ctbAdcs::setEnable")
return -1;
}
int ctbAdcs::setInvert(int reg) {
try {
if (reg > -1) {
myDet->setADCInvert(reg);
}
auto retval = myDet->getADCInvert().tsquash("Different values");
eInversionMask->SetHexNumber(retval);
return retval;
} CATCH_DISPLAY ("Could not set/get adc enablemask.", "ctbAdcs::setEnable")
return -1;
}
void ctbAdcs::update() {
Int_t invreg;
Int_t disreg;
disreg=setEnable();
invreg=setInvert();
for (int is=0; is<NADCS; is++) {
sAdc[is]->setAdcAlias(NULL,-1,-1);
if (invreg & (1<<is) )
sAdc[is]->setInverted(kTRUE);
else
sAdc[is]->setInverted(kFALSE);
if (disreg & (1<<is) )
sAdc[is]->setEnable(kTRUE);
else
sAdc[is]->setEnable(kFALSE);
}
Emit("AdcEnable(Int_t)", disreg);
}
string ctbAdcs::getAdcParameters() {
ostringstream line;
line << "reg "<< hex << setInvert() << "# ADC invert reg" << dec << endl;
line << "reg "<< hex << setEnable() << " # ADC enable reg"<< dec << endl;
return line.str();
}
void ctbAdcs::CheckAll() {
for (int is=0; is<NADCS; is++){
sAdc[is]->setPlot(kTRUE);
}
}
void ctbAdcs::RemoveAll() {
for (int is=0; is<NADCS; is++) {
sAdc[is]->setPlot(kFALSE);
}
}
void ctbAdcs::CheckHalf0() {
for (int is=0; is<NADCS/2; is++) {
sAdc[is]->setPlot(kTRUE);
}
}
void ctbAdcs::RemoveHalf0() {
for (int is=0; is<NADCS/2; is++){
sAdc[is]->setPlot(kFALSE);
}
}
void ctbAdcs::CheckHalf1() {
for (int is=NADCS/2; is<NADCS; is++){
sAdc[is]->setPlot(kTRUE);
}
}
void ctbAdcs::RemoveHalf1() {
for (int is=NADCS/2; is<NADCS; is++){
sAdc[is]->setPlot(kFALSE);
}
}
int ctbAdcs::setAdcAlias(string line) {
int is=-1, plot=0, color=-1;
char tit[100];
int narg=sscanf(line.c_str(),"ADC%d %s %d %x",&is,tit,&plot, &color);
if (narg<2)
return -1;
if (narg!=3)
color=-1;
if (is>=0 && is<NADCS) {
sAdc[is]->setAdcAlias(tit,plot,color);
}
return is;
}
string ctbAdcs::getAdcAlias() {
ostringstream line;
for (int is=0; is<NADCS; is++)
line << sAdc[is]->getAdcAlias();
return line.str();
}
void ctbAdcs::ToggledAdcPlot(Int_t b){
Emit("ToggledAdcPlot(Int_t)", b);
}
void ctbAdcs::AdcEnable(Int_t b){
Emit("AdcEnable(Int_t)", b);
}
void ctbAdcs::ToggledAdcEnable(Int_t b){
Int_t oreg=setEnable();
Int_t m=1<<b;
if (sAdc[b]->getEnable())
oreg|=m;
else
oreg&=~m;
setEnable(oreg);
Emit("AdcEnable(Int_t)", oreg);
}
void ctbAdcs::ToggledAdcInvert(Int_t b){
Int_t oreg=setInvert();
Int_t m=1<<b;
if (sAdc[b]->getInverted())
oreg|=m;
else
oreg&=~m;
setInvert(oreg);
}
Pixel_t ctbAdcs::getColor(int i){
if (i>=0 && i<NADCS)
return sAdc[i]->getColor();
return static_cast<Pixel_t>(-1);
}
Bool_t ctbAdcs::getEnabled(int i){
if (i>=0 && i<NADCS)
return sAdc[i]->getEnabled();
return static_cast<Bool_t>(-1);
}
Bool_t ctbAdcs::getEnable(int i){
if (i>=0 && i<NADCS)
return sAdc[i]->getEnable();
return static_cast<Bool_t>(-1);
}
Bool_t ctbAdcs::getPlot(int i){
if (i>=0 && i<NADCS)
return sAdc[i]->getPlot();
return static_cast<Bool_t>(-1);
}

View File

@ -1,157 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBADCS_H
#define CTBADCS_H
#include <TGFrame.h>
#define NADCS 32
class TRootEmbeddedCanvas;
class TGButtonGroup;
class TGVerticalFrame;
class TGHorizontalFrame;
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TH2F;
class TGComboBox;
class TGCheckButton;
class TGColorSelect;
class TColor;
class THStack;
class TGraphErrors;
class TGTextButton;
class TGTab;
class TGraph;
namespace sls
{
class Detector;
};
#include <string>
using namespace std;
class ctbAdc : public TGHorizontalFrame {
private:
TGLabel *sAdcLabel;
TGCheckButton *sAdcEnable;
TGCheckButton *sAdcPlot;
TGCheckButton *sAdcInvert;
TGColorSelect *fColorSel;
// TGraph *gADC;
int id;
sls::Detector *myDet;
public:
ctbAdc(TGVerticalFrame *page, int i, sls::Detector *det);
void setAdcAlias(char *tit, int plot, int color);
string getAdcAlias();
void ToggledAdcPlot(Int_t b);
void ToggledAdcEnable(Int_t b);
void ToggledAdcInvert(Int_t b);
void ToggledPlot(Bool_t b);
void ToggledEnable(Bool_t b);
void ToggledInvert(Bool_t b);
void ColorChanged(Pixel_t);
void setEnabled(Bool_t b);
Bool_t getEnabled();
// TGraph *getGraph();
void update();
Pixel_t getColor();
Bool_t getEnable();
void setEnable(Bool_t);
void setPlot(Bool_t);
Bool_t getInverted();
Bool_t getPlot();
void setInverted(Bool_t);
ClassDef(ctbAdc,0)
};
class ctbAdcs : public TGGroupFrame {
private:
ctbAdc *sAdc[NADCS];
sls::Detector *myDet;
TGTextButton *bCheckAll;
TGTextButton *bRemoveAll;
TGTextButton *bCheckHalf[2];
TGTextButton *bRemoveHalf[2];
TGNumberEntry *eInversionMask;
TGNumberEntry *eEnableMask;
/* TGTextButton *bPlotSelected; */
/* TGNumberEntry *eMinX; */
/* TGNumberEntry *eMaxX; */
/* TGNumberEntry *eMinY; */
/* TGNumberEntry *eMaxY; */
/* TGTextButton *bGetPixel; */
/* TGNumberEntry *ePixelX; */
/* TGNumberEntry *ePixelY; */
/* TGLabel *lPixelValue; */
public:
ctbAdcs(TGVerticalFrame *page, sls::Detector *det);
int setAdcAlias(string line);
string getAdcAlias();
string getAdcParameters();
void ToggledAdcPlot(Int_t);
void ToggledAdcInvert(Int_t);
void ToggledAdcEnable(Int_t);
void AdcEnable(Int_t b);
// TGraph *getGraph(int i);
void CheckAll();
void RemoveAll();
void update();
int setInvert(int reg=-1);
int setEnable(int reg=-1);
Pixel_t getColor(int i);
Bool_t getEnabled(int i);
Bool_t getPlot(int i);
Bool_t getEnable(int i);
void CheckHalf0();
void RemoveHalf0();
void CheckHalf1();
void RemoveHalf1();
ClassDef(ctbAdcs,0)
};
#endif

View File

@ -1,235 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <TGTextEntry.h>
#include <TGLabel.h>
#include <TGNumberEntry.h>
#include <TGButton.h>
#include "ctbDacs.h"
#include "ctbDefs.h"
#include "sls/Detector.h"
#include "sls/sls_detector_defs.h"
using namespace std;
ctbDac::ctbDac(TGGroupFrame *page, int idac, sls::Detector *det) : TGHorizontalFrame(page, 800,50) , id(idac), myDet(det) {
TGHorizontalFrame *hframe=this;
page->AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
MapWindow();
char tit[100];
sprintf(tit, "DAC %d:",idac);
dacsLabel= new TGCheckButton(hframe, tit);// new TGLabel(hframe, tit);
dacsLabel->SetOn(kTRUE, kTRUE);
dacsLabel->Connect("Toggled(Bool_t)","ctbDac",this,"setOn(Bool_t)");
hframe->AddFrame(dacsLabel,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
dacsLabel->MapWindow();
dacsLabel->SetTextJustify(kTextLeft);
dacsEntry = new TGNumberEntry(hframe, 0, 9,999, TGNumberFormat::kNESInteger,
TGNumberFormat::kNEANonNegative,
TGNumberFormat::kNELLimitMinMax,
0, 65535);
hframe->AddFrame(dacsEntry,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
dacsEntry->MapWindow();
dacsEntry->Resize(150,30);
dacsUnit= new TGCheckButton(hframe, "mV");
// if (idac!=slsDetectorDefs::ADC_VPP) {
hframe->AddFrame( dacsUnit,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
dacsUnit->MapWindow();
if (idac==slsDetectorDefs::ADC_VPP) {
dacsUnit->SetEnabled(kFALSE);
hframe->HideFrame(dacsUnit);
dacsUnit->MapWindow();
cout << "hiding!" << endl;
}
if (idac==slsDetectorDefs::HIGH_VOLTAGE) {
dacsUnit->SetText("V");
dacsUnit->SetOn(kTRUE,kTRUE);
dacsUnit->SetEnabled(kFALSE);
}
//}
sprintf(tit, "xxx");
dacsValue= new TGLabel(hframe, tit);
hframe->AddFrame( dacsValue,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
dacsValue->MapWindow();
dacsValue->SetTextJustify(kTextLeft);
TGTextEntry *e=dacsEntry->TGNumberEntry::GetNumberEntry();
e->Connect("ReturnPressed()","ctbDac",this,"setValue()");
// e->Connect("ValueSet(Long_t)","ctbDac",this,"setValue(Long_t)");
dacsEntry->Connect("ValueSet(Long_t)","ctbDac",this,"setValue(Long_t)");
// cout << "(((((((((((((((((((((((((((((((" << dacsEntry->GetListOfSignals()->At(0)->IsA() << endl;
}
int ctbDac::setLabel(char *tit, int mv) {
if(tit)
dacsLabel->SetText(tit);
if (mv==1)
dacsUnit->SetOn(kTRUE,kTRUE);
else if (mv==0)
dacsUnit->SetOn(kFALSE,kTRUE);
// else if (mv==2) {
// ;}
// else if (mv==3)
// ;
return id;
}
string ctbDac::getLabel() {
ostringstream line;
line << dacsLabel->GetText() << " " << dacsUnit->IsOn() << endl;
// line << "DAC" << dec << id << " " << dacsUnit->IsOn() << endl;
return line.str();
}
int ctbDac::getMoenchDacId() {
slsDetectorDefs::dacIndex moenchDacIndices[8] = {slsDetectorDefs::VBP_COLBUF, slsDetectorDefs::VIPRE, slsDetectorDefs::VIN_CM, slsDetectorDefs::VB_SDA, slsDetectorDefs::VCASC_SFP, slsDetectorDefs::VOUT_CM, slsDetectorDefs::VIPRE_CDS, slsDetectorDefs::IBIAS_SFP};
if (id >= 8) {
return id;
}
return static_cast<int>(moenchDacIndices[id]);
}
void ctbDac::setValue(Long_t a) {setValue();}
void ctbDac::setValue() {
cout << "setting dac! "<< id << " value " << dacsEntry->GetIntNumber() << " units " << dacsUnit->IsOn() << endl;
try {
int sid = id;
if (myDet->getDetectorType().squash() == slsDetectorDefs::MOENCH) {
sid = getMoenchDacId();
}
myDet->setDAC(static_cast<slsDetectorDefs::dacIndex>(sid), dacsEntry->GetIntNumber(), dacsUnit->IsOn());
} CATCH_DISPLAY ("Could not set dac " + to_string(id) + ".", "ctbDac::setValue")
getValue();
}
void ctbDac::setOn(Bool_t b) {
// cout << "setting dac! "<< id << endl;
if ( dacsLabel->IsOn()) {
setValue();
} else {
try {
int sid = id;
if (myDet->getDetectorType().squash() == slsDetectorDefs::MOENCH) {
sid = getMoenchDacId();
}
myDet->setDAC(static_cast<slsDetectorDefs::dacIndex>(sid), -100, false);
} CATCH_DISPLAY ("Could not power off dac " + to_string(id) + ".", "ctbDac::setOn")
}
getValue();
}
int ctbDac::getValue() {
try {
int sid = id;
if (myDet->getDetectorType().squash() == slsDetectorDefs::MOENCH) {
sid = getMoenchDacId();
}
int val = myDet->getDAC(static_cast<slsDetectorDefs::dacIndex>(sid), dacsUnit->IsOn()).tsquash("Different values");
cout << "dac " << id << " " << val << endl;
dacsValue->SetText(to_string(val).c_str());
if (val >= 0) {
dacsLabel->SetOn(kTRUE);
} else {
dacsLabel->SetOn(kFALSE);
}
return val;
} CATCH_DISPLAY ("Could not get dac " + to_string(id) + ".", "ctbDac::getValue")
return -1;
}
ctbDacs::ctbDacs(TGVerticalFrame *page, sls::Detector *det) : TGGroupFrame(page,"DACs",kVerticalFrame) , myDet(det){
SetTitlePos(TGGroupFrame::kLeft);
page->AddFrame(this,new TGLayoutHints( kLHintsTop | kLHintsExpandX , 10,10,10,10));
MapWindow();
// cout << "window mapped " << endl;
for (int idac=0; idac<NDACS; idac++) {
dacs[idac]=new ctbDac(this, idac, myDet);
}
dacs[NDACS]=new ctbDac(this, slsDetectorDefs::ADC_VPP, myDet);
dacs[NDACS+1]=new ctbDac(this, slsDetectorDefs::HIGH_VOLTAGE, myDet);
dacs[NDACS]->setLabel((char*)"ADC Vpp",2);
dacs[NDACS+1]->setLabel((char*)"High Voltage",3);
}
int ctbDacs::setDacAlias(string line) {
int is=-1, mv=0;
char tit[100];
int narg=sscanf(line.c_str(),"DAC%d %s %d",&is,tit,&mv);
if (narg<2)
return -1;
if (is>=0 && is<NDACS)
dacs[is]->setLabel(tit,mv);
return is;
}
string ctbDacs::getDacAlias() {
ostringstream line;
for (int i=0; i<NDACS; i++)
line << dacs[i]->getLabel() << endl;
return line.str();
}
string ctbDacs::getDacParameters() {
ostringstream line;
for (int i=0; i<NDACS; i++) {
//line << "dacs:" << i << " " << dacs[i]->getValue << endl;
line << "dac:" << i << " " << dacs[i]->getValue() << endl;
}
return line.str();
}
void ctbDacs::update() {
for (int idac=0; idac<NDACS+1; idac++) {
dacs[idac]->getValue();
}
}

View File

@ -1,77 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBDACS_H
#define CTBDACS_H
#include <TGFrame.h>
#define NDACS 18
//#define NDACS 16
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TGCheckButton;
namespace sls
{
class Detector;
};
#include <string>
using namespace std;
class ctbDac : public TGHorizontalFrame {
protected:
// TGLabel *dacsLabel;
TGNumberEntry *dacsEntry;
TGCheckButton *dacsUnit;
TGCheckButton *dacsLabel;
TGLabel *dacsValue;
int id;
sls::Detector* myDet;
public:
ctbDac(TGGroupFrame*, int , sls::Detector*);
void setValue();
void setValue(Long_t);
int getValue();
void setOn(Bool_t);
int setLabel(char *tit, int mv);
string getLabel();
int getMoenchDacId();
ClassDef(ctbDac,0)
};
class ctbDacs : public TGGroupFrame {
private:
ctbDac *dacs[NDACS+2];
sls::Detector* myDet;
public:
ctbDacs(TGVerticalFrame *page, sls::Detector*);
int setDacAlias(string line);
// int setDacAlias(string line);
string getDacAlias();
string getDacParameters();
void update();
ClassDef(ctbDacs,0)
};
#endif

View File

@ -1,86 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include <string>
#include <stdexcept>
#include <chrono>
//#include "sls/sls_detector_exceptions.h"
//#include "sls/ansi.h"
#define RED "\x1b[31m"
#define RESET "\x1b[0m"
#define BOLD "\x1b[1m"
#define cprintf(code, format, ...) printf(code format RESET, ##__VA_ARGS__)
#define CATCH_DISPLAY(m, s) catch(...) { ctbDefs::DisplayExceptions(m, s); }
#define CATCH_HANDLE(...) catch(...) { ctbDefs::HandleExceptions(__VA_ARGS__); }
class ctbDefs {
public:
/**
* Empty Constructor
*/
ctbDefs(){};
// convert double seconds to chrono ns
static std::chrono::nanoseconds ConvertDoubleStoChronoNS(double timeS) {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::nanoseconds;
return duration_cast<nanoseconds>(duration<double>(timeS));
}
// convert chrono ns to doubel s
static double ConvertChronoNStoDoubleS(std::chrono::nanoseconds timeNs) {
using std::chrono::duration;
using std::chrono::duration_cast;
return duration_cast<duration<double>>(timeNs).count();
}
static void DisplayExceptions(std::string emsg, std::string src) {
try {
throw;
} /* catch (const sls::SocketError &e) {
throw;
} catch (const sls::SharedMemoryError &e) {
throw;
} */catch (const std::exception &e) {
ExceptionMessage(emsg, e.what(), src);
}
};
template <class CT> struct NonDeduced { using type = CT; };
template <class S, typename RT, typename... CT>
static void HandleExceptions(const std::string emsg, const std::string src, S* s,
RT (S::*somefunc)(CT...),
typename NonDeduced<CT>::type... Args) {
try {
throw;
} /*catch (const sls::SocketError &e) {
throw;
} catch (const sls::SharedMemoryError &e) {
throw;
} */catch (const std::exception &e) {
ExceptionMessage(emsg, e.what(), src);
(s->*somefunc)(Args...);
}
};
static void ExceptionMessage(std::string message,
std::string exceptionMessage,
std::string source) {
// because sls_detector_exceptions cannot be included
if (exceptionMessage.find("hared memory") != std::string::npos) {
throw;
}
if (exceptionMessage.find("annot connect") != std::string::npos) {
throw;
}
cprintf(RED, "Warning (%s): %s [Caught Exception: %s]\n", source.c_str(), message.c_str(), exceptionMessage.c_str());
//return Message(qDefs::WARNING, message + std::string("\nCaught exception:\n") + exceptionMessage, source);
};
};

View File

@ -1,159 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <TApplication.h>
#include <TColor.h>
#include <TStyle.h>
#include <TROOT.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include "sls/Detector.h"
#include "sls/sls_detector_defs.h"
//#include "sls_receiver_defs.h"
#include "ctbMain.h"
#include "ctbDefs.h"
using namespace std;
int main(int argc, char **argv) {
string afname, cfname, pfname;
int id=0;
int af=0, cf=0, pf=0;
cout << " *** " << argc << endl;
for (int ia=0; ia<argc; ia++) {
if (strcmp(argv[ia],"-alias")==0) {
if (ia+1<argc) {
afname=argv[ia+1];
ia++;
af=1;
}
} else if (strcmp(argv[ia],"-config")==0) {
if (ia+1<argc) {
cfname=argv[ia+1];
ia++;
cf=1;
}
} else if (strcmp(argv[ia],"-par")==0) {
if (ia+1<argc) {
pfname=argv[ia+1];
ia++;
pf=1;
}
} else if (strcmp(argv[ia],"-id")==0) {
if (ia+1<argc) {
id=atoi(argv[ia+1]);
ia++;
}
}
}
cout << " *** " << endl;
sls::Detector *myDet = nullptr;
try {
/****** Create detector ****************/
myDet=new sls::Detector(id);
cout << "Created multi detector id " << id << endl;
if (cf) {
myDet->loadConfig(cfname);
cout << "Config file loaded successfully" << endl;
} else {
cout << "No config file specified" << endl;
}
cout << "hostname " << myDet->getHostname() << endl;
if (pf) {
myDet->loadParameters(pfname);
cout << "Loaded parameter file successfully" << endl;
} else{
cout << "No parameter file specified" << endl;
}
} CATCH_DISPLAY ("Could not create detector/ load config/parameters.", "ctbGui::main")
/***********Create GUI stuff *******************/
TApplication theApp("App",&argc,argv);
gStyle->SetDrawBorder(0);
gStyle->SetCanvasColor(kWhite);
gStyle->SetCanvasDefH(800);
gStyle->SetCanvasDefW(800);
gStyle->SetCanvasBorderMode(0);
gStyle->SetPadBorderMode(0);
gStyle->SetPaintTextFormat("5.2f");
gStyle->SetLineWidth(2);
gStyle->SetTextSize(1.1);
gStyle->SetLabelSize(0.04,"xy");
gStyle->SetTitleSize(0.05,"xy");
gStyle->SetTitleOffset(1.0,"x");
gStyle->SetTitleOffset(1.1,"y");
gStyle->SetPadTopMargin(0.15);
gStyle->SetPadRightMargin(0.15);
gStyle->SetPadBottomMargin(0.15);
gStyle->SetPadLeftMargin(0.15);
gStyle->SetLegendBorderSize(1);
gStyle->SetFrameBorderMode(0);
gStyle->SetFrameFillColor(kWhite);
// gStyle->SetLegendFillColor(kWhite);
gStyle->SetTitleFillColor(kWhite);
gStyle->SetFillColor(kWhite);
gStyle->SetStatFontSize(0.03);
gStyle->SetStatBorderSize(1);
gStyle->SetStatFormat("6.4g");
gStyle->SetStatX(0.95);
gStyle->SetStatY(0.95);
gStyle->SetStatW(0.2);
gStyle->SetStatH(0.2);
gStyle->SetTitleX(0.1);
gStyle->SetTitleY(0.95);
gStyle->SetTitleBorderSize(0);
gStyle->SetTitleFontSize(0.05);
gROOT->SetStyle("Default");
TColor::InitializeColors();
const Int_t NRGBs = 5;
const Int_t NCont = 90;
Double_t stops[NRGBs] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
Double_t red[NRGBs] = { 0.00, 0.00, 0.87, 1.00, 0.51 };
Double_t green[NRGBs] = { 0.00, 0.81, 1.00, 0.20, 0.00 };
Double_t blue[NRGBs] = { 0.51, 1.00, 0.12, 0.00, 0.00 };
TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont);
gStyle->SetNumberContours(NCont);
gROOT->ForceStyle();
ctbMain *mf=new ctbMain(gClient->GetRoot(), myDet);
cout << " *** " << argc << endl;
for (int ia=0; ia<argc; ia++)
cout << argv[ia] << endl;
cout << " *** " << endl;
if (af)
mf->loadAlias(afname);
else
cout << "no alias specified" << endl;
theApp.Run();
return 0;
}

View File

@ -1,17 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma link C++ class ctbMain;
#pragma link C++ class ctbDacs;
#pragma link C++ class ctbDac;
#pragma link C++ class ctbSignals;
#pragma link C++ class ctbSignal;
#pragma link C++ class ctbAdc;
#pragma link C++ class ctbAdcs;
#pragma link C++ class ctbLoop;
#pragma link C++ class ctbWait;
#pragma link C++ class ctbPattern;
#pragma link C++ class ctbAcquisition;
#pragma link C++ class ctbPower;
#pragma link C++ class ctbPowers;
#pragma link C++ class ctbSlowAdc;
#pragma link C++ class ctbSlowAdcs;

View File

@ -1,588 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <TApplication.h>
#include <TGClient.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TRandom.h>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <TGButtonGroup.h>
#include <TGNumberEntry.h>
#include <TGLabel.h>
#include <TList.h>
#include <TGFileDialog.h>
#include <TGComboBox.h>
#include <TH2F.h>
#include <TColor.h>
#include <TH1F.h>
#include <TGraphErrors.h>
#include <THStack.h>
#include <TGTab.h>
#include <TApplication.h>
#include <TGCanvas.h>
#include <stdlib.h>
#include <TGMenu.h>
#include <TGDockableFrame.h>
//#include <TGMenuBar.h>
//#include <TGPopupMenu.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include "sls/Detector.h"
#include "ctbDefs.h"
#include "ctbMain.h"
#include "ctbDacs.h"
#include "ctbSlowAdcs.h"
#include "ctbPowers.h"
#include "ctbSignals.h"
#include "ctbPattern.h"
#include "ctbAdcs.h"
#include "ctbAcquisition.h"
//#include "ctbActions.h"
using namespace std;
ctbMain::ctbMain(const TGWindow *p, sls::Detector *det)
: TGMainFrame(p,800,800), pwrs(NULL), senses(NULL) {
myDet=det;
Connect("CloseWindow()", "ctbMain", this, "CloseWindow()");
// fMenuDock = new TGDockableFrame(this);
// AddFrame(fMenuDock, new TGLayoutHints(kLHintsExpandX, 0, 0, 1, 0));
// fMenuDock->SetWindowName("GuiTest Menu");
fMenuBarLayout = new TGLayoutHints(kLHintsTop | kLHintsExpandX);
fMenuBarItemLayout = new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0);
fMenuBarHelpLayout = new TGLayoutHints(kLHintsTop | kLHintsRight);
fMenuFile = new TGPopupMenu(gClient->GetRoot());
int im=0;
fMenuFile->AddEntry("Open Alias", im++);
fMenuFile->AddEntry("Save Alias", im++);
fMenuFile->AddSeparator();
fMenuFile->AddEntry("Open Parameters", im++);
fMenuFile->AddEntry("Save Parameters", im++);
fMenuFile->AddSeparator();
fMenuFile->AddEntry("Open Configuration", im++);
fMenuFile->AddEntry("Save Configuration", im++);
fMenuFile->AddSeparator();
fMenuFile->AddEntry("Open Pattern", im++);
fMenuFile->AddEntry("Save Pattern", im++);
fMenuFile->AddSeparator();
fMenuFile->AddEntry("Exit", im++);
fMenuFile->Connect("Activated(Int_t)", "ctbMain", this,
"HandleMenu(Int_t)");
i_dacs=-1;
i_pwrs=-1;
i_senses=-1;
i_sig=-1;
i_adcs=-1;
i_pat=-1;
i_acq=-1;
int i_page=0;
TGVerticalFrame *vframe=new TGVerticalFrame(this, 800,1200); //main frame
fMenuBar = new TGMenuBar(vframe, 1, 1, kHorizontalFrame);
fMenuBar->AddPopup("&File", fMenuFile, fMenuBarItemLayout);
// fMenuBar->AddPopup("&Test", fMenuTest, fMenuBarItemLayout);
// fMenuBar->AddPopup("&View", fMenuView, fMenuBarItemLayout);
// fMenuBar->AddPopup("&Help", fMenuHelp, fMenuBarHelpLayout);
vframe->AddFrame(fMenuBar, fMenuBarLayout);
TGHorizontalFrame* hpage=new TGHorizontalFrame(vframe, 800,1200); //horizontal frame. Inside there should be the tab and the canvas
mtab=new TGTab(hpage, 1500, 1200); //tab!
// page=new TGVerticalFrame(mtab, 1500,1200);
cout << "DACS" << endl;
TGCompositeFrame *tf = mtab->AddTab("DACs");
TGVerticalFrame *page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
dacs=new ctbDacs(page, myDet);
i_dacs=i_page++;
cout << "power " << endl;
tf = mtab->AddTab("Power Supplies");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
pwrs=new ctbPowers(page, myDet);
i_pwrs=i_page++;
cout << "sense " << endl;
tf = mtab->AddTab("Sense");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
senses=new ctbSlowAdcs(page, myDet);
i_senses=i_page++;
cout << "signals " << endl;
tf = mtab->AddTab("Signals");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
sig=new ctbSignals(page, myDet);
sig->Connect("ToggledSignalPlot(Int_t)","ctbMain",this,"setSignalPlot(Int_t)");
i_sig=i_page++;
cout << "adcs " << endl;
tf = mtab->AddTab("ADCs");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
adcs=new ctbAdcs(page, myDet);
adcs->Connect("ToggledAdcPlot(Int_t)","ctbMain",this,"setADCPlot(Int_t)");
adcs->Connect("AdcEnable(Int_t)","ctbMain",this,"setADCEnable(Int_t)");
i_adcs=i_page++;
cout << "pattern" << endl;
tf = mtab->AddTab("Pattern");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
pat=new ctbPattern(page, myDet);
pat->Connect("patternFileChanged(const char*)","ctbMain",this,"setPatternFile(const char*)");
pat->Connect("patternCompilerChanged(const char*)","ctbMain",this,"setPatternCompiler(const char*)");
pat->Connect("analogSamplesChanged(const int)","ctbMain",this,"setAnalogSamples(int)");
pat->Connect("digitalSamplesChanged(const int)","ctbMain",this,"setDigitalSamples(int)");
pat->Connect("readoutModeChanged(int)","ctbMain",this,"setReadoutMode(int)");
i_pat=i_page++;
cout << "acquisition" << endl;
tf = mtab->AddTab("Acquisition");
page=new TGVerticalFrame(tf, 1500,1200);
tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
acq=new ctbAcquisition(page, myDet);
i_acq=i_page++;
// cout << "actions" << endl;
// tf = mtab->AddTab("Actions");
// page=new TGVerticalFrame(tf, 1500,1200);
// tf->AddFrame(page, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
// actions=new ctbActions(page, myDet);
// i_actions=i_page++;
cout << "tabs finished" << endl;
hpage->AddFrame(mtab,new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
vframe->AddFrame(hpage,new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
AddFrame(vframe,new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10,10,10,1));
vframe->MapWindow();
hpage->MapWindow();
mtab->MapWindow();
page->MapWindow();
// Sets window name and shows the main frame
cout << "dockabel" << endl;
TGDockableFrame *fdock=new TGDockableFrame(hpage);
hpage->AddFrame(fdock, new TGLayoutHints(kLHintsBottom | kLHintsCenterX | kLHintsExpandX | kLHintsExpandY, 10,10,10,10));
fdock->MapWindow();
cout << "canvas" << endl;
// // Creates widgets of the example
fEcanvas = new TRootEmbeddedCanvas ("Ecanvas",fdock,800,800);//hpage,800,800);
//fEcanvas = new TRootEmbeddedCanvas ("Ecanvas",this,800,800);//hpage,800,800);
// fEcanvas->Resize();
// fEcanvas->GetCanvas()->Update();
//AddFrame(fEcanvas, new TGLayoutHints(kLHintsBottom | kLHintsCenterX | kLHintsExpandX | kLHintsExpandY, 10,10,10,10));
// // hpage->
fdock->AddFrame(fEcanvas, new TGLayoutHints(kLHintsBottom | kLHintsCenterX | kLHintsExpandX | kLHintsExpandY, 10,10,10,10));
fEcanvas->MapWindow();
acq->setCanvas(getCanvas());
hpage->MapSubwindows();
mtab->Connect("Selected(Int_t)","ctbMain",this,"tabSelected(Int_t)");
cout << "connect mtab" << endl;
try{
setReadoutMode(pat->getReadoutMode());
} CATCH_DISPLAY ("Could not get readout flags", "ctbPattern::getReadoutMode")
setADCEnable(adcs->setEnable());
setAnalogSamples(pat->getAnalogSamples());
setDigitalSamples(pat->getDigitalSamples());
tabSelected(0);
SetWindowName("CTB Gui");
MapSubwindows();
Resize(1500,1200);
MapWindow();
}
void ctbMain::CloseWindow() {
gApplication->Terminate();
}
TCanvas* ctbMain::getCanvas() {
return fEcanvas->GetCanvas();
}
void ctbMain::HandleMenu(Int_t id)
{
// Handle menu items.
switch (id) {
case 0: // fMenuFile->AddEntry("Open Alias", im++);
cout << "Open Alias" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
printf("Open file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
loadAlias(fi.fFilename);
}
break;
case 1: // fMenuFile->AddEntry("Save Alias", im++);
cout << "Save Alias" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDSave, &fi);
printf("Save file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
saveAlias(fi.fFilename);
}
break;
case 2: //fMenuFile->AddEntry("Open Parameters", im++);
cout << "Open Parameters" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
printf("Open file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
loadParameters(fi.fFilename);
}
break;
case 3: // fMenuFile->AddEntry("Open Configuration", im++);
cout << "Open configuration" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
printf("Open file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
loadConfiguration(fi.fFilename);
}
break;
case 4: //fMenuFile->AddEntry("Open Pattern", im++);
cout << "Open pattern" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
printf("Open file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
loadParameters(fi.fFilename);
}
break;
case 5: //fMenuFile->AddEntry("Save Pattern", im++);
cout << "Save pattern" << endl;
{
static TString dir(".");
TGFileInfo fi;
//fi.fFileTypes = filetypes;
fi.fIniDir = StrDup(dir);
printf("fIniDir = %s\n", fi.fIniDir);
new TGFileDialog(gClient->GetRoot(), this, kFDSave, &fi);
printf("Open file: %s (dir: %s)\n", fi.fFilename, fi.fIniDir);
// dir = fi.fIniDir;
if (fi.fFilename)
savePattern(fi.fFilename);
}
break;
case 6: // fMenuFile->AddEntry("Exit", im++);
CloseWindow();
default:
printf("Menu item %d selected\n", id);
break;
}
}
int ctbMain::setADCPlot(Int_t i) {
// cout << "ADC " << i << " plot or color toggled" << endl;
// acq->setGraph(i,adcs->getGraph(i));
acq->setGraph(i,adcs->getEnabled(i),adcs->getColor(i));
return -1;
}
int ctbMain::setSignalPlot(Int_t i) {
// cout << "ADC " << i << " plot or color toggled" << endl;
// acq->setGraph(i,adcs->getGraph(i));
acq->setBitGraph(i,sig->getPlot(i),sig->getColor(i));
return -1;
}
void ctbMain::loadConfiguration(string fname) {
try{
myDet->loadConfig(fname);
} CATCH_DISPLAY ("Could not load config.", "ctbMain::loadConfiguration")
}
void ctbMain::loadParameters(string fname) {
try{
myDet->loadParameters(fname);
} CATCH_DISPLAY ("Could not load parameters.", "ctbMain::loadParameters")
}
void ctbMain::savePattern(string fname) {
try{
myDet->savePattern(fname);
} CATCH_DISPLAY ("Could not save pattern.", "ctbMain::savePattern")
}
int ctbMain::loadAlias(string fname) {
string line;
char aaaa[1000];
int i;
ifstream myfile (fname.c_str());
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
// cout << line ;
if (sscanf(line.c_str(),"BIT%d",&i)>0) {
//cout << "*******" << line<< endl;
sig->setSignalAlias(line);
// cout << line ;
} else if (sscanf(line.c_str(),"DAC%d",&i)>0) {
dacs->setDacAlias(line);
// cout << "+++++++++" << line<< endl;
} else if (sscanf(line.c_str(),"ADC%d",&i)>0) {
adcs->setAdcAlias(line);
// cout << "---------" << line<< endl;
} // else
// cout << "<<<<<<<" << line << endl;
else if (sscanf(line.c_str(),"PAT%s",aaaa)>0) {
pat->setPatternAlias(line);
// cout << "---------" << line<< endl;
} else if (sscanf(line.c_str(),"V%s",aaaa)>0) {
if (pwrs) pwrs->setPwrAlias(line);
// cout << "+++++++++" << line<< endl;
} else if (sscanf(line.c_str(),"SENSE%d",&i)>0) {
if (senses) senses->setSlowAdcAlias(line);
// cout << "+++++++++" << line<< endl;
}
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
int ctbMain::saveAlias(string fname) {
string line;
ofstream myfile (fname.c_str());
if (myfile.is_open())
{
//while ( getline (myfile,line) )
// {
// cout << line ;
//if (sscanf(line.c_str(),"BIT%d",&i)>0) {
//cout << "*******" << line<< endl;
myfile << sig->getSignalAlias();
// cout << line ;
// } else if (sscanf(line.c_str(),"DAC%d",&i)>0) {
myfile << dacs->getDacAlias();
if (pwrs) myfile << pwrs->getPwrAlias();
if (senses) myfile << senses->getSlowAdcAlias();
// cout << "+++++++++" << line<< endl;
// } else if (sscanf(line.c_str(),"ADC%d",&i)>0) {
myfile << adcs->getAdcAlias();
// cout << "---------" << line<< endl;
// } // else
// cout << "<<<<<<<" << line << endl;
myfile << pat->getPatternAlias();
//}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
void ctbMain::tabSelected(Int_t i) {
// cout << "Selected tab " << i << endl;
// cout << "Current tab is " << mtab->GetCurrent() << endl;
if (i==i_dacs) dacs->update();
else if (i==i_pwrs) pwrs->update();
else if (i==i_senses) ;//senses->update();
else if (i==i_sig) sig->update();
else if (i==i_adcs) adcs->update();
else if (i==i_pat) pat->update();
else if (i==i_acq) acq->update();
else if (i==i_acq) acq->update();
// else if (i==i_actions) actions->update();
else cout << "Unknown tab " << i << endl;
}
void ctbMain::setPatternFile(const char* t) {
acq->setPatternFile(t);
}
void ctbMain::setPatternCompiler(const char* t) {
acq->setPatternCompiler(t);
}
void ctbMain::setAnalogSamples(const int n) {
acq->setAnalogSamples(n);
}
void ctbMain::setDigitalSamples(const int n) {
acq->setDigitalSamples(n);
}
void ctbMain::setReadoutMode(int flags) {
acq->setReadoutMode(flags);
}
void ctbMain::setADCEnable(Int_t reg){
acq->setADCEnable(reg);
}

View File

@ -1,130 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBMAIN_H
#define CTBMAIN_H
#include <TGFrame.h>
class TRootEmbeddedCanvas;
class TGButtonGroup;
class TGVerticalFrame;
class TGHorizontalFrame;
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TH2F;
class TGComboBox;
class TGCheckButton;
class THStack;
class TGraphErrors;
class TGTextButton;
class TGTab;
class TGMenuBar;
class TGPopupMenu;
class TGDockableFrame;
class TGLayoutHints;
class TGCanvas;
class TCanvas;
class ctbDacs;
class ctbSlowAdcs;
class ctbPowers;
class ctbSignals;
namespace sls
{
class Detector;
};
class ctbPattern;
class ctbAdcs;
class ctbAcquisition;
//class ctbActions;
#include <string>
using namespace std;
class ctbMain : public TGMainFrame {
private:
sls::Detector *myDet;
TRootEmbeddedCanvas *fEcanvas;
TRootEmbeddedCanvas *fModulecanvas;
TGButtonGroup *br;
TGTab *mtab;
ctbDacs *dacs;
int i_dacs;
ctbPowers *pwrs;
int i_pwrs;
ctbSlowAdcs *senses;
int i_senses;
ctbSignals *sig;
int i_sig;
ctbAdcs *adcs;
int i_adcs;
ctbPattern *pat;
int i_pat;
ctbAcquisition *acq;
int i_acq;
// ctbActions *actions;
int i_actions;
TGDockableFrame *fMenuDock;
TGMenuBar *fMenuBar;
TGPopupMenu *fMenuFile, *fMenuTest, *fMenuView, *fMenuHelp;
TGPopupMenu *fCascadeMenu, *fCascade1Menu, *fCascade2Menu;
TGPopupMenu *fMenuNew1, *fMenuNew2;
TGLayoutHints *fMenuBarLayout, *fMenuBarItemLayout, *fMenuBarHelpLayout;
TGCanvas *myCanvas;
public:
ctbMain(const TGWindow *p, sls::Detector *det);
int loadAlias(string fname);
int saveAlias(string fname);
void loadParameters(string fname);
void savePattern(string fname);
void loadConfiguration(string fname);
void tabSelected(Int_t);
int setADCPlot(Int_t);
int setSignalPlot(Int_t);
void CloseWindow();
void setPatternFile(const char* t);
void setPatternCompiler(const char* t);
void setAnalogSamples(const int);
void setDigitalSamples(const int);
void setReadoutMode(int);
void setADCEnable(Int_t);
void HandleMenu(Int_t);
TCanvas* getCanvas();
ClassDef(ctbMain,0)
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,181 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBPATTERN_H
#define CTBPATTERN_H
#include <TGFrame.h>
#define NLOOPS 3
#define NWAITS 3
#define NADCS 32
#define PATLEN 1024
class TRootEmbeddedCanvas;
class TGButtonGroup;
class TGVerticalFrame;
class TGHorizontalFrame;
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TH2F;
class TGComboBox;
class TGCheckButton;
class TGTextEntry;
class TGCheckButton;
class THStack;
class TGraphErrors;
class energyCalibration;
class TGTextButton;
class TGTab;
namespace sls
{
class Detector;
};
#include <string>
using namespace std;
class ctbLoop : public TGHorizontalFrame {
private:
TGNumberEntry *eLoopStartAddr;
TGNumberEntry *eLoopStopAddr;
TGNumberEntry *eLoopNumber;
int id;
sls::Detector *myDet;
public:
ctbLoop(TGGroupFrame *page, int i,sls::Detector *det);
void setNLoops();
void update();
ClassDef(ctbLoop,0)
};
class ctbWait : public TGHorizontalFrame {
private:
TGNumberEntry *eWaitAddr;
TGNumberEntry *eWaitTime;
int id;
sls::Detector *myDet;
public:
ctbWait(TGGroupFrame *page, int i,sls::Detector *det);
void setWaitTime();
void update();
ClassDef(ctbWait,0)
};
class ctbPattern : public TGGroupFrame {
private:
TGNumberEntry *eAdcClkFreq;
TGNumberEntry *eRunClkFreq;
TGNumberEntry *eDBitClkFreq;
TGNumberEntry *eAdcClkPhase;
TGNumberEntry *eDBitClkPhase;
//TGNumberEntry *eRunClkPhase;
TGNumberEntry *eStartAddr;
TGNumberEntry *eStopAddr;
TGNumberEntry *eFrames;
TGNumberEntry *ePeriod;
TGNumberEntry *eTriggers;
// TGNumberEntry *eMeasurements;
TGNumberEntry *eAdcPipeline;
TGNumberEntry *eDBitPipeline;
ctbLoop *eLoop[NLOOPS];
ctbWait *eWait[NWAITS];
TGTextEntry *patternCompiler;
TGTextEntry *patternFile;
TGTextButton *browseCompiler;
TGTextButton *browseFile;
TGNumberEntry *eAnalogSamples;
TGNumberEntry *eDigitalSamples;
TGCheckButton *cbAnalog;
TGCheckButton *cbDigital;
char pat[PATLEN*8];
sls::Detector *myDet;
public:
ctbPattern(TGVerticalFrame *page, sls::Detector *det);
void update();
void setAdcFreq();
void setRunFreq();
void setDBitFreq();
void setAdcPhase();
void setDBitPhase();
// void setRunPhase();
void setAdcPipeline();
void setDBitPipeline();
void setFrames();
void setTriggers();
// void setMeasurements();
void setPeriod();
void chooseCompiler();
void choosePattern();
string getCompiler();
string getPatternFile();
void setPatternAlias(string);
string getPatternAlias();
int getAnalogSamples();
void setAnalogSamples();
int getDigitalSamples();
void setDigitalSamples();
void setReadoutMode(Bool_t);
int getReadoutMode();
void setFile();
void setCompiler();
void patternFileChanged(const char*);
void patternCompilerChanged(const char*);
void analogSamplesChanged(const int t);
void digitalSamplesChanged(const int t);
void readoutModeChanged(int);
ClassDef(ctbPattern,0)
};
#endif

View File

@ -1,225 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <TGFrame.h>
#include <TGButtonGroup.h>
#include <TGNumberEntry.h>
#include <TGLabel.h>
#include <TList.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "ctbDefs.h"
#include "ctbDacs.h"
#include "ctbPowers.h"
#include "sls/Detector.h"
#include "sls/sls_detector_defs.h"
using namespace std;
ctbPower::ctbPower(TGGroupFrame* f, int i, sls::Detector* d)
: ctbDac(f, i, d)
{
cout << "****************************************************************power " << i << endl;
dacsUnit->SetOn(kTRUE);
dacsUnit->SetEnabled(kFALSE);
switch(i) {
case slsDetectorDefs::V_POWER_IO:
dacsLabel->SetText("VIO");
break;
case slsDetectorDefs::V_POWER_A:
dacsLabel->SetText("VA");
break;
case slsDetectorDefs::V_POWER_B:
dacsLabel->SetText("VB");
break;
case slsDetectorDefs::V_POWER_C:
dacsLabel->SetText("VC");
break;
case slsDetectorDefs::V_POWER_D:
dacsLabel->SetText("VD");
break;
case slsDetectorDefs::V_POWER_CHIP:
dacsLabel->SetText("VCHIP");
dacsLabel->SetEnabled(kFALSE);
break;
default:
dacsLabel->SetText("Bad index");
break;
};
TGTextEntry *e=dacsEntry->TGNumberEntry::GetNumberEntry();
e->Disconnect ("ReturnPressed()");
e->Disconnect ("ValueSet(Long_t)");
e->Connect("ReturnPressed()","ctbPower",this,"setValue()");
dacsEntry->Connect("ValueSet(Long_t)","ctbPower",this,"setValue(Long_t)");
};
string ctbPower::getLabel() {
ostringstream line;
switch (id) {
case slsDetectorDefs::V_POWER_IO:
line << "VIO";
break;
case slsDetectorDefs::V_POWER_A:
line << "VA";
break;
case slsDetectorDefs::V_POWER_B:
line << "VB";
break;
case slsDetectorDefs::V_POWER_C:
line << "VC";
break;
case slsDetectorDefs::V_POWER_D:
line << "VD";
break;
case slsDetectorDefs::V_POWER_CHIP:
line << "VCHIP";
break;
default:
line << "VBAD";
break;
}
line << " " << dacsLabel->GetText() << endl;
return line.str();
}
void ctbPower::setValue(Long_t a) {ctbPower::setValue();}
void ctbPower::setValue() {
cout << "***************************Setting power " << dacsEntry->GetIntNumber() << " " << id << " " << 1 << endl;
try {
myDet->setVoltage(static_cast<slsDetectorDefs::dacIndex>(id), dacsEntry->GetIntNumber());
} CATCH_DISPLAY ("Could not set power " + to_string(id) + ".", "ctbPower::setValue")
getValue();
}
int ctbPower::getValue() {
try {
int val = myDet->getVoltage(static_cast<slsDetectorDefs::dacIndex>(id)).tsquash("Different values");
cout << "****************************Getting power " << val << " " << id << " " << 1 << endl;
dacsValue->SetText(to_string(val).c_str());
if (val > 0) {
if (id != static_cast<int>(slsDetectorDefs::V_POWER_CHIP))
dacsLabel->SetOn(kTRUE);
} else {
dacsLabel->SetOn(kFALSE);
}
return val;
} CATCH_DISPLAY ("Could not get power " + to_string(id) + ".", "ctbPower::getValue")
return -1;
}
ctbPowers::ctbPowers(TGVerticalFrame* page, sls::Detector* det) : TGGroupFrame(page,"Power Supplies",kVerticalFrame) , myDet(det){
SetTitlePos(TGGroupFrame::kLeft);
page->AddFrame(this,new TGLayoutHints( kLHintsTop | kLHintsExpandX , 10,10,10,10));
MapWindow();
// cout << "window mapped " << endl;
for (int idac=0; idac<NPOWERS; idac++) {
dacs[idac]=new ctbPower(this, slsDetectorDefs::V_POWER_A+idac, myDet);
}
}
int ctbPowers::setPwrAlias(string line) {
int is=-1;
char tit[100];
if (sscanf(line.c_str(),"VA %s",tit)) {
dacs[0]->setLabel(tit,1);
is=0;
}
if (sscanf(line.c_str(),"VB %s",tit)) {
dacs[1]->setLabel(tit,1);
is=1;
}
if (sscanf(line.c_str(),"VC %s",tit)) {
dacs[2]->setLabel(tit,1);
is=2;
}
if (sscanf(line.c_str(),"VD %s",tit)) {
dacs[3]->setLabel(tit,1);
is=3;
}
if (sscanf(line.c_str(),"VIO %s",tit)) {
dacs[4]->setLabel(tit,1);
is=4;
}
if (sscanf(line.c_str(),"VCHIP %s",tit)) {
dacs[5]->setLabel(tit,1);
is=5;
}
return is;
}
string ctbPowers::getPwrAlias() {
ostringstream line;
for (int i=0; i<NPOWERS; i++)
line << dacs[i]->getLabel() << endl;
return line.str();
}
string ctbPowers::getPwrParameters() {
ostringstream line;
line << "v_a" << " " << dacs[0]->getValue() << " mv" << endl;
line << "v_b" << " " << dacs[1]->getValue() << " mv" << endl;
line << "v_c" << " " << dacs[2]->getValue() << " mv" << endl;
line << "v_d" << " " << dacs[3]->getValue() << " mv" << endl;
line << "v_io" << " " << dacs[4]->getValue() << " mv" << endl;
line << "v_chip" << " " << dacs[5]->getValue() << " mv" << endl;
// for (int i=0; i<POWERS; i++) {
// //line << "dacs:" << i << " " << dacs[i]->getValue << endl;
// line << "dac:" << i << " " << dacs[i]->getValue() << endl;
// }
return line.str();
}
void ctbPowers::update() {
for (int idac=0; idac<NPOWERS; idac++) {
dacs[idac]->getValue();
}
}

View File

@ -1,69 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBPOWERS_H
#define CTBPOWERS_H
#include <TGFrame.h>
#define NPOWERS 6
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TGCheckButton;
namespace sls
{
class Detector;
};
#include <string>
using namespace std;
class ctbPower : public ctbDac {
public:
ctbPower(TGGroupFrame* f, int i, sls::Detector* d);
string getLabel();
int getValue();
void setValue();
void setValue(Long_t);
ClassDef(ctbPower,0)
};
class ctbPowers : public TGGroupFrame
{
private:
ctbPower *dacs[NPOWERS];
sls::Detector* myDet;
public:
//ctbPowers();
ctbPowers(TGVerticalFrame*, sls::Detector*);
int setPwrAlias(string);
string getPwrAlias();
string getPwrParameters();
void update();
ClassDef(ctbPowers,0)
};
#endif

View File

@ -1,543 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <TApplication.h>
#include <TGClient.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TRandom.h>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <TGButtonGroup.h>
#include <TGNumberEntry.h>
#include <TGLabel.h>
#include <TList.h>
#include <TGFileDialog.h>
#include <TGComboBox.h>
#include <TH2F.h>
#include <TColor.h>
#include <TH1F.h>
#include <TGraphErrors.h>
#include <THStack.h>
#include <TGTab.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <TGButtonGroup.h>
#include <TGNumberEntry.h>
#include <TGLabel.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <TColor.h>
#include <TGColorSelect.h>
#include "ctbSignals.h"
#include "ctbDefs.h"
#include "sls/Detector.h"
using namespace std;
//#define DEFAULTFN "run_0.encal"
ctbSignal::ctbSignal(TGFrame *page, int i, sls::Detector *det)
: TGHorizontalFrame(page, 800,50), myDet(det), id(i), hsig(NULL) {
TGHorizontalFrame *hframe=this;
char tit[100];
sprintf(tit, "BIT%d ",id);
sLabel= new TGLabel(hframe, tit);
hframe->AddFrame( sLabel,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sLabel->MapWindow();
sLabel->SetTextJustify(kTextLeft);
sOutput= new TGCheckButton(hframe, "Out");
hframe->AddFrame( sOutput,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sOutput->MapWindow();
sOutput->Connect("Toggled(Bool_t)","ctbSignal",this,"ToggledOutput(Bool_t)");
sDbitList= new TGCheckButton(hframe, "DB List");
hframe->AddFrame( sDbitList,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sDbitList->MapWindow();
sDbitList->Connect("Toggled(Bool_t)","ctbSignal",this,"ToggledDbitList(Bool_t)");
sPlot= new TGCheckButton(hframe, "Plot");
hframe->AddFrame( sPlot,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
sPlot->MapWindow();
sPlot->Connect("Toggled(Bool_t)","ctbSignal",this,"ToggledPlot(Bool_t)");
fColorSel = new TGColorSelect(hframe, id+1, 0);
fColorSel->Connect("ColorSelected(Pixel_t)","ctbSignal",this,"ColorChanged(Pixel_t)");
hframe->AddFrame(fColorSel, new TGLayoutHints(kLHintsTop |
kLHintsLeft, 2, 0, 2, 2));
fColorSel->SetColor(TColor::Number2Pixel(id+1));
ToggledOutput(kFALSE);
ToggledPlot(kFALSE);
// if (id==63) {
// sOutput->SetOn(kTRUE);
// sOutput->SetEnabled(kFALSE);
// }
// #ifdef CTB
// if (id==62) {
// sOutput->SetOn(kTRUE);
// sOutput->SetEnabled(kFALSE);
// }
// // if (id>=32 && id<48)
// // fixOutput(1);
// // else if (id>=48 && id<64)
// // fixOutput(0);
// #endif
}
int ctbSignal::setSignalAlias(char *tit, int plot, int col) {
if (tit)
sLabel->SetText(tit);
if (plot>0) {
sPlot->SetOn(kTRUE,kTRUE);
} else if (plot==0)
sPlot->SetOn(kFALSE,kTRUE);
if (col>=0)
fColorSel->SetColor(col);//TColor::Number2Pixel(col+1));
fColorSel->SetEnabled(sPlot->IsOn());
return 0;
}
string ctbSignal::getSignalAlias() {
ostringstream oss;
oss << "BIT" << dec << id << " " << sLabel->GetText()->Data() << " " << sPlot->IsOn() << hex << " " << fColorSel->GetColor() << endl;
return oss.str();
}
int ctbSignal::setOutput(Long64_t r) {
// cout << hex << r << dec <<endl;
Long64_t mask=((Long64_t)1<<id);
if (r&mask)
sOutput->SetOn(kTRUE,kTRUE);
else
sOutput->SetOn(kFALSE,kTRUE);
return sOutput->IsOn();
}
int ctbSignal::fixOutput(int i) {
if (i) {
sPlot->SetOn(kFALSE);
//sClock->SetOn(kFALSE,kTRUE);
sOutput->SetOn(kTRUE);
// sPlot->SetEnabled(kFALSE);
// sClock->SetEnabled(kTRUE);
} else {
sOutput->SetOn(kFALSE,kTRUE);
// sClock->SetOn(kFALSE);
// sClock->SetEnabled(kFALSE);
sPlot->SetEnabled(kTRUE);
}
sOutput->SetEnabled(kFALSE);
return 0;
}
int ctbSignal::setDbitList(Long64_t r) {
if (r)
sDbitList->SetOn(kTRUE,kFALSE);
else
sDbitList->SetOn(kFALSE,kFALSE);
return sDbitList->IsOn();
}
int ctbSignal::isDbitList() { return sDbitList->IsOn();}
int ctbSignal::isOutput() { return sOutput->IsOn();}
int ctbSignal::isPlot() { return sPlot->IsOn();}
Pixel_t ctbSignal::getColor(){return fColorSel->GetColor();}
void ctbSignal::ToggledOutput(Bool_t b) {
ToggledSignalOutput(id);
if (b) {
// sClock->SetEnabled(kTRUE);
sPlot->SetOn(kFALSE);
// sPlot->SetEnabled(kFALSE);
fColorSel->SetEnabled(kFALSE);
} else {
// sClock->SetEnabled(kFALSE);
// sClock->SetOn(kFALSE);
sPlot->SetEnabled(kTRUE);
if ( sPlot->IsOn())
fColorSel->SetEnabled(kFALSE);
else
fColorSel->SetEnabled(kTRUE);
}
}
void ctbSignal::ToggledDbitList(Bool_t b){
Long_t mask=id;
ToggledSignalDbitList(mask);
}
void ctbSignal::ToggledPlot(Bool_t b){
Long_t mask=b<<id;
ToggledSignalPlot(mask);
fColorSel->SetEnabled(b);
}
void ctbSignal::ColorChanged(Pixel_t p){
ToggledSignalPlot(id);
}
void ctbSignal::ToggledSignalOutput(Int_t b) {
cout << "Toggle signal " << id << " " << b << " " << sOutput->IsOn() <<endl;;
Emit("ToggledSignalOutput(Int_t)", id);
}
void ctbSignal::ToggledSignalDbitList(Int_t b){
cout << "Toggle dbitlist " << id << " " << b << endl;;
Emit("ToggledSignalDbitList(Int_t)", id);
}
void ctbSignal::ToggledSignalPlot(Int_t b){
Emit("ToggledSignalPlot(Int_t)", id);
}
ctbSignals::ctbSignals(TGVerticalFrame *page, sls::Detector *det)
: TGGroupFrame(page,"IO Signals",kVerticalFrame), myDet(det) {
SetTitlePos(TGGroupFrame::kLeft);
page->AddFrame(this,new TGLayoutHints( kLHintsTop | kLHintsExpandX , 10,10,10,10));
MapWindow();
TGHorizontalFrame *hframe;
TGHorizontalFrame* hhframe=new TGHorizontalFrame(this, 800,800);
AddFrame(hhframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hhframe->MapWindow();
TGVerticalFrame *vframe;
int idac=0;
for (idac=0; idac<NSIGNALS; idac++) {
if (idac%((NSIGNALS+2)/2)==0) {
vframe=new TGVerticalFrame(hhframe, 400,800);
hhframe->AddFrame(vframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
vframe->MapWindow();
}
signals[idac]=new ctbSignal(vframe,idac,myDet);
signals[idac]->Connect("ToggledSignalOutput(Int_t)","ctbSignals",this,"ToggledOutReg(Int_t)");
signals[idac]->Connect("ToggledSignalDbitList(Int_t)","ctbSignals",this,"ToggledDbitList(Int_t)");
signals[idac]->Connect("ToggledSignalPlot(Int_t)","ctbSignals",this,"ToggledPlot(Int_t)");
vframe->AddFrame(signals[idac],new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
signals[idac]->MapWindow();
}
hframe=new TGHorizontalFrame(vframe, 800,50);
vframe->AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
TGLabel *label= new TGLabel(hframe, "IO Control Register: ");
hframe->AddFrame(label,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
label->MapWindow();
label->SetTextJustify(kTextLeft);
eIOCntrlRegister = new TGNumberEntry(hframe, 0, 16,999, TGNumberFormat::kNESHex,
TGNumberFormat::kNEANonNegative,
TGNumberFormat::kNELNoLimits);
hframe->AddFrame(eIOCntrlRegister,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1));
eIOCntrlRegister->MapWindow();
eIOCntrlRegister->Resize(150,30);
hframe=new TGHorizontalFrame(vframe, 800,50);
vframe->AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
hframe->MapWindow();
label= new TGLabel(hframe, "DBit Offset: ");
hframe->AddFrame(label,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1));
label->MapWindow();
label->SetTextJustify(kTextLeft);
eDbitOffset = new TGNumberEntry(hframe, 0, 9,999, TGNumberFormat::kNESInteger,
TGNumberFormat::kNEANonNegative,
TGNumberFormat::kNELNoLimits);
hframe->AddFrame(eDbitOffset,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1));
eDbitOffset->MapWindow();
eDbitOffset->Resize(150,30);
TGTextEntry *e= eDbitOffset->TGNumberEntry::GetNumberEntry();
e->Connect("ReturnPressed()","ctbSignals",this,"setDbitOffset()");
e->Connect("ValueSet(Long_t)","ctbSignals",this,"setDbitOffset(Long_t)");
}
int ctbSignals::setSignalAlias(string line) {
int is=-1, plot=0, col=-1;
char tit[100];
int narg=sscanf(line.c_str(),"BIT%d %s %d %d",&is,tit,&plot,&col);
if (narg<2)
return -1;
if (is>=0 && is<NIOSIGNALS) {
signals[is]->setSignalAlias(tit,plot,col);
}
return is;
}
string ctbSignals::getSignalAlias() {
ostringstream oss;
for (int is=0; is<NIOSIGNALS; is++)
oss << signals[is]->getSignalAlias() << endl;
return oss.str();
}
void ctbSignals::update() {
try {
Long64_t oreg = static_cast<Long64_t>(myDet->getPatternIOControl().tsquash("Different values"));
cout << hex << oreg << dec << endl;
for (int idac=0; idac<NIOSIGNALS; idac++) {
signals[idac]->setOutput(oreg);
}
} CATCH_DISPLAY ("Could not get patternIOcontrol.", "ctbSignals::update")
if (myDet->getDetectorType().squash() == slsDetectorDefs::MOENCH) {
// enable all
for (int is=0; is<64; is++) {
signals[is]->setDbitList(1);
}
eDbitOffset->SetNumber(0);
}
// ctb
else {
try {
auto dbitlist = myDet->getRxDbitList().tsquash("Different values");
// enable all
if (dbitlist.empty()) {
for (int is=0; is<64; is++) {
signals[is]->setDbitList(1);
}
}
else {
// disable all
for (int is=0; is<64; is++) {
signals[is]->setDbitList(0);
}
// enable selected
for (const auto &value : dbitlist) {
signals[value]->setDbitList(1);
}
}
} CATCH_DISPLAY ("Could not get receiver dbit list.", "ctbSignals::update")
try {
auto val = myDet->getRxDbitOffset().tsquash("Different values");
eDbitOffset->SetNumber(val);
} CATCH_DISPLAY ("Could not get receiver dbit offset.", "ctbSignals::update")
}
}
string ctbSignals::getSignalParameters() {
try {
auto val = myDet->getPatternIOControl().tsquash("Different values");
ostringstream line;
line << "patioctrl " << hex << val << dec << endl;
return line.str();
} CATCH_DISPLAY ("Could not get patternIOcontrol.", "ctbSignals::getSignalParameters")
return ("");
}
void ctbSignals::ToggledOutReg(Int_t mask) {
try {
Long64_t oreg = static_cast<Long64_t>(myDet->getPatternIOControl().tsquash("Different values"));
Long64_t m=((Long64_t)1)<<mask;
cout << dec << sizeof(Long64_t) << " " << mask << " " << hex << m << " ioreg " << oreg;
if (signals[mask]->isOutput()) {
cout << " or " << m ;
oreg|=m;
} else {
cout << " not " << ~m ;
oreg&=~m;
}
cout << " after " << oreg << endl;
myDet->setPatternIOControl(static_cast<uint64_t>(oreg));
oreg = static_cast<Long64_t>(myDet->getPatternIOControl().tsquash("Different values"));
cout << dec << sizeof(Long64_t) << " " << mask << " " << hex << m << " ioreg " << oreg << endl;
eIOCntrlRegister->SetText(to_string(oreg).c_str());
} CATCH_DISPLAY ("Could not get/set patternIOcontrol.", "ctbSignals::ToggledOutReg")
}
void ctbSignals::ToggledDbitList(Int_t mask){
try {
auto dbitlist = myDet->getRxDbitList().tsquash("Different values");
// anyway all enabled
if ((dbitlist.empty()) && (signals[mask]->isDbitList())) {
;
}
// set the dbitlist
else {
std::vector <int> new_dbitlist;
for (int is=0; is<64; is++) {
if (signals[is]->isDbitList()){
new_dbitlist.push_back(is);
cout << is << " " << new_dbitlist.size() - 1 << endl;
}
}
if (new_dbitlist.size() > 64)
new_dbitlist.clear();
myDet->setRxDbitList(new_dbitlist);
// get list again
dbitlist = myDet->getRxDbitList().tsquash("Different values");
}
// enable all
if (dbitlist.empty()) {
for (int is=0; is<64; is++) {
signals[is]->setDbitList(1);
}
}
else {
// disable all
for (int is=0; is<64; is++) {
signals[is]->setDbitList(0);
}
// enable selected
for (const auto &value : dbitlist) {
signals[value]->setDbitList(1);
}
}
} CATCH_DISPLAY ("Could not get/set receiver dbit list.", "ctbSignals::ToggledDbitList")
}
void ctbSignals::ToggledPlot(Int_t b) {
Emit("ToggledSignalPlot(Int_t)", b);
}
void ctbSignals::ToggledSignalPlot(Int_t b) {
Emit("ToggledSignalPlot(Int_t)", b);
}
Pixel_t ctbSignals::getColor(int i){
if (i>=0 && i<NSIGNALS)
return signals[i]->getColor();
return static_cast<Pixel_t>(-1);
}
int ctbSignals::getPlot(int i){
if (i>=0 && i<NSIGNALS)
return signals[i]->isPlot();
return -1;
};
void ctbSignals::setDbitOffset(Long_t) {
setDbitOffset();
}
void ctbSignals::setDbitOffset(){
try {
myDet->setRxDbitOffset(eDbitOffset->GetNumber());
} CATCH_DISPLAY ("Could not set receiver dbit offset.", "ctbSignals::setDbitOffset")
}

View File

@ -1,123 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBSIGNALS_H
#define CTBSIGNALS_H
#include <TGFrame.h>
#define NSIGNALS 64
#define NIOSIGNALS 64 //for moench board was 52
#define ADCLATCH 63
#define DIGSIGLATCH 62
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TGCheckButton;
class TH1I;
class TGTextButton;
class TGColorSelect;
class TGNumberEntry;
namespace sls
{
class Detector;
};
class ctbSignal;
#include <string>
using namespace std;
class ctbSignal : public TGHorizontalFrame {
// RQ_OBJECT("ctbSignal")
private:
TGLabel *sLabel;
TGCheckButton *sOutput;
TGCheckButton *sDbitList;
TGCheckButton *sPlot;
TGLabel *sValue;
TGNumberEntry *sEntry;
TGColorSelect *fColorSel;
sls::Detector *myDet;
Int_t id;
TH1I *hsig;
public:
ctbSignal(TGFrame *page, int i, sls::Detector *det);
int setSignalAlias(char *tit, int plot, int col);
string getSignalAlias();
TH1I *getPlot() {return hsig;};
int setOutput(Long64_t);
int fixOutput(int);
int setDbitList(Long64_t);
void ToggledOutput(Bool_t);
void ToggledDbitList(Bool_t);
void ToggledPlot(Bool_t);
void ColorChanged(Pixel_t);
int isDbitList();
int isOutput();
int isPlot();
Pixel_t getColor();
void ToggledSignalOutput(Int_t); //*SIGNAL*
void ToggledSignalDbitList(Int_t); //*SIGNAL*
void ToggledSignalPlot(Int_t); //*SIGNAL*
ClassDef(ctbSignal,0)
};
class ctbSignals : public TGGroupFrame {
private:
ctbSignal *signals[NSIGNALS];
TGNumberEntry *eIOCntrlRegister;
TGNumberEntry *eDbitOffset;
sls::Detector *myDet;
public:
ctbSignals(TGVerticalFrame *page, sls::Detector *det);
int setSignalAlias(string line);
string getSignalAlias();
int getPlot(int);
Pixel_t getColor(int);
void update();
// void saveParameters();
string getSignalParameters();
//void setDbitList(Int_t);
void setDbitOffset(Long_t);
void setDbitOffset();
void ToggledOutReg(Int_t);
void ToggledDbitList(Int_t);
void ToggledPlot(Int_t);
void ToggledSignalPlot(Int_t); //*SIGNAL*
ClassDef(ctbSignals,0)
};
#endif

View File

@ -1,184 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <TGTextEntry.h>
#include <TGLabel.h>
#include <TGNumberEntry.h>
#include <TGButton.h>
#include "ctbSlowAdcs.h"
#include "ctbDefs.h"
#include "sls/Detector.h"
#include "sls/sls_detector_defs.h"
using namespace std;
ctbSlowAdc::ctbSlowAdc(TGGroupFrame *page, int idac, sls::Detector *det) : TGHorizontalFrame(page, 800,50) , id(idac), myDet(det) {
TGHorizontalFrame *hframe=this;
page->AddFrame(hframe,new TGLayoutHints(kLHintsTop | kLHintsExpandX , 1,1,1,1));
MapWindow();
char tit[100];
sprintf(tit, "SENSE %d:",idac-1000);
dacsLabel= new TGLabel(hframe, tit);// new TGLabel(hframe, tit);
hframe->AddFrame(dacsLabel,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
dacsLabel->MapWindow();
dacsLabel->SetTextJustify(kTextLeft);
sprintf(tit, "xxx");
dacsValue= new TGLabel(hframe, tit);
hframe->AddFrame( dacsValue,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
dacsValue->MapWindow();
dacsValue->SetTextJustify(kTextLeft);
TGTextButton *b= new TGTextButton(hframe, "Update");
hframe->AddFrame( b,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 5, 5, 5, 5));
b->MapWindow();
b->SetTextJustify(kTextLeft);
b->Connect("Clicked()","ctbSlowAdc",this,"getValue()");
}
int ctbSlowAdc::setLabel(char *tit) {
if(tit)
dacsLabel->SetText(tit);
return id;
}
string ctbSlowAdc::getLabel() {
ostringstream line;
line << dacsLabel->GetText() << endl;
// line << "DAC" << dec << id << " " << dacsUnit->IsOn() << endl;
return line.str();
}
int ctbSlowAdc::getValue() {
try {
std::string s;
// temp
if (id == static_cast<int>(slsDetectorDefs::SLOW_ADC_TEMP)) {
int val = myDet->getTemperature(static_cast<slsDetectorDefs::dacIndex>(id)).tsquash("Different values");
cout << "slow adc temp" << " " << val << endl;
s = to_string(val) + " " + to_string(0x00b0) + "C";//<2F>C
dacsValue->SetText(s.c_str());
return val;
}
// mv
else {
int val = myDet->getSlowADC(static_cast<slsDetectorDefs::dacIndex>(id)).tsquash("Different values");
cout << "slow adc " << id << " " << val << endl;
s = to_string(val) + " mV";
dacsValue->SetText(s.c_str());
return val;
}
} CATCH_DISPLAY ("Could not get slow dac " + to_string(id) + ".", "ctbSlowAdc::getValue")
return -1;
}
ctbSlowAdcs::ctbSlowAdcs(TGVerticalFrame *page, sls::Detector *det) : TGGroupFrame(page,"Sense",kVerticalFrame) , myDet(det){
SetTitlePos(TGGroupFrame::kLeft);
page->AddFrame(this,new TGLayoutHints( kLHintsTop | kLHintsExpandX , 10,10,10,10));
MapWindow();
// cout << "window mapped " << endl;
for (int idac=0; idac<NSLOWADCS + 1; idac++) {
adcs[idac]=new ctbSlowAdc(this, idac+1000, myDet);
}
adcs[NSLOWADCS]->setLabel((char*)"Temperature");
}
int ctbSlowAdcs::setSlowAdcAlias(string line) {
int is=-1, mv=0;
char tit[100];
int narg=sscanf(line.c_str(),"SENSE%d %s %d",&is,tit,&mv);
if (narg<2)
return -1;
if (is>=0 && is<NSLOWADCS)
adcs[is]->setLabel(tit);
return is;
}
string ctbSlowAdcs::getSlowAdcAlias() {
ostringstream line;
for (int i=0; i<NSLOWADCS; i++)
line << adcs[i]->getLabel() << endl;
return line.str();
}
string ctbSlowAdcs::getAdcParameters() {
ostringstream line;
for (int i=0; i<NSLOWADCS; i++) {
//line << "dacs:" << i << " " << dacs[i]->getValue << endl;
line << "adc:" << i << " " << adcs[i]->getValue() << endl;
}
line << "adc:-1" << adcs[NSLOWADCS]->getValue() << endl;
return line.str();
}
void ctbSlowAdcs::update() {
for (int idac=0; idac<NSLOWADCS+1; idac++) {
adcs[idac]->getValue();
}
}

View File

@ -1,80 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef CTBSLOWADCS_H
#define CTBSLOWADCS_H
#include <TGFrame.h>
//#define NDACS 16
#define NSLOWADCS 8
class TGTextEntry;
class TGLabel;
class TGNumberEntry;
class TGCheckButton;
class TGTextButton;
namespace sls
{
class Detector;
};
#include <string>
using namespace std;
class ctbSlowAdc : public TGHorizontalFrame {
protected:
// TGLabel *dacsLabel;
// TGNumberEntry *dacsEntry;
// TGCheckButton *dacsUnit;
TGLabel *dacsLabel;
TGLabel *dacsValue;
int id;
sls::Detector* myDet;
public:
ctbSlowAdc(TGGroupFrame*, int , sls::Detector*);
int getValue();
int setLabel(char *tit);
string getLabel();
ClassDef(ctbSlowAdc,0)
};
class ctbSlowAdcs : public TGGroupFrame {
private:
ctbSlowAdc *adcs[NSLOWADCS+1];
sls::Detector* myDet;
public:
ctbSlowAdcs(TGVerticalFrame *page, sls::Detector*);
int setSlowAdcAlias(string line);
// int setDacAlias(string line);
string getSlowAdcAlias();
string getAdcParameters();
void update();
ClassDef(ctbSlowAdcs,0)
};
#endif

View File

@ -890,7 +890,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS = */docs/* */tests/* */python/* */manual */slsDetectorServers/* */libs/* */integrationTests *README* */slsDetectorGui/* */ctbGui/* */slsDetectorCalibration/*
EXCLUDE_PATTERNS = */docs/* */tests/* */python/* */manual */slsDetectorServers/* */libs/* */integrationTests *README* */slsDetectorGui/* */ctbGui/* */slsDetectorCalibration/* *TobiSchluter*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the

View File

@ -32,14 +32,14 @@ Commands
.. include:: ../commands.rst
Depreciated commands
Deprecated commands
------------------------
.. note ::
All the dac commands are preceded with the **dac** command. Use command **daclist** to get correct list of dac command arguments for current detector.
.. csv-table:: Depreciated commands
:file: ../depreciated.csv
.. csv-table:: Deprecated commands
:file: ../deprecated.csv
:widths: 35, 35
:header-rows: 1

View File

@ -55,9 +55,9 @@ int main() {
fs << '\t' << cmd << usage << help << "\n";
}
std::ofstream fs2("depreciated.csv");
std::ofstream fs2("deprecated.csv");
fs2 << "Old, New\n";
auto cmds = proxy.GetDepreciatedCommands();
auto cmds = proxy.GetDeprecatedCommands();
for (auto it : cmds) {
fs2 << it.first << ", " << it.second << '\n';
}

View File

@ -9,4 +9,6 @@ slsDetectorPackage/8.0.0_rh7 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.0_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.1_rh7 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.1_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.2_rh7 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.2_rh8 stable cmake/3.15.5 Qt/5.12.10

View File

@ -0,0 +1,35 @@
name: Build inplace, run tests and linting
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ".[dev]"
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Build C extension
run: |
make
- name: Run tests using pytest
run: |
make test
- name: check code formatting
run: |
make check_format
- name: lint the code with ruff
run: |
make lint

133
pyctbgui/.gitignore vendored Normal file
View File

@ -0,0 +1,133 @@
nohup.out
.idea/
tests/.tmp
run_*
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View File

@ -0,0 +1,18 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/google/yapf
rev: v0.40.1
hooks:
- id: yapf
name: yapf
language: python
entry: yapf
args: [-i,--style,pyproject.toml]
types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.0.285
hooks:
- id: ruff

11
pyctbgui/CtbGui Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env python3
from PyQt5 import QtWidgets
import sys
from pyctbgui.ui import MainWindow
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec_()

2
pyctbgui/MANIFEST.in Normal file
View File

@ -0,0 +1,2 @@
include pyctbgui/ui/*.ui
recursive-include src *.c *.h

39
pyctbgui/Makefile Normal file
View File

@ -0,0 +1,39 @@
# TODO! Add support for making the pkg?
# Which tests should we have?
default: ext
ext: ## [DEFAULT] build c extension in place
rm -rf build/ pyctbgui/_decoder.cpython*
python setup.py build_ext --inplace
clean: ## Remove the build folder and the shared library
rm -rf build/ pyctbgui/_decoder.cpython*
test: ## Run unit tests using pytest
python -m pytest -v tests/unit
test_gui: ## Run E2E tests using pytest
python -m pytest -v tests/gui
setup_gui_test: ## Setup the environment for the E2E tests
ctbDetectorServer_virtual > /tmp/simulator.log 2>&1 &
slsReceiver > /tmp/slsReceiver.log 2>&1 &
sleep 3
sls_detector_put config tests/gui/data/simulator.config
killall: ## Kill all the processes started by setup_gui_test
killall slsReceiver ctbDetectorServer_virtual
lint: ## run ruff linter to check formatting errors
@ruff check tests pyctbgui *.py && echo "Ruff checks passed ✅"
format: ## format code inplace using style in pyproject.toml
yapf --style pyproject.toml -m -r -i tests pyctbgui *.py
check_format: ## Check if source is formatted properly
yapf --style pyproject.toml -r -d tests pyctbgui *.py
help: # from compiler explorer
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

31
pyctbgui/README.md Normal file
View File

@ -0,0 +1,31 @@
# New Chip Test Board Gui using Python
Prototype for a new python based GUI for the Chip Test Board
## Getting started
```bash
git clone https://github.com/slsdetectorgroup/pyctbgui.git
cd pyctbgui
make #compiles the c extension inplace
./CtbGui
```
## Display help for the Makefile
```
$ make help
check_format Check if source is formatted properly
clean Remove the build folder and the shared library
ext [DEFAULT] build c extension in place
format format code inplace using style in pyproject.toml
lint run ruff linter to check formatting errors
test Run unit tests using pytest
```
## setup pre-commit hooks
```
pre-commit install
```

73
pyctbgui/client.py Normal file
View File

@ -0,0 +1,73 @@
import json
import zmq
import numpy as np
from slsdet import Detector
import matplotlib.pyplot as plt
det = Detector()
zmqIp = det.zmqip
zmqport = det.zmqport
zmq_stream = det.rx_zmqstream
def zmq_receiver():
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect(f"tcp://{zmqIp}:{zmqport}")
socket.subscribe("")
while True:
msg = socket.recv_multipart()
if len(msg) == 2:
header, data = msg
jsonHeader = json.loads(header)
print(jsonHeader)
print(f'Data size: {len(data)}')
data_array = np.array(np.frombuffer(data, dtype=np.uint16))
break
return data_array
def analog(data_array):
adc_numbers = [
9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
25, 24
]
n_pixels_per_sc = 5000
sc_width = 25
analog_frame = np.zeros((400, 400))
order_sc = np.zeros((400, 400))
for n_pixel in range(n_pixels_per_sc):
#these_dbits = int(digital_data[n_pixel])
for i_sc, adc_nr in enumerate(adc_numbers):
# ANALOG
col = ((adc_nr % 16) * sc_width) + (n_pixel % sc_width)
if i_sc < 16:
row = 199 - int(n_pixel / sc_width)
else:
row = 200 + int(n_pixel / sc_width)
index_min = n_pixel * 32 + i_sc
pixel_value = data_array[index_min]
analog_frame[row, col] = pixel_value
order_sc[row, col] = i_sc
return analog_frame
fig, ax = plt.subplots()
data = analog(data_array=zmq_receiver())
im = ax.imshow(data)
ax.invert_yaxis()
fig.colorbar(im)
plt.show()
# pg.image(data, title="test")
# if __name__ == '__main__':
# pg.QtWidgets.QApplication.exec_()

View File

@ -0,0 +1,2 @@
from .utils.defines import Defines as defs
from .utils import bit_utils, alias_utility

View File

@ -0,0 +1,401 @@
import logging
import typing
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.bit_utils import bit_is_set, manipulate_bit
from pyctbgui.utils.defines import Defines
import pyctbgui.utils.pixelmap as pm
from pyctbgui.utils.recordOrApplyPedestal import recordOrApplyPedestal
if typing.TYPE_CHECKING:
from pyctbgui.services import AcquisitionTab, PlotTab
class AdcTab(QtWidgets.QWidget):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "adc.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
self.plotTab: PlotTab | None = None
self.acquisitionTab: AcquisitionTab | None = None
self.legend: LegendItem | None = None
self.logger = logging.getLogger('AdcTab')
def setup_ui(self):
self.plotTab = self.mainWindow.plotTab
self.acquisitionTab = self.mainWindow.acquisitionTab
for i in range(Defines.adc.count):
self.setADCButtonColor(i, self.plotTab.getRandomColor())
self.initializeAllAnalogPlots()
self.legend = self.mainWindow.plotAnalogWaveform.getPlotItem().legend
self.legend.clear()
# subscribe to toggle legend
self.plotTab.subscribeToggleLegend(self.updateLegend)
def initializeAllAnalogPlots(self):
self.mainWindow.plotAnalogWaveform = pg.plot()
self.mainWindow.plotAnalogWaveform.addLegend(colCount=Defines.colCount)
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotAnalogWaveform, 1)
self.mainWindow.analogPlots = {}
waveform = np.zeros(1000)
for i in range(Defines.adc.count):
pen = pg.mkPen(color=self.getADCButtonColor(i), width=1)
legendName = getattr(self.view, f"labelADC{i}").text()
self.mainWindow.analogPlots[i] = self.mainWindow.plotAnalogWaveform.plot(waveform,
pen=pen,
name=legendName)
self.mainWindow.analogPlots[i].hide()
self.mainWindow.plotAnalogImage = pg.ImageView()
self.mainWindow.nAnalogRows = 0
self.mainWindow.nAnalogCols = 0
self.mainWindow.analog_frame = np.zeros((self.mainWindow.nAnalogRows, self.mainWindow.nAnalogCols))
self.mainWindow.plotAnalogImage.getView().invertY(False)
self.mainWindow.plotAnalogImage.setImage(self.mainWindow.analog_frame)
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotAnalogImage, 2)
def connect_ui(self):
for i in range(Defines.adc.count):
getattr(self.view, f"checkBoxADC{i}Inv").stateChanged.connect(partial(self.setADCInv, i))
getattr(self.view, f"checkBoxADC{i}En").stateChanged.connect(partial(self.setADCEnable, i))
getattr(self.view, f"checkBoxADC{i}Plot").stateChanged.connect(partial(self.setADCEnablePlot, i))
getattr(self.view, f"pushButtonADC{i}").clicked.connect(partial(self.selectADCColor, i))
self.view.checkBoxADC0_15En.stateChanged.connect(partial(self.setADCEnableRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31En.stateChanged.connect(
partial(self.setADCEnableRange, Defines.adc.half, Defines.adc.count))
self.view.checkBoxADC0_15Plot.stateChanged.connect(partial(self.setADCEnablePlotRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31Plot.stateChanged.connect(
partial(self.setADCEnablePlotRange, Defines.adc.half, Defines.adc.count))
self.view.checkBoxADC0_15Inv.stateChanged.connect(partial(self.setADCInvRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31Inv.stateChanged.connect(
partial(self.setADCInvRange, Defines.adc.half, Defines.adc.count))
self.view.lineEditADCInversion.editingFinished.connect(self.setADCInvReg)
self.view.lineEditADCEnable.editingFinished.connect(self.setADCEnableReg)
def refresh(self):
self.updateADCNames()
self.updateADCInv()
self.updateADCEnable()
# ADCs Tab functions
def getEnabledPlots(self):
"""
return plots that are shown (checkBoxADC#Plot is checked)
"""
enabledPlots = []
self.legend.clear()
for i in range(Defines.adc.count):
if getattr(self.view, f'checkBoxADC{i}Plot').isChecked():
plotName = getattr(self.view, f"labelADC{i}").text()
enabledPlots.append((self.mainWindow.analogPlots[i], plotName))
return enabledPlots
def updateLegend(self):
"""
update the legend for the ADC 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)
def updateADCNames(self):
"""
get adc names from detector and update them in the UI
"""
for i, adc_name in enumerate(self.det.getAdcNames()):
getattr(self.view, f"labelADC{i}").setText(adc_name)
def processWaveformData(self, data: bytes, aSamples: int) -> dict[str, np.ndarray]:
"""
view function
plots processed waveform data
@param data: raw waveform data
@param aSamples: analog samples
@return: waveform dict returned to handle it for saving the output
"""
waveforms = {}
analog_array = self._processWaveformData(data, aSamples, self.mainWindow.nADCEnabled)
idx = 0
for i in range(Defines.adc.count):
checkBoxPlot = getattr(self.view, f"checkBoxADC{i}Plot")
checkBoxEn = getattr(self.view, f"checkBoxADC{i}En")
if checkBoxEn.isChecked() and checkBoxPlot.isChecked():
waveform = analog_array[:, idx]
idx += 1
self.mainWindow.analogPlots[i].setData(waveform)
plotName = getattr(self.view, f"labelADC{i}").text()
waveforms[plotName] = waveform
return waveforms
@recordOrApplyPedestal
def _processWaveformData(self, data: bytes, aSamples: int, nADCEnabled: int) -> np.ndarray:
"""
model function
processes raw waveform data
@param data: raw waveform data
@param aSamples: analog samples
@param nADCEnabled: number of enabled ADCs
@return: processed waveform data
"""
analog_array = np.array(np.frombuffer(data, dtype=np.uint16, count=nADCEnabled * aSamples))
return analog_array.reshape(-1, nADCEnabled)
def processImageData(self, data, aSamples):
"""
process the raw receiver data for analog image
data: raw analog image
aSamples: analog samples
"""
# get zoom state
viewBox = self.mainWindow.plotAnalogImage.getView()
state = viewBox.getState()
try:
self.mainWindow.analog_frame = self._processImageData(data, aSamples, self.mainWindow.nADCEnabled)
self.plotTab.ignoreHistogramSignal = True
self.mainWindow.plotAnalogImage.setImage(self.mainWindow.analog_frame.T)
except Exception:
self.logger.exception('Exception Caught')
self.mainWindow.statusbar.setStyleSheet("color:red")
message = f'Warning: Invalid size for Analog Image. Expected' \
f' {self.mainWindow.nAnalogRows * self.mainWindow.nAnalogCols} ' \
f'size, got {self.mainWindow.analog_frame.size} instead.'
self.acquisitionTab.updateCurrentFrame('Invalid Image')
self.mainWindow.statusbar.showMessage(message)
print(message)
self.plotTab.setFrameLimits(self.mainWindow.analog_frame)
# keep the zoomed in state (not 1st image)
if self.mainWindow.firstAnalogImage:
self.mainWindow.firstAnalogImage = False
else:
viewBox.setState(state)
return self.mainWindow.analog_frame.T
@recordOrApplyPedestal
def _processImageData(self, data, aSamples, nADCEnabled):
analog_array = np.array(np.frombuffer(data, dtype=np.uint16, count=nADCEnabled * aSamples))
return decoder.decode(analog_array, pm.moench04_analog())
def getADCEnableReg(self):
retval = self.det.adcenable
if self.det.tengiga:
retval = self.det.adcenable10g
self.view.lineEditADCEnable.editingFinished.disconnect()
self.view.lineEditADCEnable.setText("0x{:08x}".format(retval))
self.view.lineEditADCEnable.editingFinished.connect(self.setADCEnableReg)
return retval
def setADCEnableReg(self):
self.view.lineEditADCEnable.editingFinished.disconnect()
try:
mask = int(self.mainWindow.lineEditADCEnable.text(), 16)
if self.det.tengiga:
self.det.adcenable10g = mask
else:
self.det.adcenable = mask
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Enable Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
self.view.lineEditADCEnable.editingFinished.connect(self.setADCEnableReg)
self.updateADCEnable()
def getADCEnable(self, i, mask):
checkBox = getattr(self.view, f"checkBoxADC{i}En")
checkBox.stateChanged.disconnect()
checkBox.setChecked(bit_is_set(mask, i))
checkBox.stateChanged.connect(partial(self.setADCEnable, i))
def updateADCEnable(self):
retval = self.getADCEnableReg()
self.mainWindow.nADCEnabled = bin(retval).count('1')
for i in range(Defines.adc.count):
self.getADCEnable(i, retval)
self.getADCEnablePlot(i)
self.getADCEnableColor(i)
self.plotTab.addSelectedAnalogPlots(i)
self.getADCEnableRange(retval)
self.getADCEnablePlotRange()
def setADCEnable(self, i):
checkBox = getattr(self.view, f"checkBoxADC{i}En")
try:
if self.det.tengiga:
enableMask = manipulate_bit(checkBox.isChecked(), self.det.adcenable10g, i)
self.det.adcenable10g = enableMask
else:
enableMask = manipulate_bit(checkBox.isChecked(), self.det.adcenable, i)
self.det.adcenable = enableMask
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Enable Fail", str(e), QtWidgets.QMessageBox.Ok)
self.updateADCEnable()
def getADCEnableRange(self, mask):
self.view.checkBoxADC0_15En.stateChanged.disconnect()
self.view.checkBoxADC16_31En.stateChanged.disconnect()
self.view.checkBoxADC0_15En.setChecked((mask & Defines.adc.BIT0_15_MASK) == Defines.adc.BIT0_15_MASK)
self.view.checkBoxADC16_31En.setChecked((mask & Defines.adc.BIT16_31_MASK) == Defines.adc.BIT16_31_MASK)
self.view.checkBoxADC0_15En.stateChanged.connect(partial(self.setADCEnableRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31En.stateChanged.connect(
partial(self.setADCEnableRange, Defines.adc.half, Defines.adc.count))
def setADCEnableRange(self, start_nr, end_nr):
mask = self.getADCEnableReg()
checkBox = getattr(self.view, f"checkBoxADC{start_nr}_{end_nr - 1}En")
for i in range(start_nr, end_nr):
mask = manipulate_bit(checkBox.isChecked(), mask, i)
try:
if self.det.tengiga:
self.det.adcenable10g = mask
else:
self.det.adcenable = mask
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Enable Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
self.updateADCEnable()
def getADCEnablePlot(self, i):
checkBox = getattr(self.view, f"checkBoxADC{i}En")
checkBoxPlot = getattr(self.view, f"checkBoxADC{i}Plot")
checkBoxPlot.setEnabled(checkBox.isChecked())
def setADCEnablePlot(self, i):
pushButton = getattr(self.view, f"pushButtonADC{i}")
checkBox = getattr(self.view, f"checkBoxADC{i}Plot")
pushButton.setEnabled(checkBox.isChecked())
self.getADCEnablePlotRange()
self.plotTab.addSelectedAnalogPlots(i)
self.updateLegend()
def getADCEnablePlotRange(self):
self.view.checkBoxADC0_15Plot.stateChanged.disconnect()
self.view.checkBoxADC16_31Plot.stateChanged.disconnect()
self.view.checkBoxADC0_15Plot.setEnabled(
all(getattr(self.view, f"checkBoxADC{i}Plot").isEnabled() for i in range(Defines.adc.half)))
self.view.checkBoxADC16_31Plot.setEnabled(
all(
getattr(self.view, f"checkBoxADC{i}Plot").isEnabled()
for i in range(Defines.adc.half, Defines.adc.count)))
self.view.checkBoxADC0_15Plot.setChecked(
all(getattr(self.view, f"checkBoxADC{i}Plot").isChecked() for i in range(Defines.adc.half)))
self.view.checkBoxADC16_31Plot.setChecked(
all(
getattr(self.view, f"checkBoxADC{i}Plot").isChecked()
for i in range(Defines.adc.half, Defines.adc.count)))
self.view.checkBoxADC0_15Plot.stateChanged.connect(partial(self.setADCEnablePlotRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31Plot.stateChanged.connect(
partial(self.setADCEnablePlotRange, Defines.adc.half, Defines.adc.count))
def setADCEnablePlotRange(self, start_nr, end_nr):
checkBox = getattr(self.view, f"checkBoxADC{start_nr}_{end_nr - 1}Plot")
enable = checkBox.isChecked()
for i in range(start_nr, end_nr):
checkBox = getattr(self.view, f"checkBoxADC{i}Plot")
checkBox.setChecked(enable)
self.plotTab.addAllSelectedAnalogPlots()
def getADCEnableColor(self, i):
checkBox = getattr(self.view, f"checkBoxADC{i}Plot")
pushButton = getattr(self.view, f"pushButtonADC{i}")
pushButton.setEnabled(checkBox.isEnabled() and checkBox.isChecked())
def selectADCColor(self, i):
pushButton = getattr(self.view, f"pushButtonADC{i}")
self.plotTab.showPalette(pushButton)
pen = pg.mkPen(color=self.getADCButtonColor(i), width=1)
self.mainWindow.analogPlots[i].setPen(pen)
def getADCButtonColor(self, i):
pushButton = getattr(self.view, f"pushButtonADC{i}")
return self.plotTab.getActiveColor(pushButton)
def setADCButtonColor(self, i, color):
pushButton = getattr(self.view, f"pushButtonADC{i}")
return self.plotTab.setActiveColor(pushButton, color)
def getADCInvReg(self):
retval = self.det.adcinvert
self.view.lineEditADCInversion.editingFinished.disconnect()
self.view.lineEditADCInversion.setText("0x{:08x}".format(retval))
self.view.lineEditADCInversion.editingFinished.connect(self.setADCInvReg)
return retval
def setADCInvReg(self):
self.view.lineEditADCInversion.editingFinished.disconnect()
try:
self.det.adcinvert = int(self.mainWindow.lineEditADCInversion.text(), 16)
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Inversion Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
self.view.lineEditADCInversion.editingFinished.connect(self.setADCInvReg)
self.updateADCInv()
def getADCInv(self, i, inv):
checkBox = getattr(self.view, f"checkBoxADC{i}Inv")
checkBox.stateChanged.disconnect()
checkBox.setChecked(bit_is_set(inv, i))
checkBox.stateChanged.connect(partial(self.setADCInv, i))
def updateADCInv(self):
retval = self.getADCInvReg()
for i in range(Defines.adc.count):
self.getADCInv(i, retval)
self.getADCInvRange(retval)
def setADCInv(self, i):
out = self.det.adcinvert
checkBox = getattr(self.view, f"checkBoxADC{i}Inv")
mask = manipulate_bit(checkBox.isChecked(), out, i)
self.det.adcinvert = mask
retval = self.getADCInvReg()
self.getADCInv(i, retval)
self.getADCInvRange(retval)
def getADCInvRange(self, inv):
self.view.checkBoxADC0_15Inv.stateChanged.disconnect()
self.view.checkBoxADC16_31Inv.stateChanged.disconnect()
self.view.checkBoxADC0_15Inv.setChecked((inv & Defines.adc.BIT0_15_MASK) == Defines.adc.BIT0_15_MASK)
self.view.checkBoxADC16_31Inv.setChecked((inv & Defines.adc.BIT16_31_MASK) == Defines.adc.BIT16_31_MASK)
self.view.checkBoxADC0_15Inv.stateChanged.connect(partial(self.setADCInvRange, 0, Defines.adc.half))
self.view.checkBoxADC16_31Inv.stateChanged.connect(
partial(self.setADCInvRange, Defines.adc.half, Defines.adc.count))
def setADCInvRange(self, start_nr, end_nr):
out = self.det.adcinvert
checkBox = getattr(self.view, f"checkBoxADC{start_nr}_{end_nr - 1}Inv")
mask = getattr(Defines.adc, f"BIT{start_nr}_{end_nr - 1}_MASK")
if checkBox.isChecked():
self.det.adcinvert = out | mask
else:
self.det.adcinvert = out & ~mask
self.updateADCInv()
def saveParameters(self) -> list[str]:
return [
f"adcenable {self.view.lineEditADCEnable.text()}",
f"adcinvert {self.view.lineEditADCInversion.text()}",
]

View File

@ -0,0 +1,719 @@
import json
import typing
from pathlib import Path
import numpy as np
import time
import zmq
from PyQt5 import QtWidgets, uic
import logging
from slsdet import readoutMode, runStatus
from pyctbgui.utils.defines import Defines
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
from pyctbgui.utils.numpyWriter.npz_writer import NpzFileWriter
if typing.TYPE_CHECKING:
# only used for type hinting. To avoid circular dependencies these
# won't be imported in runtime
from pyctbgui.services import SignalsTab, TransceiverTab, AdcTab, PlotTab
class AcquisitionTab(QtWidgets.QWidget):
def __init__(self, parent):
self.__isWaveform = None
super().__init__(parent)
self.currentMeasurement = None
self.dsamples = None
self.stoppedFlag = None
self.asamples = None
self.tsamples = None
uic.loadUi(Path(__file__).parent.parent / 'ui' / "acquisition.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
self.signalsTab: SignalsTab = None
self.transceiverTab: TransceiverTab = None
self.adcTab: AdcTab = None
self.plotTab: PlotTab = None
self.writeNumpy: bool = False
self.outputDir: Path = Path('/')
self.outputFileNamePrefix: str = ''
self.numpyFileManagers: dict[str, NumpyFileManager] = {}
self.logger = logging.getLogger('AcquisitionTab')
def setup_ui(self):
self.signalsTab = self.mainWindow.signalsTab
self.transceiverTab = self.mainWindow.transceiverTab
self.adcTab = self.mainWindow.adcTab
self.plotTab = self.mainWindow.plotTab
self.toggleStartButton(False)
def connect_ui(self):
# For Acquistions Tab
self.view.comboBoxROMode.currentIndexChanged.connect(self.setReadOut)
self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency)
self.view.spinBoxTransceiver.editingFinished.connect(self.setTransceiver)
self.view.spinBoxAnalog.editingFinished.connect(self.setAnalog)
self.view.spinBoxDigital.editingFinished.connect(self.setDigital)
self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency)
self.view.spinBoxADCPhase.editingFinished.connect(self.setADCPhase)
self.view.spinBoxADCPipeline.editingFinished.connect(self.setADCPipeline)
self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency)
self.view.spinBoxDBITPhase.editingFinished.connect(self.setDBITPhase)
self.view.spinBoxDBITPipeline.editingFinished.connect(self.setDBITPipeline)
self.view.checkBoxFileWriteRaw.stateChanged.connect(self.setFileWrite)
self.view.checkBoxFileWriteNumpy.stateChanged.connect(self.setFileWriteNumpy)
self.view.lineEditFileName.editingFinished.connect(self.setFileName)
self.view.lineEditFilePath.editingFinished.connect(self.setFilePath)
self.view.pushButtonFilePath.clicked.connect(self.browseFilePath)
self.view.spinBoxAcquisitionIndex.editingFinished.connect(self.setAccquisitionIndex)
self.view.spinBoxFrames.editingFinished.connect(self.setFrames)
self.view.spinBoxPeriod.editingFinished.connect(self.setPeriod)
self.view.comboBoxPeriod.currentIndexChanged.connect(self.setPeriod)
self.view.spinBoxTriggers.editingFinished.connect(self.setTriggers)
def refresh(self):
self.getReadout()
self.getRunFrequency()
self.getTransceiver()
self.getAnalog()
self.getDigital()
self.getADCFrequency()
self.getADCPhase()
self.getADCPipeline()
self.getDBITFrequency()
self.getDBITPhase()
self.getDBITPipeline()
self.getFileWrite()
self.getFileName()
self.getFilePath()
self.getAccquisitionIndex()
self.getFrames()
self.getTriggers()
self.getPeriod()
self.updateDetectorStatus(self.det.status)
# Acquisition Tab functions
def getReadout(self):
self.view.comboBoxROMode.currentIndexChanged.disconnect()
self.view.spinBoxAnalog.editingFinished.disconnect()
self.view.spinBoxDigital.editingFinished.disconnect()
self.view.spinBoxTransceiver.editingFinished.disconnect()
self.mainWindow.romode = self.det.romode
self.view.comboBoxROMode.setCurrentIndex(self.mainWindow.romode.value)
match self.mainWindow.romode:
case readoutMode.ANALOG_ONLY:
self.view.spinBoxAnalog.setEnabled(True)
self.view.labelAnalog.setEnabled(True)
self.view.spinBoxDigital.setDisabled(True)
self.view.labelDigital.setDisabled(True)
self.view.labelTransceiver.setDisabled(True)
self.view.spinBoxTransceiver.setDisabled(True)
case readoutMode.DIGITAL_ONLY:
self.view.spinBoxAnalog.setDisabled(True)
self.view.labelAnalog.setDisabled(True)
self.view.spinBoxDigital.setEnabled(True)
self.view.labelDigital.setEnabled(True)
self.view.labelTransceiver.setDisabled(True)
self.view.spinBoxTransceiver.setDisabled(True)
case readoutMode.ANALOG_AND_DIGITAL:
self.view.spinBoxAnalog.setEnabled(True)
self.view.labelAnalog.setEnabled(True)
self.view.spinBoxDigital.setEnabled(True)
self.view.labelDigital.setEnabled(True)
self.view.labelTransceiver.setDisabled(True)
self.view.spinBoxTransceiver.setDisabled(True)
case readoutMode.TRANSCEIVER_ONLY:
self.view.spinBoxAnalog.setDisabled(True)
self.view.labelAnalog.setDisabled(True)
self.view.spinBoxDigital.setDisabled(True)
self.view.labelDigital.setDisabled(True)
self.view.labelTransceiver.setEnabled(True)
self.view.spinBoxTransceiver.setEnabled(True)
case _:
self.view.spinBoxAnalog.setDisabled(True)
self.view.labelAnalog.setDisabled(True)
self.view.spinBoxDigital.setEnabled(True)
self.view.labelDigital.setEnabled(True)
self.view.labelTransceiver.setEnabled(True)
self.view.spinBoxTransceiver.setEnabled(True)
self.view.comboBoxROMode.currentIndexChanged.connect(self.setReadOut)
self.view.spinBoxAnalog.editingFinished.connect(self.setAnalog)
self.view.spinBoxDigital.editingFinished.connect(self.setDigital)
self.view.spinBoxTransceiver.editingFinished.connect(self.setTransceiver)
self.getAnalog()
self.getDigital()
self.plotTab.showPlot()
def plotReferesh(self):
self.read_zmq()
def setReadOut(self):
self.view.comboBoxROMode.currentIndexChanged.disconnect()
try:
if self.view.comboBoxROMode.currentIndex() == 0:
self.det.romode = readoutMode.ANALOG_ONLY
elif self.view.comboBoxROMode.currentIndex() == 1:
self.det.romode = readoutMode.DIGITAL_ONLY
elif self.view.comboBoxROMode.currentIndex() == 2:
self.det.romode = readoutMode.ANALOG_AND_DIGITAL
elif self.view.comboBoxROMode.currentIndex() == 3:
self.det.romode = readoutMode.TRANSCEIVER_ONLY
else:
self.det.romode = readoutMode.DIGITAL_AND_TRANSCEIVER
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Readout Mode Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.comboBoxROMode.currentIndexChanged.connect(self.setReadOut)
self.getReadout()
def getRunFrequency(self):
self.view.spinBoxRunF.editingFinished.disconnect()
self.view.spinBoxRunF.setValue(self.det.runclk)
self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency)
def setRunFrequency(self):
self.view.spinBoxRunF.editingFinished.disconnect()
try:
self.det.runclk = self.view.spinBoxRunF.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Run Frequency Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency)
self.getRunFrequency()
def getTransceiver(self):
self.view.spinBoxTransceiver.editingFinished.disconnect()
self.tsamples = self.det.tsamples
self.view.spinBoxTransceiver.setValue(self.tsamples)
self.view.spinBoxTransceiver.editingFinished.connect(self.setTransceiver)
def setTransceiver(self):
self.view.spinBoxTransceiver.editingFinished.disconnect()
try:
self.det.tsamples = self.view.spinBoxTransceiver.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Transceiver Samples Fail", str(e),
QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxTransceiver.editingFinished.connect(self.setTransceiver)
self.getTransceiver()
def getAnalog(self):
self.view.spinBoxAnalog.editingFinished.disconnect()
self.asamples = self.det.asamples
self.view.spinBoxAnalog.setValue(self.asamples)
self.view.spinBoxAnalog.editingFinished.connect(self.setAnalog)
def setAnalog(self):
self.view.spinBoxAnalog.editingFinished.disconnect()
try:
self.det.asamples = self.view.spinBoxAnalog.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Digital Samples Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxAnalog.editingFinished.connect(self.setAnalog)
self.getAnalog()
def getDigital(self):
self.view.spinBoxDigital.editingFinished.disconnect()
self.dsamples = self.det.dsamples
self.view.spinBoxDigital.setValue(self.dsamples)
self.view.spinBoxDigital.editingFinished.connect(self.setDigital)
def setDigital(self):
self.view.spinBoxDigital.editingFinished.disconnect()
try:
self.det.dsamples = self.view.spinBoxDigital.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Digital Samples Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxDigital.editingFinished.connect(self.setDigital)
self.getDigital()
def getADCFrequency(self):
self.view.spinBoxADCF.editingFinished.disconnect()
self.view.spinBoxADCF.setValue(self.det.adcclk)
self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency)
def setADCFrequency(self):
self.view.spinBoxADCF.editingFinished.disconnect()
try:
self.det.adcclk = self.view.spinBoxADCF.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Frequency Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency)
self.getADCFrequency()
def getADCPhase(self):
self.view.spinBoxADCPhase.editingFinished.disconnect()
self.view.spinBoxADCPhase.setValue(self.det.adcphase)
self.view.spinBoxADCPhase.editingFinished.connect(self.setADCPhase)
def setADCPhase(self):
self.view.spinBoxADCPhase.editingFinished.disconnect()
try:
self.det.adcphase = self.view.spinBoxADCPhase.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Phase Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxADCPhase.editingFinished.connect(self.setADCPhase)
self.getADCPhase()
def getADCPipeline(self):
self.view.spinBoxADCPipeline.editingFinished.disconnect()
self.view.spinBoxADCPipeline.setValue(self.det.adcpipeline)
self.view.spinBoxADCPipeline.editingFinished.connect(self.setADCPipeline)
def setADCPipeline(self):
self.view.spinBoxADCPipeline.editingFinished.disconnect()
try:
self.det.adcpipeline = self.view.spinBoxADCPipeline.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Pipeline Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxADCPipeline.editingFinished.connect(self.setADCPipeline)
self.getADCPipeline()
def getDBITFrequency(self):
self.view.spinBoxDBITF.editingFinished.disconnect()
self.view.spinBoxDBITF.setValue(self.det.dbitclk)
self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency)
def setDBITFrequency(self):
self.view.spinBoxDBITF.editingFinished.disconnect()
try:
self.det.dbitclk = self.view.spinBoxDBITF.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "DBit Frequency Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency)
self.getDBITFrequency()
def getDBITPhase(self):
self.view.spinBoxDBITPhase.editingFinished.disconnect()
self.view.spinBoxDBITPhase.setValue(self.det.dbitphase)
self.view.spinBoxDBITPhase.editingFinished.connect(self.setDBITPhase)
def setDBITPhase(self):
self.view.spinBoxDBITPhase.editingFinished.disconnect()
try:
self.det.dbitphase = self.view.spinBoxDBITPhase.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "DBit Phase Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxDBITPhase.editingFinished.connect(self.setDBITPhase)
self.getDBITPhase()
def getDBITPipeline(self):
self.view.spinBoxDBITPipeline.editingFinished.disconnect()
self.view.spinBoxDBITPipeline.setValue(self.det.dbitpipeline)
self.view.spinBoxDBITPipeline.editingFinished.connect(self.setDBITPipeline)
def setDBITPipeline(self):
self.view.spinBoxDBITPipeline.editingFinished.disconnect()
try:
self.det.dbitpipeline = self.view.spinBoxDBITPipeline.value()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "DBit Pipeline Fail", str(e), QtWidgets.QMessageBox.Ok)
# TODO: handling double event exceptions
self.view.spinBoxDBITPipeline.editingFinished.connect(self.setDBITPipeline)
self.getDBITPipeline()
def getFileWrite(self):
self.view.checkBoxFileWriteRaw.stateChanged.disconnect()
self.view.checkBoxFileWriteRaw.setChecked(self.det.fwrite)
self.view.checkBoxFileWriteRaw.stateChanged.connect(self.setFileWrite)
def setFileWrite(self):
self.det.fwrite = self.view.checkBoxFileWriteRaw.isChecked()
self.getFileWrite()
def setFileWriteNumpy(self):
"""
slot for saving the data in numpy (.npy) format
"""
self.writeNumpy = not self.writeNumpy
def getFileName(self):
"""
set the lineEditFilePath input widget to the filename value from the detector
"""
self.view.lineEditFileName.editingFinished.disconnect()
fileName = self.det.fname
self.view.lineEditFileName.setText(fileName)
self.outputFileNamePrefix = fileName
self.view.lineEditFileName.editingFinished.connect(self.setFileName)
def setFileName(self):
"""
slot for setting the filename from the widget to the detector
"""
self.det.fname = self.view.lineEditFileName.text()
self.getFileName()
def getFilePath(self):
"""
set the lineEditFilePath input widget to the path value from the detector
"""
self.view.lineEditFilePath.editingFinished.disconnect()
path = self.det.fpath
self.view.lineEditFilePath.setText(str(path))
self.view.lineEditFilePath.editingFinished.connect(self.setFilePath)
self.outputDir = path
def setFilePath(self):
"""
slot to set the directory of the output for the detector
"""
self.det.fpath = Path(self.view.lineEditFilePath.text())
self.getFilePath()
def saveNumpyFile(self, data: np.ndarray | dict[str, np.ndarray], jsonHeader):
"""
save the acquisition data (waveform or image) in the specified path
save waveform in multiple .npy files
save image as npy file format
@note: frame number can be up to 100,000 so the data arrays cannot be fully loaded to memory
"""
if not self.writeNumpy:
return
if self.outputDir == Path('/'):
self.outputDir = Path('./')
if self.outputFileNamePrefix == '':
self.outputFileNamePrefix = 'run'
for device in data:
if device not in self.numpyFileManagers:
tmpPath = self.outputDir / f'{self.outputFileNamePrefix}_{device}_{jsonHeader["fileIndex"]}.npy'
self.numpyFileManagers[device] = NumpyFileManager(tmpPath, 'w', data[device].shape, data[device].dtype)
self.numpyFileManagers[device].writeOneFrame(data[device])
if 'progress' in jsonHeader and jsonHeader['progress'] >= 100:
# close opened files after saving the last frame
self.closeOpenedNumpyFiles(jsonHeader)
def closeOpenedNumpyFiles(self, jsonHeader):
"""
create npz file for waveform plots and close opened numpy files to persist their data
"""
if not self.writeNumpy:
return
if len(self.numpyFileManagers) == 0:
return
oneFile: bool = len(self.numpyFileManagers) == 1
filepaths = [npw.file.name for device, npw in self.numpyFileManagers.items()]
filenames = list(self.numpyFileManagers.keys())
ext = 'npy' if oneFile else 'npz'
newPath = self.outputDir / f'{self.outputFileNamePrefix}_{jsonHeader["fileIndex"]}.{ext}'
if not oneFile:
# if there is multiple .npy files group them in an .npz file
self.numpyFileManagers.clear()
NpzFileWriter.zipNpyFiles(newPath, filepaths, filenames, deleteOriginals=True, compressed=False)
else:
# rename files from "run_ADC0_0.npy" to "run_0.npy" if it is a single .npy file
oldPath = self.outputDir / f'{self.outputFileNamePrefix}_' \
f'{self.numpyFileManagers.popitem()[0]}_{jsonHeader["fileIndex"]}.{ext}'
Path.rename(oldPath, newPath)
self.logger.info(f'Saving numpy data in {newPath} Finished')
def browseFilePath(self):
response = QtWidgets.QFileDialog.getExistingDirectory(parent=self.mainWindow,
caption="Select Path to Save Output File",
directory=str(Path.cwd()),
options=(QtWidgets.QFileDialog.ShowDirsOnly
| QtWidgets.QFileDialog.DontResolveSymlinks)
# filter='README (*.md *.ui)'
)
if response:
self.view.lineEditFilePath.setText(response)
self.setFilePath()
def getAccquisitionIndex(self):
self.view.spinBoxAcquisitionIndex.editingFinished.disconnect()
self.view.spinBoxAcquisitionIndex.setValue(self.det.findex)
self.view.spinBoxAcquisitionIndex.editingFinished.connect(self.setAccquisitionIndex)
def setAccquisitionIndex(self):
self.det.findex = self.view.spinBoxAcquisitionIndex.value()
self.getAccquisitionIndex()
def getFrames(self):
self.view.spinBoxFrames.editingFinished.disconnect()
self.view.spinBoxFrames.setValue(self.det.frames)
self.view.spinBoxFrames.editingFinished.connect(self.setFrames)
def setFrames(self):
self.det.frames = self.view.spinBoxFrames.value()
self.getFrames()
def getPeriod(self):
self.view.spinBoxPeriod.editingFinished.disconnect()
self.view.comboBoxPeriod.currentIndexChanged.disconnect()
# Converting to right time unit for period
tPeriod = self.det.period
if tPeriod < 100e-9:
self.view.comboBoxPeriod.setCurrentIndex(3)
self.view.spinBoxPeriod.setValue(tPeriod / 1e-9)
elif tPeriod < 100e-6:
self.view.comboBoxPeriod.setCurrentIndex(2)
self.view.spinBoxPeriod.setValue(tPeriod / 1e-6)
elif tPeriod < 100e-3:
self.view.comboBoxPeriod.setCurrentIndex(1)
self.view.spinBoxPeriod.setValue(tPeriod / 1e-3)
else:
self.view.comboBoxPeriod.setCurrentIndex(0)
self.view.spinBoxPeriod.setValue(tPeriod)
self.view.spinBoxPeriod.editingFinished.connect(self.setPeriod)
self.view.comboBoxPeriod.currentIndexChanged.connect(self.setPeriod)
def setPeriod(self):
if self.view.comboBoxPeriod.currentIndex() == 0:
self.det.period = self.view.spinBoxPeriod.value()
elif self.view.comboBoxPeriod.currentIndex() == 1:
self.det.period = self.view.spinBoxPeriod.value() * (1e-3)
elif self.view.comboBoxPeriod.currentIndex() == 2:
self.det.period = self.view.spinBoxPeriod.value() * (1e-6)
else:
self.det.period = self.view.spinBoxPeriod.value() * (1e-9)
self.getPeriod()
def getTriggers(self):
self.view.spinBoxTriggers.editingFinished.disconnect()
self.view.spinBoxTriggers.setValue(self.det.triggers)
self.view.spinBoxTriggers.editingFinished.connect(self.setTriggers)
def setTriggers(self):
self.det.triggers = self.view.spinBoxTriggers.value()
self.getTriggers()
def updateDetectorStatus(self, status):
self.mainWindow.labelDetectorStatus.setText(status.name)
def updateCurrentMeasurement(self):
self.mainWindow.labelCurrentMeasurement.setText(str(self.currentMeasurement))
# print(f"Meausrement {self.currentMeasurement}")
def updateCurrentFrame(self, val):
self.mainWindow.labelFrameNumber.setText(str(val))
def updateAcquiredFrames(self, val):
self.mainWindow.labelAcquiredFrames.setText(str(val))
def toggleAcquire(self):
if self.mainWindow.pushButtonStart.isChecked():
self.plotTab.showPatternViewer(False)
self.acquire()
else:
self.stopAcquisition()
def toggleStartButton(self, started):
if started:
self.mainWindow.pushButtonStart.setChecked(True)
self.mainWindow.pushButtonStart.setText('Stop')
else:
self.mainWindow.pushButtonStart.setChecked(False)
self.mainWindow.pushButtonStart.setText('Start')
def stopAcquisition(self):
self.det.stop()
self.stoppedFlag = True
def checkBeforeAcquire(self):
if self.plotTab.view.radioButtonImage.isChecked():
# matterhorn image
if self.plotTab.view.comboBoxPlot.currentText() == "Matterhorn":
if self.mainWindow.romode not in [readoutMode.TRANSCEIVER_ONLY, readoutMode.DIGITAL_AND_TRANSCEIVER]:
QtWidgets.QMessageBox.warning(self.mainWindow, "Plot type",
"To read Matterhorn image, please enable transceiver readout mode",
QtWidgets.QMessageBox.Ok)
return False
if self.transceiverTab.getTransceiverEnableReg() != Defines.Matterhorn.tranceiverEnable:
QtWidgets.QMessageBox.warning(
self.mainWindow, "Plot type", "To read Matterhorn image, please set transceiver enable to " +
str(Defines.Matterhorn.tranceiverEnable), QtWidgets.QMessageBox.Ok)
return False
# moench04 image
elif self.plotTab.view.comboBoxPlot.currentText() == "Moench04":
if self.mainWindow.romode not in [readoutMode.ANALOG_ONLY, readoutMode.ANALOG_AND_DIGITAL]:
QtWidgets.QMessageBox.warning(self.mainWindow, "Plot type",
"To read Moench 04 image, please enable analog readout mode",
QtWidgets.QMessageBox.Ok)
return False
if self.mainWindow.nADCEnabled != 32:
QtWidgets.QMessageBox.warning(self.mainWindow, "Plot type",
"To read Moench 04 image, please enable all 32 adcs",
QtWidgets.QMessageBox.Ok)
return False
return True
def acquire(self):
if not self.checkBeforeAcquire():
self.toggleStartButton(False)
return
self.stoppedFlag = False
self.toggleStartButton(True)
self.currentMeasurement = 0
# ensure zmq streaming is enabled
if self.det.rx_zmqstream == 0:
self.det.rx_zmqstream = 1
# some functions that must be updated for local values
self.getTransceiver()
self.getAnalog()
self.getDigital()
self.getReadout()
self.signalsTab.getDBitOffset()
self.adcTab.getADCEnableReg()
self.signalsTab.updateDigitalBitEnable()
self.transceiverTab.getTransceiverEnableReg()
self.startMeasurement()
def startMeasurement(self):
try:
self.updateCurrentMeasurement()
self.updateCurrentFrame(0)
self.updateAcquiredFrames(0)
self.mainWindow.progressBar.setValue(0)
self.det.rx_start()
self.det.start()
time.sleep(Defines.Time_Wait_For_Packets_ms)
self.checkEndofAcquisition()
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Acquire Fail", str(e), QtWidgets.QMessageBox.Ok)
self.checkEndofAcquisition()
def checkEndofAcquisition(self):
caught = self.det.rx_framescaught[0]
self.updateAcquiredFrames(caught)
status = self.det.getDetectorStatus()[0]
self.updateDetectorStatus(status)
measurementDone = False
# print(f'status:{status}')
match status:
case runStatus.RUNNING:
pass
case runStatus.WAITING:
pass
case runStatus.TRANSMITTING:
pass
case _:
measurementDone = True
# check for 500ms for no packets
# needs more time for 1g streaming out done
if measurementDone:
time.sleep(Defines.Time_Wait_For_Packets_ms)
if self.det.rx_framescaught[0] != caught:
measurementDone = False
numMeasurments = self.view.spinBoxMeasurements.value()
if measurementDone:
if self.det.rx_status == runStatus.RUNNING:
self.det.rx_stop()
if self.view.checkBoxFileWriteRaw.isChecked() or self.view.checkBoxFileWriteNumpy.isChecked():
self.view.spinBoxAcquisitionIndex.stepUp()
self.setAccquisitionIndex()
# next measurement
self.currentMeasurement += 1
if self.currentMeasurement < numMeasurments and not self.stoppedFlag:
self.startMeasurement()
else:
self.mainWindow.statusTimer.stop()
self.toggleStartButton(False)
else:
self.mainWindow.statusTimer.start(Defines.Time_Status_Refresh_ms)
# For other functios
# Reading data from zmq and decoding it
def read_zmq(self):
# print("in readzmq")
try:
msg = self.socket.recv_multipart(flags=zmq.NOBLOCK)
if len(msg) != 2:
if len(msg) != 1:
print(f'len(msg) = {len(msg)}')
return
header, data = msg
jsonHeader = json.loads(header)
self.mainWindow.progressBar.setValue(int(jsonHeader['progress']))
self.updateCurrentFrame(jsonHeader['frameIndex'])
# waveform
waveforms = {}
if self.plotTab.view.radioButtonWaveform.isChecked():
# analog
if self.mainWindow.romode.value in [0, 2]:
waveforms |= self.adcTab.processWaveformData(data, self.asamples)
# digital
if self.mainWindow.romode.value in [1, 2, 4]:
waveforms |= self.signalsTab.processWaveformData(data, self.asamples, self.dsamples)
# transceiver
if self.mainWindow.romode.value in [3, 4]:
waveforms |= self.transceiverTab.processWaveformData(data, self.dsamples)
# image
else:
# analog
if self.mainWindow.romode.value in [0, 2]:
waveforms['analog_image'] = self.adcTab.processImageData(data, self.asamples)
# transceiver
if self.mainWindow.romode.value in [3, 4]:
waveforms['tx_image'] = self.transceiverTab.processImageData(data, self.dsamples)
self.saveNumpyFile(waveforms, jsonHeader)
except zmq.ZMQError:
pass
except Exception:
self.logger.exception("Exception caught")
def setup_zmq(self):
self.det.rx_zmqstream = 1
self.zmqIp = self.det.zmqip
self.zmqport = self.det.zmqport
self.zmq_stream = self.det.rx_zmqstream
self.context = zmq.Context()
self.socket = self.context.socket(zmq.SUB)
self.socket.connect(f"tcp://{self.zmqIp}:{self.zmqport}")
self.socket.subscribe("")
def saveParameters(self) -> list[str]:
return [
f'romode {self.view.comboBoxROMode.currentText().lower()}',
f'runclk {self.view.spinBoxRunF.value()}',
f'adcclk {self.view.spinBoxADCF.value()}',
f'adcphase {self.view.spinBoxADCPhase.value()}',
f'adcpipeline {self.view.spinBoxADCPipeline.value()}',
f'dbitclk {self.view.spinBoxDBITF.value()}',
f'dbitphase {self.view.spinBoxDBITPhase.value()}',
f'dbitpipeline {self.view.spinBoxDBITPipeline.value()}',
f'fwrite {int(self.view.checkBoxFileWriteRaw.isChecked())}',
f'fname {self.view.lineEditFileName.text()}',
f'fpath {self.view.lineEditFilePath.text()}',
f'findex {self.view.spinBoxAcquisitionIndex.value()}',
f'frames {self.view.spinBoxFrames.value()}',
f'triggers {self.view.spinBoxTriggers.value()}',
f'period {self.view.spinBoxPeriod.value()} {self.view.comboBoxPeriod.currentText().lower()}',
f'asamples {self.view.spinBoxAnalog.value()}',
f'dsamples {self.view.spinBoxDigital.value()}',
f'tsamples {self.view.spinBoxTransceiver.value()}',
]

View File

@ -0,0 +1,170 @@
from functools import partial
from pathlib import Path
from PyQt5 import QtWidgets, uic
from pyctbgui.utils.defines import Defines
from slsdet import dacIndex
class DacTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "Dacs.ui", parent)
self.view = parent
def setup_ui(self):
for i in range(Defines.dac.count):
dac = getattr(dacIndex, f"DAC_{i}")
getattr(self.view, f"spinBoxDAC{i}").setValue(self.det.getDAC(dac)[0])
if self.det.highvoltage == 0:
self.view.spinBoxHighVoltage.setDisabled(True)
self.view.checkBoxHighVoltage.setChecked(False)
def connect_ui(self):
n_dacs = len(self.det.daclist)
for i in range(n_dacs):
getattr(self.view, f"spinBoxDAC{i}").editingFinished.connect(partial(self.setDAC, i))
getattr(self.view, f"checkBoxDAC{i}").stateChanged.connect(partial(self.setDACTristate, i))
getattr(self.view, f"checkBoxDAC{i}mV").stateChanged.connect(partial(self.getDAC, i))
self.view.comboBoxADCVpp.currentIndexChanged.connect(self.setADCVpp)
self.view.spinBoxHighVoltage.editingFinished.connect(self.setHighVoltage)
self.view.checkBoxHighVoltage.stateChanged.connect(self.setHighVoltage)
def refresh(self):
self.updateDACNames()
for i in range(Defines.dac.count):
self.getDACTristate(i)
self.getDAC(i)
self.getADCVpp()
self.getHighVoltage()
def updateDACNames(self):
for i, name in enumerate(self.det.getDacNames()):
getattr(self.view, f"checkBoxDAC{i}").setText(name)
def getDACTristate(self, i):
checkBox = getattr(self.view, f"checkBoxDAC{i}")
dac = getattr(dacIndex, f"DAC_{i}")
checkBox.stateChanged.disconnect()
if (self.det.getDAC(dac)[0]) == -100:
checkBox.setChecked(False)
else:
checkBox.setChecked(True)
checkBox.stateChanged.connect(partial(self.setDACTristate, i))
def setDACTristate(self, i):
checkBox = getattr(self.view, f"checkBoxDAC{i}")
if not checkBox.isChecked():
self.setDAC(i)
self.getDAC(i)
def getDAC(self, i):
checkBox = getattr(self.view, f"checkBoxDAC{i}")
checkBoxmV = getattr(self.view, f"checkBoxDAC{i}mV")
spinBox = getattr(self.view, f"spinBoxDAC{i}")
label = getattr(self.view, f"labelDAC{i}")
dac = getattr(dacIndex, f"DAC_{i}")
checkBox.stateChanged.disconnect()
checkBoxmV.stateChanged.disconnect()
spinBox.editingFinished.disconnect()
# do not uncheck automatically
if self.det.getDAC(dac)[0] != -100:
checkBox.setChecked(True)
if checkBox.isChecked():
spinBox.setEnabled(True)
checkBoxmV.setEnabled(True)
else:
spinBox.setDisabled(True)
checkBoxmV.setDisabled(True)
in_mv = checkBoxmV.isChecked() and checkBox.isChecked()
dacValue = self.det.getDAC(dac, in_mv)[0]
unit = "mV" if in_mv else ""
label.setText(f"{dacValue} {unit}")
spinBox.setValue(dacValue)
checkBox.stateChanged.connect(partial(self.setDACTristate, i))
checkBoxmV.stateChanged.connect(partial(self.getDAC, i))
spinBox.editingFinished.connect(partial(self.setDAC, i))
def setDAC(self, i):
checkBoxDac = getattr(self.view, f"checkBoxDAC{i}")
checkBoxmV = getattr(self.view, f"checkBoxDAC{i}mV")
spinBox = getattr(self.view, f"spinBoxDAC{i}")
dac = getattr(dacIndex, f"DAC_{i}")
value = -100
if checkBoxDac.isChecked():
value = spinBox.value()
in_mV = checkBoxDac.isChecked() and checkBoxmV.isChecked()
self.det.setDAC(dac, value, in_mV)
self.getDAC(i)
def getADCVpp(self):
retval = self.det.adcvpp
self.view.labelADCVpp.setText(f'Mode: {str(retval)}')
self.view.comboBoxADCVpp.currentIndexChanged.disconnect()
self.view.comboBoxADCVpp.setCurrentIndex(retval)
self.view.comboBoxADCVpp.currentIndexChanged.connect(self.setADCVpp)
def setADCVpp(self):
self.det.adcvpp = self.view.comboBoxADCVpp.currentIndex()
self.getADCVpp()
def getHighVoltage(self):
retval = self.det.highvoltage
self.view.labelHighVoltage.setText(str(retval))
self.view.spinBoxHighVoltage.editingFinished.disconnect()
self.view.checkBoxHighVoltage.stateChanged.disconnect()
self.view.spinBoxHighVoltage.setValue(retval)
if retval:
self.view.checkBoxHighVoltage.setChecked(True)
if self.view.checkBoxHighVoltage.isChecked():
self.view.spinBoxHighVoltage.setEnabled(True)
self.view.spinBoxHighVoltage.editingFinished.connect(self.setHighVoltage)
self.view.checkBoxHighVoltage.stateChanged.connect(self.setHighVoltage)
def setHighVoltage(self):
value = 0
if self.view.checkBoxHighVoltage.isChecked():
value = self.view.spinBoxHighVoltage.value()
try:
self.det.highvoltage = value
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "High Voltage Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
self.getHighVoltage()
def saveParameters(self) -> list:
"""
save parameters for the current tab
@return: list of commands
"""
commands = []
for i in range(Defines.dac.count):
# if checkbox disabled put -100 in dac units
enabled = getattr(self.view, f"checkBoxDAC{i}").isChecked()
if not enabled:
commands.append(f"dac {i} -100")
# else put the value in dac or mV units
else:
value = getattr(self.view, f"spinBoxDAC{i}").value()
inMV = getattr(self.view, f"checkBoxDAC{i}mV").isChecked()
unit = " mV" if inMV else ""
commands.append(f"dac {i} {value}{unit}")
commands.append(f"adcvpp {self.view.comboBoxADCVpp.currentText()} mV")
commands.append(f"highvoltage {self.view.spinBoxHighVoltage.value()}")
return commands

View File

@ -0,0 +1,456 @@
import os
from functools import partial
from pathlib import Path
from PyQt5 import QtWidgets, uic
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from pyctbgui.utils.defines import Defines
from pyctbgui.utils.plotPattern import PlotPattern
class PatternTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "pattern.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
self.plotTab = None
def setup_ui(self):
# Pattern Tab
self.plotTab = self.mainWindow.plotTab
for i in range(len(Defines.Colors)):
self.view.comboBoxPatColor.addItem(Defines.Colors[i])
self.view.comboBoxPatWaitColor.addItem(Defines.Colors[i])
self.view.comboBoxPatLoopColor.addItem(Defines.Colors[i])
for i in range(len(Defines.LineStyles)):
self.view.comboBoxPatWaitLineStyle.addItem(Defines.LineStyles[i])
self.view.comboBoxPatLoopLineStyle.addItem(Defines.LineStyles[i])
self.updateDefaultPatViewerParameters()
self.view.comboBoxPatColorSelect.setCurrentIndex(0)
self.view.comboBoxPatWait.setCurrentIndex(0)
self.view.comboBoxPatLoop.setCurrentIndex(0)
self.view.spinBoxPatClockSpacing.setValue(self.clock_vertical_lines_spacing)
self.view.checkBoxPatShowClockNumber.setChecked(self.show_clocks_number)
self.view.doubleSpinBoxLineWidth.setValue(self.line_width)
self.view.lineEditPatternFile.setText(self.det.patfname[0])
# rest gets updated after connecting to slots
# pattern viewer plot area
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self.view)
self.mainWindow.gridLayoutPatternViewer.addWidget(self.toolbar)
self.mainWindow.gridLayoutPatternViewer.addWidget(self.canvas)
self.figure.clear()
def connect_ui(self):
# For Pattern Tab
self.view.lineEditStartAddress.editingFinished.connect(self.setPatLimitAddress)
self.view.lineEditStopAddress.editingFinished.connect(self.setPatLimitAddress)
for i in range(Defines.pattern.loops_count):
getattr(self.view,
f"lineEditLoop{i}Start").editingFinished.connect(partial(self.setPatLoopStartStopAddress, i))
getattr(self.view,
f"lineEditLoop{i}Stop").editingFinished.connect(partial(self.setPatLoopStartStopAddress, i))
getattr(self.view, f"lineEditLoop{i}Wait").editingFinished.connect(partial(self.setPatLoopWaitAddress, i))
getattr(self.view,
f"spinBoxLoop{i}Repetition").editingFinished.connect(partial(self.setPatLoopRepetition, i))
getattr(self.view, f"spinBoxLoop{i}WaitTime").editingFinished.connect(partial(self.setPatLoopWaitTime, i))
self.view.pushButtonCompiler.clicked.connect(self.setCompiler)
self.view.pushButtonUncompiled.clicked.connect(self.setUncompiledPatternFile)
self.view.pushButtonPatternFile.clicked.connect(self.setPatternFile)
self.view.pushButtonLoadPattern.clicked.connect(self.loadPattern)
self.view.comboBoxPatColorSelect.currentIndexChanged.connect(self.getPatViewerColors)
self.view.comboBoxPatWait.currentIndexChanged.connect(self.getPatViewerWaitParameters)
self.view.comboBoxPatLoop.currentIndexChanged.connect(self.getPatViewerLoopParameters)
self.view.comboBoxPatColor.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatWaitColor.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatLoopColor.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatWaitLineStyle.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatLoopLineStyle.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxWaitAlpha.editingFinished.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxLoopAlpha.editingFinished.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxWaitAlphaRect.editingFinished.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxLoopAlphaRect.editingFinished.connect(self.updatePatViewerParameters)
self.view.spinBoxPatClockSpacing.editingFinished.connect(self.updatePatViewerParameters)
self.view.checkBoxPatShowClockNumber.stateChanged.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxLineWidth.editingFinished.connect(self.updatePatViewerParameters)
self.view.pushButtonViewPattern.clicked.connect(self.viewPattern)
def refresh(self):
self.getPatLimitAddress()
for i in range(Defines.pattern.loops_count):
self.getPatLoopStartStopAddress(i)
self.getPatLoopWaitAddress(i)
self.getPatLoopRepetition(i)
self.getPatLoopWaitTime(i)
# Pattern Tab functions
def getPatLimitAddress(self):
retval = self.det.patlimits
self.view.lineEditStartAddress.editingFinished.disconnect()
self.view.lineEditStopAddress.editingFinished.disconnect()
self.view.lineEditStartAddress.setText("0x{:04x}".format(retval[0]))
self.view.lineEditStopAddress.setText("0x{:04x}".format(retval[1]))
self.view.lineEditStartAddress.editingFinished.connect(self.setPatLimitAddress)
self.view.lineEditStopAddress.editingFinished.connect(self.setPatLimitAddress)
def setPatLimitAddress(self):
self.view.lineEditStartAddress.editingFinished.disconnect()
self.view.lineEditStopAddress.editingFinished.disconnect()
try:
start = int(self.view.lineEditStartAddress.text(), 16)
stop = int(self.view.lineEditStopAddress.text(), 16)
self.det.patlimits = [start, stop]
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Pattern Limit Address Fail", str(e),
QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
self.view.lineEditStartAddress.editingFinished.connect(self.setPatLimitAddress)
self.view.lineEditStopAddress.editingFinished.connect(self.setPatLimitAddress)
self.getPatLimitAddress()
def getPatLoopStartStopAddress(self, level):
retval = self.det.patloop[level]
lineEditStart = getattr(self.view, f"lineEditLoop{level}Start")
lineEditStop = getattr(self.view, f"lineEditLoop{level}Stop")
lineEditStart.editingFinished.disconnect()
lineEditStop.editingFinished.disconnect()
lineEditStart.setText("0x{:04x}".format(retval[0]))
lineEditStop.setText("0x{:04x}".format(retval[1]))
lineEditStart.editingFinished.connect(partial(self.setPatLoopStartStopAddress, level))
lineEditStop.editingFinished.connect(partial(self.setPatLoopStartStopAddress, level))
def setPatLoopStartStopAddress(self, level):
lineEditStart = getattr(self.view, f"lineEditLoop{level}Start")
lineEditStop = getattr(self.view, f"lineEditLoop{level}Stop")
lineEditStart.editingFinished.disconnect()
lineEditStop.editingFinished.disconnect()
try:
start = int(lineEditStart.text(), 16)
stop = int(lineEditStop.text(), 16)
self.det.patloop[level] = [start, stop]
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Pattern Loop Start Stop Address Fail", str(e),
QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
lineEditStart.editingFinished.connect(partial(self.setPatLoopStartStopAddress, level))
lineEditStop.editingFinished.connect(partial(self.setPatLoopStartStopAddress, level))
self.getPatLoopStartStopAddress(level)
def getPatLoopWaitAddress(self, level):
retval = self.det.patwait[level]
lineEdit = getattr(self.view, f"lineEditLoop{level}Wait")
lineEdit.editingFinished.disconnect()
lineEdit.setText("0x{:04x}".format(retval))
lineEdit.editingFinished.connect(partial(self.setPatLoopWaitAddress, level))
def setPatLoopWaitAddress(self, level):
lineEdit = getattr(self.view, f"lineEditLoop{level}Wait")
lineEdit.editingFinished.disconnect()
try:
addr = int(lineEdit.text(), 16)
self.det.patwait[level] = addr
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Pattern Wait Address Fail", str(e),
QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
lineEdit.editingFinished.connect(partial(self.setPatLoopWaitAddress, level))
self.getPatLoopWaitAddress(level)
def getPatLoopRepetition(self, level):
retval = self.det.patnloop[level]
spinBox = getattr(self.view, f"spinBoxLoop{level}Repetition")
spinBox.editingFinished.disconnect()
spinBox.setValue(retval)
spinBox.editingFinished.connect(partial(self.setPatLoopRepetition, level))
def setPatLoopRepetition(self, level):
spinBox = getattr(self.view, f"spinBoxLoop{level}Repetition")
self.det.patnloop[level] = spinBox.value()
self.getPatLoopRepetition(level)
def getPatLoopWaitTime(self, level):
retval = self.det.patwaittime[level]
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitTime")
spinBox.editingFinished.disconnect()
spinBox.setValue(retval)
spinBox.editingFinished.connect(partial(self.setPatLoopWaitTime, level))
def setPatLoopWaitTime(self, level):
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitTime")
self.det.patwaittime[level] = spinBox.value()
self.getPatLoopWaitTime(level)
def setCompiler(self):
response = QtWidgets.QFileDialog.getOpenFileName(
parent=self.mainWindow,
caption="Select a compiler file",
directory=str(Path.cwd()),
# filter='README (*.md *.ui)'
)
if response[0]:
self.view.lineEditCompiler.setText(response[0])
def setUncompiledPatternFile(self):
filt = 'Pattern code(*.py *.c)'
folder = Path(self.det.patfname[0]).parent
if not folder:
folder = Path.cwd()
response = QtWidgets.QFileDialog.getOpenFileName(parent=self.mainWindow,
caption="Select an uncompiled pattern file",
directory=str(folder),
filter=filt)
if response[0]:
self.view.lineEditUncompiled.setText(response[0])
def setPatternFile(self):
filt = 'Pattern file(*.pyat *.pat)'
folder = Path(self.det.patfname[0]).parent
if not folder:
folder = Path.cwd()
response = QtWidgets.QFileDialog.getOpenFileName(parent=self.mainWindow,
caption="Select a compiled pattern file",
directory=str(folder),
filter=filt)
if response[0]:
self.view.lineEditPatternFile.setText(response[0])
def compilePattern(self):
compilerFile = self.view.lineEditCompiler.text()
if not compilerFile:
QtWidgets.QMessageBox.warning(self.mainWindow, "Compile Fail", "No compiler selected. Please select one.",
QtWidgets.QMessageBox.Ok)
return ""
pattern_file = self.view.lineEditUncompiled.text()
# if old compile file exists, backup and remove to ensure old copy not loaded
oldFile = Path(pattern_file + 'at')
if oldFile.is_file():
print("Moving old compiled pattern file to _bck")
exit_status = os.system('mv ' + str(oldFile) + ' ' + str(oldFile) + '_bkup')
if exit_status != 0:
retval = QtWidgets.QMessageBox.question(
self.mainWindow, "Backup Fail",
"Could not make a backup of old compiled code. Proceed anyway to compile and overwrite?",
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
if retval == QtWidgets.QMessageBox.No:
return ""
compileCommand = compilerFile + ' ' + pattern_file
print(compileCommand)
print("Compiling pattern code to .pat file")
exit_status = os.system(compileCommand)
if exit_status != 0:
QtWidgets.QMessageBox.warning(self.mainWindow, "Compile Fail", "Could not compile pattern.",
QtWidgets.QMessageBox.Ok)
return ""
pattern_file += 'at'
return pattern_file
def getCompiledPatFname(self):
if self.view.checkBoxCompile.isChecked():
pattern_file = self.compilePattern()
# pat name from pattern field
else:
pattern_file = self.view.lineEditPatternFile.text()
if not pattern_file:
QtWidgets.QMessageBox.warning(self.mainWindow, "Pattern Fail",
"No pattern file selected. Please select one.", QtWidgets.QMessageBox.Ok)
return ""
return pattern_file
def loadPattern(self):
pattern_file = self.getCompiledPatFname()
if not pattern_file:
return
# load pattern
self.det.pattern = pattern_file
self.view.lineEditPatternFile.setText(self.det.patfname[0])
def getPatViewerColors(self):
colorLevel = self.view.comboBoxPatColorSelect.currentIndex()
color = self.colors_plot[colorLevel]
self.view.comboBoxPatColor.currentIndexChanged.disconnect()
self.view.comboBoxPatColor.setCurrentIndex(Defines.Colors.index(color))
self.view.comboBoxPatColor.currentIndexChanged.connect(self.updatePatViewerParameters)
def getPatViewerWaitParameters(self):
waitLevel = self.view.comboBoxPatWait.currentIndex()
color = self.colors_wait[waitLevel]
line_style = self.linestyles_wait[waitLevel]
alpha = self.alpha_wait[waitLevel]
alpha_rect = self.alpha_wait_rect[waitLevel]
self.view.comboBoxPatWaitColor.currentIndexChanged.disconnect()
self.view.comboBoxPatWaitLineStyle.currentIndexChanged.disconnect()
self.view.doubleSpinBoxWaitAlpha.editingFinished.disconnect()
self.view.doubleSpinBoxWaitAlphaRect.editingFinished.disconnect()
self.view.comboBoxPatWaitColor.setCurrentIndex(Defines.Colors.index(color))
self.view.comboBoxPatWaitLineStyle.setCurrentIndex(Defines.LineStyles.index(line_style))
self.view.doubleSpinBoxWaitAlpha.setValue(alpha)
self.view.doubleSpinBoxWaitAlphaRect.setValue(alpha_rect)
self.view.comboBoxPatWaitColor.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatWaitLineStyle.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxWaitAlpha.editingFinished.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxWaitAlphaRect.editingFinished.connect(self.updatePatViewerParameters)
def getPatViewerLoopParameters(self):
loopLevel = self.view.comboBoxPatLoop.currentIndex()
color = self.colors_loop[loopLevel]
line_style = self.linestyles_loop[loopLevel]
alpha = self.alpha_loop[loopLevel]
alpha_rect = self.alpha_loop_rect[loopLevel]
self.view.comboBoxPatLoopColor.currentIndexChanged.disconnect()
self.view.comboBoxPatLoopLineStyle.currentIndexChanged.disconnect()
self.view.doubleSpinBoxLoopAlpha.editingFinished.disconnect()
self.view.doubleSpinBoxLoopAlphaRect.editingFinished.disconnect()
self.view.comboBoxPatLoopColor.setCurrentIndex(Defines.Colors.index(color))
self.view.comboBoxPatLoopLineStyle.setCurrentIndex(Defines.LineStyles.index(line_style))
self.view.doubleSpinBoxLoopAlpha.setValue(alpha)
self.view.doubleSpinBoxLoopAlphaRect.setValue(alpha_rect)
self.view.comboBoxPatLoopColor.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.comboBoxPatLoopLineStyle.currentIndexChanged.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxLoopAlpha.editingFinished.connect(self.updatePatViewerParameters)
self.view.doubleSpinBoxLoopAlphaRect.editingFinished.connect(self.updatePatViewerParameters)
# only at start up
def updateDefaultPatViewerParameters(self):
self.colors_plot = Defines.Colors_plot.copy()
self.colors_wait = Defines.Colors_wait.copy()
self.linestyles_wait = Defines.Linestyles_wait.copy()
self.alpha_wait = Defines.Alpha_wait.copy()
self.alpha_wait_rect = Defines.Alpha_wait_rect.copy()
self.colors_loop = Defines.Colors_loop.copy()
self.linestyles_loop = Defines.Linestyles_loop.copy()
self.alpha_loop = Defines.Alpha_loop.copy()
self.alpha_loop_rect = Defines.Alpha_loop_rect.copy()
self.clock_vertical_lines_spacing = Defines.Clock_vertical_lines_spacing
self.show_clocks_number = Defines.Show_clocks_number
self.line_width = Defines.Line_width
# print('default')
# self.printPatViewerParameters()
def updatePatViewerParameters(self):
colorLevel = self.view.comboBoxPatColorSelect.currentIndex()
color = self.view.comboBoxPatColor.currentIndex()
# self.colors_plot[colorLevel] = f'tab:{Defines.Colors[color].lower()}'
self.colors_plot[colorLevel] = Defines.Colors[color]
waitLevel = self.view.comboBoxPatWait.currentIndex()
color = self.view.comboBoxPatWaitColor.currentIndex()
line_style = self.view.comboBoxPatWaitLineStyle.currentIndex()
alpha = self.view.doubleSpinBoxWaitAlpha.value()
alpha_rect = self.view.doubleSpinBoxWaitAlphaRect.value()
self.colors_wait[waitLevel] = Defines.Colors[color]
self.linestyles_wait[waitLevel] = Defines.LineStyles[line_style]
self.alpha_wait[waitLevel] = alpha
self.alpha_wait_rect[waitLevel] = alpha_rect
loopLevel = self.view.comboBoxPatLoop.currentIndex()
color = self.view.comboBoxPatLoopColor.currentIndex()
line_style = self.view.comboBoxPatLoopLineStyle.currentIndex()
alpha = self.view.doubleSpinBoxLoopAlpha.value()
alpha_rect = self.view.doubleSpinBoxLoopAlphaRect.value()
self.colors_loop[loopLevel] = Defines.Colors[color]
self.linestyles_loop[loopLevel] = Defines.LineStyles[line_style]
self.alpha_loop[loopLevel] = alpha
self.alpha_loop_rect[loopLevel] = alpha_rect
self.clock_vertical_lines_spacing = self.view.spinBoxPatClockSpacing.value()
self.show_clocks_number = self.view.checkBoxPatShowClockNumber.isChecked()
self.line_width = self.view.doubleSpinBoxLineWidth.value()
# for debugging
# self.printPatViewerParameters()
def printPatViewerParameters(self):
print('Pattern Viewer Parameters:')
print(f'\tcolor1: {self.colors_plot[0]}, color2: {self.colors_plot[1]}')
print(f"\twait color: {self.colors_wait}")
print(f"\twait linestyles: {self.linestyles_wait}")
print(f"\twait alpha: {self.alpha_wait}")
print(f"\twait alpha rect: {self.alpha_wait_rect}")
print(f"\tloop color: {self.colors_loop}")
print(f"\tloop linestyles: {self.linestyles_loop}")
print(f"\tloop alpha: {self.alpha_loop}")
print(f"\tloop alpha rect: {self.alpha_loop_rect}")
print(f'\tclock vertical lines spacing: {self.clock_vertical_lines_spacing}')
print(f'\tshow clocks number: {self.show_clocks_number}')
print(f'\tline width: {self.line_width}')
print('\n')
def viewPattern(self):
self.plotTab.showPatternViewer(True)
pattern_file = self.getCompiledPatFname()
if not pattern_file:
return
signalNames = self.det.getSignalNames()
p = PlotPattern(
pattern_file,
signalNames,
self.colors_plot,
self.colors_wait,
self.linestyles_wait,
self.alpha_wait,
self.alpha_wait_rect,
self.colors_loop,
self.linestyles_loop,
self.alpha_loop,
self.alpha_loop_rect,
self.clock_vertical_lines_spacing,
self.show_clocks_number,
self.line_width,
)
plt.close(self.figure)
self.mainWindow.gridLayoutPatternViewer.removeWidget(self.canvas)
self.canvas.close()
self.mainWindow.gridLayoutPatternViewer.removeWidget(self.toolbar)
self.toolbar.close()
try:
self.figure = p.patternPlot()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self.view)
self.mainWindow.gridLayoutPatternViewer.addWidget(self.toolbar)
self.mainWindow.gridLayoutPatternViewer.addWidget(self.canvas)
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Pattern Viewer Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
def saveParameters(self) -> list[str]:
commands = []
for i in range(Defines.pattern.loops_count):
commands.append(f"patnloop {i} {getattr(self.view, f'spinBoxLoop{i}Repetition').text()}")
commands.append(f"patloop {i} {getattr(self.view, f'lineEditLoop{i}Start').text()}, "
f"{getattr(self.view, f'lineEditLoop{i}Stop').text()}")
commands.append(f"patwait {i} {getattr(self.view, f'lineEditLoop{i}Wait').text()}")
commands.append(f"patwaittime {i} {getattr(self.view, f'spinBoxLoop{i}WaitTime').text()}")
commands.append(f"patlimits {self.view.lineEditStartAddress.text()}, {self.view.lineEditStopAddress.text()}")
# commands.append(f"patfname {self.view.lineEditPatternFile.text()}")
return commands

View File

@ -0,0 +1,519 @@
import logging
from functools import partial
import random
from pathlib import Path
import numpy as np
from PyQt5 import QtWidgets, QtGui, uic
import pyqtgraph as pg
from pyctbgui.utils import recordOrApplyPedestal
from pyqtgraph import PlotWidget
from pyctbgui.utils.defines import Defines
class PlotTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
self.frame_min: float = 0.0
self.frame_max: float = 0.0
uic.loadUi(Path(__file__).parent.parent / 'ui' / "plot.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
self.signalsTab = None
self.transceiverTab = None
self.acquisitionTab = None
self.adcTab = None
self.cmin: float = 0.0
self.cmax: float = 0.0
self.colorRangeMode: Defines.colorRange = Defines.colorRange.all
self.ignoreHistogramSignal: bool = False
self.imagePlots: list[PlotWidget] = []
# list of callback functions to notify tabs when we should hide their legend
# follows the observer design pattern
self.hideLegendObservers = []
self.pedestalRecord: bool = False
self.pedestalApply: bool = True
self.__acqFrames = None
self.logger = logging.getLogger('PlotTab')
def setup_ui(self):
self.signalsTab = self.mainWindow.signalsTab
self.transceiverTab = self.mainWindow.transceiverTab
self.acquisitionTab = self.mainWindow.acquisitionTab
self.adcTab = self.mainWindow.adcTab
self.initializeColorMaps()
self.imagePlots = (
self.mainWindow.plotAnalogImage,
self.mainWindow.plotDigitalImage,
self.mainWindow.plotTransceiverImage,
)
def connect_ui(self):
self.view.radioButtonNoPlot.clicked.connect(self.plotOptions)
self.view.radioButtonWaveform.clicked.connect(self.plotOptions)
self.view.radioButtonDistribution.clicked.connect(self.plotOptions)
self.view.radioButtonImage.clicked.connect(self.plotOptions)
self.view.comboBoxPlot.currentIndexChanged.connect(self.setPixelMap)
self.view.comboBoxColorMap.currentIndexChanged.connect(self.setColorMap)
self.view.comboBoxZMQHWM.currentIndexChanged.connect(self.setZMQHWM)
self.view.spinBoxSerialOffset.editingFinished.connect(self.setSerialOffset)
self.view.spinBoxNCount.editingFinished.connect(self.setNCounter)
self.view.spinBoxDynamicRange.editingFinished.connect(self.setDynamicRange)
self.view.spinBoxImageX.editingFinished.connect(self.setImageX)
self.view.spinBoxImageY.editingFinished.connect(self.setImageY)
self.view.radioButtonPedestalRecord.toggled.connect(self.togglePedestalRecord)
self.view.radioButtonPedestalApply.toggled.connect(self.togglePedestalApply)
self.view.pushButtonPedestalReset.clicked.connect(self.resetPedestal)
self.view.pushButtonSavePedestal.clicked.connect(self.savePedestal)
self.view.pushButtonLoadPedestal.clicked.connect(self.loadPedestal)
self.view.checkBoxRaw.stateChanged.connect(self.setRawData)
self.view.spinBoxRawMin.editingFinished.connect(self.setRawData)
self.view.spinBoxRawMax.editingFinished.connect(self.setRawData)
self.view.checkBoxPedestal.stateChanged.connect(self.setPedestalSubtract)
self.view.spinBoxPedestalMin.editingFinished.connect(self.setPedestalSubtract)
self.view.spinBoxPedestalMax.editingFinished.connect(self.setPedestalSubtract)
self.view.spinBoxFit.editingFinished.connect(self.setFitADC)
self.view.spinBoxPlot.editingFinished.connect(self.setPlotBit)
self.view.pushButtonReferesh.clicked.connect(self.acquisitionTab.refresh)
# color range widgets
self.view.cminSpinBox.editingFinished.connect(self.setCmin)
self.view.cmaxSpinBox.editingFinished.connect(self.setCmax)
self.view.radioButtonAutomatic.clicked.connect(partial(self.setColorRangeMode, Defines.colorRange.all))
self.view.radioButtonFixed.clicked.connect(partial(self.setColorRangeMode, Defines.colorRange.fixed))
self.view.radioButtonCenter.clicked.connect(partial(self.setColorRangeMode, Defines.colorRange.center))
for plot in self.imagePlots:
plot.scene.sigMouseMoved.connect(partial(self.showPlotValues, plot))
plot.getHistogramWidget().item.sigLevelChangeFinished.connect(partial(self.handleHistogramChange, plot))
self.view.checkBoxShowLegend.stateChanged.connect(self.toggleLegend)
def refresh(self):
self.getZMQHWM()
def initializeColorMaps(self):
self.view.comboBoxColorMap.addItems(Defines.Color_map)
self.view.comboBoxColorMap.setCurrentIndex(Defines.Color_map.index(Defines.Default_Color_Map))
self.setColorMap()
def savePedestal(self):
"""
slot function to save pedestal values
"""
response = QtWidgets.QFileDialog.getSaveFileName(self.view, "Save Pedestal", str(self.det.fpath))
recordOrApplyPedestal.savePedestal(Path(response[0]))
self.logger.info(f'saved Pedestal in {response[0]}')
def loadPedestal(self):
"""
slot function to load pedestal values
"""
response = QtWidgets.QFileDialog.getOpenFileName(self.view, "Load Pedestal", str(self.det.fpath))
if response[0] == '':
return
recordOrApplyPedestal.reset(self)
try:
recordOrApplyPedestal.loadPedestal(Path(response[0]))
except (IsADirectoryError, ValueError, EOFError):
QtWidgets.QMessageBox.warning(
self.view,
"Loading Pedestal Failed",
"Loading Pedestal failed make sure the file is in the valid .npy format",
QtWidgets.QMessageBox.Ok,
)
self.logger.exception("Exception when loading pedestal")
else:
self.logger.info(f'loaded Pedestal from {response[0]}')
self.updateLabelPedestalFrames(True)
def togglePedestalRecord(self):
"""
slot function for pedestal record radio button
toggle pedestal record variable and disables the frames spinboxes in acquisition tab or plot tab depenging on
the mode
"""
self.pedestalRecord = not self.pedestalRecord
def togglePedestalApply(self):
"""
slot function for pedestal apply radio button
"""
self.pedestalApply = not self.pedestalApply
def resetPedestal(self):
"""
slot function for resetting the pedestal
"""
recordOrApplyPedestal.reset(self)
def updateLabelPedestalFrames(self, loadedPedestal=False):
"""
updates labelPedestalFrames to the length of savedFrames
"""
if loadedPedestal:
self.view.labelPedestalFrames.setText('using loaded pedestal file')
else:
self.view.labelPedestalFrames.setText(f'recorded frames: {recordOrApplyPedestal.getFramesCount()}')
def subscribeToggleLegend(self, fn_cbk):
"""
subscribe to the event of toggling the hide legend checkbox by subscribing
with a callback function
"""
self.hideLegendObservers.append(fn_cbk)
def toggleLegend(self):
"""
notify subscribers for the showLegend checkbox event by executing their callbacks
"""
self.mainWindow.showLegend = not self.mainWindow.showLegend
for notify_function in self.hideLegendObservers:
notify_function()
def setCmin(self, value=None):
"""
slot for setting cmin from cminSpinBox
also used as a normal function
"""
if value is None:
self.cmin = self.view.cminSpinBox.value()
else:
self.cmin = value
self.updateColorRangeUI()
def setCmax(self, value=None):
"""
slot for setting cmax from cmaxSpinBox
also used as a normal function
"""
if value is None:
self.cmax = self.view.cmaxSpinBox.value()
else:
self.cmax = value
self.updateColorRangeUI()
def setColorRangeMode(self, mode):
"""
slot for setting the color range mode (all,fixed,3-97%)
"""
self.colorRangeMode = mode
# disable or enable cmin/cmax spinboxes
enableSpinBoxes = mode == Defines.colorRange.fixed
self.view.cminSpinBox.setEnabled(enableSpinBoxes)
self.view.cmaxSpinBox.setEnabled(enableSpinBoxes)
self.updateColorRange()
self.updateColorRangeUI()
def handleHistogramChange(self, plot):
"""
slot called after changing the color bar
This is called even when pyqtgraph sets the image without any user intervention
the class attribute ignore_histogram_signal is set to False before setting the image
so that we can distinguish between the signal originates from pyqt or from the user
"""
if not self.ignoreHistogramSignal:
self.cmin, self.cmax = plot.getHistogramWidget().item.getLevels()
self.setCmin(self.cmin)
self.setCmax(self.cmax)
self.ignoreHistogramSignal = False
# self.setColorRangeMode(Defines.colorRange.fixed)
def setFrameLimits(self, frame):
"""
function called from AcquisitionTab::read_zmq to get the maximum and minimum
values of the decoded frame and save them in frame_min/frame_max
"""
self.frame_min = np.min(frame)
self.frame_max = np.max(frame)
self.updateColorRange()
def updateColorRange(self):
"""
for mode:
- all: sets cmin and cmax to the maximums/minimum values of the frame
- 3-97%: limits cmax and cmin so that we ignore 3% from each end of the whole range
- fixed: this function does not change cmin and cmax
"""
if self.colorRangeMode == Defines.colorRange.all:
self.cmin = self.frame_min
self.cmax = self.frame_max
elif self.colorRangeMode == Defines.colorRange.center:
self.cmin = self.frame_min + 0.03 * (self.frame_max - self.frame_min)
self.cmax = self.frame_max - 0.03 * (self.frame_max - self.frame_min)
self.updateColorRangeUI()
def updateColorRangeUI(self):
"""
updates UI views should be called after every change to cmin or cmax
"""
for plot in self.imagePlots:
plot.getHistogramWidget().item.setLevels(min=self.cmin, max=self.cmax)
self.view.cminSpinBox.setValue(self.cmin)
self.view.cmaxSpinBox.setValue(self.cmax)
def setColorMap(self):
cm = pg.colormap.getFromMatplotlib(self.view.comboBoxColorMap.currentText())
# print(f'color map:{self.comboBoxColorMap.currentText()}')
self.mainWindow.plotAnalogImage.setColorMap(cm)
self.mainWindow.plotDigitalImage.setColorMap(cm)
self.mainWindow.plotTransceiverImage.setColorMap(cm)
def getZMQHWM(self):
self.view.comboBoxZMQHWM.currentIndexChanged.disconnect()
rx_zmq_hwm = self.det.getRxZmqHwm()[0]
# ensure same value in client zmq
self.det.setClientZmqHwm(rx_zmq_hwm)
# high readout, low HWM
if -1 < rx_zmq_hwm < 25:
self.view.comboBoxZMQHWM.setCurrentIndex(1)
# low readout, high HWM
else:
self.view.comboBoxZMQHWM.setCurrentIndex(0)
self.view.comboBoxZMQHWM.currentIndexChanged.connect(self.setZMQHWM)
def setZMQHWM(self):
val = self.view.comboBoxZMQHWM.currentIndex()
# low readout, high HWM
if val == 0:
self.det.setRxZmqHwm(Defines.Zmq_hwm_low_speed)
self.det.setClientZmqHwm(Defines.Zmq_hwm_low_speed)
# high readout, low HWM
else:
self.det.setRxZmqHwm(Defines.Zmq_hwm_high_speed)
self.det.setClientZmqHwm(Defines.Zmq_hwm_high_speed)
self.getZMQHWM()
def addSelectedAnalogPlots(self, i):
enable = getattr(self.adcTab.view, f"checkBoxADC{i}Plot").isChecked()
if enable:
self.mainWindow.analogPlots[i].show()
if not enable:
self.mainWindow.analogPlots[i].hide()
def addAllSelectedAnalogPlots(self):
for i in range(Defines.adc.count):
self.addSelectedAnalogPlots(i)
def removeAllAnalogPlots(self):
for i in range(Defines.adc.count):
self.mainWindow.analogPlots[i].hide()
cm = pg.colormap.get('CET-L9') # prepare a linear color map
self.mainWindow.plotDigitalImage.setColorMap(cm)
def addSelectedDigitalPlots(self, i):
enable = getattr(self.signalsTab.view, f"checkBoxBIT{i}Plot").isChecked()
if enable:
self.mainWindow.digitalPlots[i].show()
if not enable:
self.mainWindow.digitalPlots[i].hide()
def addAllSelectedDigitalPlots(self):
for i in range(Defines.signals.count):
self.addSelectedDigitalPlots(i)
def removeAllDigitalPlots(self):
for i in range(Defines.signals.count):
self.mainWindow.digitalPlots[i].hide()
def addSelectedTransceiverPlots(self, i):
enable = getattr(self.transceiverTab.view, f"checkBoxTransceiver{i}Plot").isChecked()
if enable:
self.mainWindow.transceiverPlots[i].show()
if not enable:
self.mainWindow.transceiverPlots[i].hide()
def addAllSelectedTransceiverPlots(self):
for i in range(Defines.transceiver.count):
self.addSelectedTransceiverPlots(i)
def removeAllTransceiverPlots(self):
for i in range(Defines.transceiver.count):
self.mainWindow.transceiverPlots[i].hide()
def showPlot(self):
self.mainWindow.plotAnalogWaveform.hide()
self.mainWindow.plotDigitalWaveform.hide()
self.mainWindow.plotTransceiverWaveform.hide()
self.mainWindow.plotAnalogImage.hide()
self.mainWindow.plotDigitalImage.hide()
self.mainWindow.plotTransceiverImage.hide()
self.view.labelDigitalWaveformOption.setDisabled(True)
self.view.radioButtonOverlay.setDisabled(True)
self.view.radioButtonStripe.setDisabled(True)
if self.mainWindow.romode.value in [0, 2]:
if self.view.radioButtonWaveform.isChecked():
self.mainWindow.plotAnalogWaveform.show()
elif self.view.radioButtonImage.isChecked():
self.mainWindow.plotAnalogImage.show()
if self.mainWindow.romode.value in [1, 2, 4]:
if self.view.radioButtonWaveform.isChecked():
self.mainWindow.plotDigitalWaveform.show()
elif self.view.radioButtonImage.isChecked():
self.mainWindow.plotDigitalImage.show()
self.view.labelDigitalWaveformOption.setEnabled(True)
self.view.radioButtonOverlay.setEnabled(True)
self.view.radioButtonStripe.setEnabled(True)
if self.mainWindow.romode.value in [3, 4]:
if self.view.radioButtonWaveform.isChecked():
self.mainWindow.plotTransceiverWaveform.show()
elif self.view.radioButtonImage.isChecked():
self.mainWindow.plotTransceiverImage.show()
def plotOptions(self):
self.mainWindow.framePatternViewer.hide()
self.showPlot()
# disable plotting
self.mainWindow.read_timer.stop()
if self.view.radioButtonWaveform.isChecked():
self.mainWindow.plotAnalogWaveform.setLabel(
'left', "<span style=\"color:black;font-size:14px\">Output [ADC]</span>")
self.mainWindow.plotAnalogWaveform.setLabel(
'bottom', "<span style=\"color:black;font-size:14px\">Analog Sample [#]</span>")
self.mainWindow.plotDigitalWaveform.setLabel(
'left', "<span style=\"color:black;font-size:14px\">Digital Bit</span>")
self.mainWindow.plotDigitalWaveform.setLabel(
'bottom', "<span style=\"color:black;font-size:14px\">Digital Sample [#]</span>")
self.mainWindow.plotTransceiverWaveform.setLabel(
'left', "<span style=\"color:black;font-size:14px\">Transceiver Bit</span>")
self.mainWindow.plotTransceiverWaveform.setLabel(
'bottom', "<span style=\"color:black;font-size:14px\">Transceiver Sample [#]</span>")
self.view.stackedWidgetPlotType.setCurrentIndex(0)
elif self.view.radioButtonImage.isChecked():
self.view.stackedWidgetPlotType.setCurrentIndex(2)
self.setPixelMap()
if self.view.radioButtonNoPlot.isChecked():
self.view.labelPlotOptions.hide()
self.view.stackedWidgetPlotType.hide()
# enable plotting
else:
self.view.labelPlotOptions.show()
self.view.stackedWidgetPlotType.show()
self.mainWindow.read_timer.start(Defines.Time_Plot_Refresh_ms)
def setPixelMap(self):
if self.view.comboBoxPlot.currentText() == "Matterhorn":
self.mainWindow.nTransceiverRows = Defines.Matterhorn.nRows
self.mainWindow.nTransceiverCols = Defines.Matterhorn.nCols
elif self.view.comboBoxPlot.currentText() == "Moench04":
self.mainWindow.nAnalogRows = Defines.Moench04.nRows
self.mainWindow.nAnalogCols = Defines.Moench04.nCols
def showPatternViewer(self, enable):
if enable:
self.mainWindow.framePatternViewer.show()
self.mainWindow.framePlot.hide()
elif self.mainWindow.framePatternViewer.isVisible():
self.mainWindow.framePatternViewer.hide()
self.mainWindow.framePlot.show()
self.showPlot()
def setSerialOffset(self):
print("plot options - Not implemented yet")
# TODO:
def setNCounter(self):
print("plot options - Not implemented yet")
# TODO:
def setDynamicRange(self):
print("plot options - Not implemented yet")
# TODO:
def setImageX(self):
print("plot options - Not implemented yet")
# TODO:
def setImageY(self):
print("plot options - Not implemented yet")
# TODO:
def setRawData(self):
print("plot options - Not implemented yet")
# TODO: raw data, min, max
def setPedestalSubtract(self):
print("plot options - Not implemented yet")
# TODO: pedestal, min, max
def setFitADC(self):
print("plot options - Not implemented yet")
# TODO:
def setPlotBit(self):
print("plot options - Not implemented yet")
# TODO:
def getRandomColor(self):
'''
Returns a random color range (except white) in format string eg. "#aabbcc"
'''
randomColor = random.randrange(0, 0xffffaa, 0xaa)
return "#{:06x}".format(randomColor)
def getActiveColor(self, button):
return button.palette().color(QtGui.QPalette.Window)
def setActiveColor(self, button, str_color):
button.setStyleSheet(":enabled {background-color: %s" % str_color + "} :disabled {background-color: grey}")
def showPalette(self, button):
color = QtWidgets.QColorDialog.getColor()
if color.isValid():
self.setActiveColor(button, color.name())
# get the RGB Values
# print(color.getRgb())
def showPlotValues(self, sender, pos):
x = sender.getImageItem().mapFromScene(pos).x()
y = sender.getImageItem().mapFromScene(pos).y()
val = 0
nMaxY = self.mainWindow.nAnalogRows
nMaxX = self.mainWindow.nAnalogCols
frame = self.mainWindow.analog_frame
if sender == self.mainWindow.plotDigitalImage:
nMaxY = self.mainWindow.nDigitalRows
nMaxX = self.mainWindow.nDigitalCols
frame = self.mainWindow.digital_frame
elif sender == self.mainWindow.plotTransceiverImage:
nMaxY = self.mainWindow.nTransceiverRows
nMaxX = self.mainWindow.nTransceiverCols
frame = self.mainWindow.transceiver_frame
if 0 <= x < nMaxX and 0 <= y < nMaxY and not np.array_equal(frame, []):
val = frame[int(x), int(y)]
message = f'[{x:.2f}, {y:.2f}] = {val:.2f}'
sender.setToolTip(message)
# print(message)
else:
sender.setToolTip('')
def saveParameters(self):
commands = []
if self.view.comboBoxZMQHWM.currentIndex() == 0:
commands.append(f"zmqhwm {Defines.Zmq_hwm_low_speed}")
else:
commands.append(f"zmqhwm {Defines.Zmq_hwm_high_speed}")
return commands

View File

@ -0,0 +1,123 @@
from functools import partial
from pathlib import Path
from PyQt5 import QtWidgets, uic
from pyctbgui.utils.defines import Defines
from slsdet import dacIndex
class PowerSuppliesTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "powerSupplies.ui", parent)
self.view = parent
def refresh(self):
self.updateVoltageNames()
for i in Defines.powerSupplies:
self.getVoltage(i)
self.getCurrent(i)
def connect_ui(self):
for i in Defines.powerSupplies:
spinBox = getattr(self.view, f"spinBoxV{i}")
checkBox = getattr(self.view, f"checkBoxV{i}")
spinBox.editingFinished.connect(partial(self.setVoltage, i))
checkBox.stateChanged.connect(partial(self.setVoltage, i))
self.view.pushButtonPowerOff.clicked.connect(self.powerOff)
def setup_ui(self):
for i in Defines.powerSupplies:
dac = getattr(dacIndex, f"V_POWER_{i}")
spinBox = getattr(self.view, f"spinBoxV{i}")
checkBox = getattr(self.view, f"checkBoxV{i}")
retval = self.det.getPower(dac)[0]
spinBox.setValue(retval)
if retval == 0:
checkBox.setChecked(False)
spinBox.setDisabled(True)
def updateVoltageNames(self):
retval = self.det.getPowerNames()
getattr(self.view, "checkBoxVA").setText(retval[0])
getattr(self.view, "checkBoxVB").setText(retval[1])
getattr(self.view, "checkBoxVC").setText(retval[2])
getattr(self.view, "checkBoxVD").setText(retval[3])
getattr(self.view, "checkBoxVIO").setText(retval[4])
def getVoltage(self, i):
spinBox = getattr(self.view, f"spinBoxV{i}")
checkBox = getattr(self.view, f"checkBoxV{i}")
voltageIndex = getattr(dacIndex, f"V_POWER_{i}")
label = getattr(self.view, f"labelV{i}")
spinBox.editingFinished.disconnect()
checkBox.stateChanged.disconnect()
retval = self.det.getMeasuredPower(voltageIndex)[0]
# spinBox.setValue(retval)
if retval > 1:
checkBox.setChecked(True)
if checkBox.isChecked():
spinBox.setEnabled(True)
else:
spinBox.setDisabled(True)
label.setText(f'{str(retval)} mV')
spinBox.editingFinished.connect(partial(self.setVoltage, i))
checkBox.stateChanged.connect(partial(self.setVoltage, i))
self.getVChip()
# TODO: handle multiple events when pressing enter (twice)
def setVoltage(self, i):
checkBox = getattr(self.view, f"checkBoxV{i}")
spinBox = getattr(self.view, f"spinBoxV{i}")
voltageIndex = getattr(dacIndex, f"V_POWER_{i}")
spinBox.editingFinished.disconnect()
value = 0
if checkBox.isChecked():
value = spinBox.value()
try:
self.det.setPower(voltageIndex, value)
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "Voltage Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
# TODO: (properly) disconnecting and connecting to handle multiple events (out of focus and pressing enter).
spinBox.editingFinished.connect(partial(self.setVoltage, i))
self.getVoltage(i)
self.getCurrent(i)
def getCurrent(self, i):
label = getattr(self.view, f"labelI{i}")
currentIndex = getattr(dacIndex, f"I_POWER_{i}")
retval = self.det.getMeasuredCurrent(currentIndex)[0]
label.setText(f'{str(retval)} mA')
def getVChip(self):
self.view.spinBoxVChip.setValue(self.det.getPower(dacIndex.V_POWER_CHIP)[0])
def powerOff(self):
for i in Defines.powerSupplies:
# set all voltages to 0
checkBox = getattr(self.view, f"checkBoxV{i}")
checkBox.stateChanged.disconnect()
checkBox.setChecked(False)
checkBox.stateChanged.connect(partial(self.setVoltage, i))
self.setVoltage(i)
def saveParameters(self) -> list:
commands = []
for i in Defines.powerSupplies:
enabled = getattr(self.view, f"checkBoxV{i}").isChecked()
if enabled:
value = getattr(self.view, f"spinBoxV{i}").value()
commands.append(f"v_{i.lower()} {value}")
else:
commands.append(f"v_{i.lower()} 0")
return commands

View File

@ -0,0 +1,373 @@
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.bit_utils import bit_is_set, manipulate_bit
from pyctbgui.utils.defines import Defines
from pyctbgui.utils.recordOrApplyPedestal import recordOrApplyPedestal
class SignalsTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "signals.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
self.plotTab = None
self.legend: LegendItem | None = None
self.rx_dbitoffset = None
self.rx_dbitlist = None
def refresh(self):
self.updateSignalNames()
self.updateDigitalBitEnable()
self.updateIOOut()
self.getDBitOffset()
def connect_ui(self):
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"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,
Defines.signals.half))
self.view.checkBoxBIT32_63Plot.stateChanged.connect(
partial(self.setEnableBitPlotRange, 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))
self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
def setup_ui(self):
self.plotTab = self.mainWindow.plotTab
for i in range(Defines.signals.count):
self.setDBitButtonColor(i, self.plotTab.getRandomColor())
self.initializeAllDigitalPlots()
self.legend = self.mainWindow.plotDigitalWaveform.getPlotItem().legend
self.legend.clear()
# subscribe to toggle legend
self.plotTab.subscribeToggleLegend(self.updateLegend)
def getEnabledPlots(self):
"""
return plots that are shown (checkBoxTransceiver{i}Plot is checked)
"""
enabledPlots = []
self.legend.clear()
for i in range(Defines.signals.count):
if getattr(self.view, f'checkBoxBIT{i}Plot').isChecked():
plotName = getattr(self.view, f"labelBIT{i}").text()
enabledPlots.append((self.mainWindow.digitalPlots[i], plotName))
return enabledPlots
def updateLegend(self):
"""
update the legend for the signals 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, aSamples, dSamples, rx_dbitlist, isPlottedArray, rx_dbitoffset, romode,
nADCEnabled):
"""
transform raw waveform data into a processed numpy array
@param data: raw waveform data
"""
dbitoffset = rx_dbitoffset
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)
return np.array(arr)
def processWaveformData(self, data, aSamples, dSamples):
"""
view function
plots processed waveform data
data: raw waveform data
dsamples: digital samples
asamples: analog samples
"""
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,
self.mainWindow.nADCEnabled)
irow = 0
for idx, i in enumerate(self.rx_dbitlist):
# bits enabled but not plotting
waveform = digital_array[idx]
if waveform is None:
continue
self.mainWindow.digitalPlots[i].setData(waveform)
plotName = getattr(self.view, f"labelBIT{i}").text()
waveforms[plotName] = waveform
# TODO: left axis does not show 0 to 1, but keeps increasing
if self.plotTab.view.radioButtonStripe.isChecked():
self.mainWindow.digitalPlots[i].setY(irow * 2)
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)
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotDigitalWaveform, 3)
self.mainWindow.digitalPlots = {}
waveform = np.zeros(1000)
for i in range(Defines.signals.count):
pen = pg.mkPen(color=self.getDBitButtonColor(i), width=1)
legendName = getattr(self.view, f"labelBIT{i}").text()
self.mainWindow.digitalPlots[i] = self.mainWindow.plotDigitalWaveform.plot(waveform,
pen=pen,
name=legendName,
stepMode="left")
self.mainWindow.digitalPlots[i].hide()
self.mainWindow.plotDigitalImage = pg.ImageView()
self.mainWindow.nDigitalRows = 0
self.mainWindow.nDigitalCols = 0
self.mainWindow.digital_frame = np.zeros((self.mainWindow.nDigitalRows, self.mainWindow.nDigitalCols))
self.mainWindow.plotDigitalImage.setImage(self.mainWindow.digital_frame)
self.mainWindow.verticalLayoutPlot.addWidget(self.mainWindow.plotDigitalImage, 4)
def updateSignalNames(self):
for i, name in enumerate(self.det.getSignalNames()):
getattr(self.view, f"labelBIT{i}").setText(name)
def getDigitalBitEnable(self, i, dbitList):
checkBox = getattr(self.view, f"checkBoxBIT{i}DB")
checkBox.stateChanged.disconnect()
checkBox.setChecked(i in list(dbitList))
checkBox.stateChanged.connect(partial(self.setDigitalBitEnable, i))
def updateDigitalBitEnable(self):
retval = self.det.rx_dbitlist
self.rx_dbitlist = list(retval)
self.mainWindow.nDBitEnabled = len(list(retval))
for i in range(Defines.signals.count):
self.getDigitalBitEnable(i, retval)
self.getEnableBitPlot(i)
self.getEnableBitColor(i)
self.plotTab.addSelectedDigitalPlots(i)
self.getDigitalBitEnableRange(retval)
self.getEnableBitPlotRange()
def setDigitalBitEnable(self, i):
bitList = self.det.rx_dbitlist
checkBox = getattr(self.view, f"checkBoxBIT{i}DB")
if checkBox.isChecked():
bitList.append(i)
else:
bitList.remove(i)
self.det.rx_dbitlist = bitList
self.updateDigitalBitEnable()
def getDigitalBitEnableRange(self, dbitList):
self.view.checkBoxBIT0_31DB.stateChanged.disconnect()
self.view.checkBoxBIT32_63DB.stateChanged.disconnect()
self.view.checkBoxBIT0_31DB.setChecked(all(x in list(dbitList) for x in range(Defines.signals.half)))
self.view.checkBoxBIT32_63DB.setChecked(
all(x in list(dbitList) for x in range(Defines.signals.half, Defines.signals.count)))
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))
def setDigitalBitEnableRange(self, start_nr, end_nr):
bitList = self.det.rx_dbitlist
checkBox = getattr(self.view, f"checkBoxBIT{start_nr}_{end_nr - 1}DB")
for i in range(start_nr, end_nr):
if checkBox.isChecked():
if i not in list(bitList):
bitList.append(i)
else:
if i in list(bitList):
bitList.remove(i)
self.det.rx_dbitlist = bitList
self.updateDigitalBitEnable()
def getEnableBitPlot(self, i):
checkBox = getattr(self.view, f"checkBoxBIT{i}DB")
checkBoxPlot = getattr(self.view, f"checkBoxBIT{i}Plot")
checkBoxPlot.setEnabled(checkBox.isChecked())
def setEnableBitPlot(self, i):
pushButton = getattr(self.view, f"pushButtonBIT{i}")
checkBox = getattr(self.view, f"checkBoxBIT{i}Plot")
pushButton.setEnabled(checkBox.isChecked())
self.getEnableBitPlotRange()
self.plotTab.addSelectedDigitalPlots(i)
self.updateLegend()
def getEnableBitPlotRange(self):
self.view.checkBoxBIT0_31Plot.stateChanged.disconnect()
self.view.checkBoxBIT32_63Plot.stateChanged.disconnect()
self.view.checkBoxBIT0_31Plot.setEnabled(
all(getattr(self.view, f"checkBoxBIT{i}Plot").isEnabled() for i in range(Defines.signals.half)))
self.view.checkBoxBIT32_63Plot.setEnabled(
all(
getattr(self.view, f"checkBoxBIT{i}Plot").isEnabled()
for i in range(Defines.signals.half, Defines.signals.count)))
self.view.checkBoxBIT0_31Plot.setChecked(
all(getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in range(Defines.signals.half)))
self.view.checkBoxBIT32_63Plot.setChecked(
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,
Defines.signals.half))
self.view.checkBoxBIT32_63Plot.stateChanged.connect(
partial(self.setEnableBitPlotRange, Defines.signals.half, Defines.signals.count))
def setEnableBitPlotRange(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):
checkBox = getattr(self.view, f"checkBoxBIT{i}Plot")
checkBox.setChecked(enable)
self.plotTab.addAllSelectedDigitalPlots()
def getEnableBitColor(self, i):
checkBox = getattr(self.view, f"checkBoxBIT{i}Plot")
pushButton = getattr(self.view, f"pushButtonBIT{i}")
pushButton.setEnabled(checkBox.isEnabled() and checkBox.isChecked())
def selectBitColor(self, i):
pushButton = getattr(self.view, f"pushButtonBIT{i}")
self.plotTab.showPalette(pushButton)
pen = pg.mkPen(color=self.getDBitButtonColor(i), width=1)
self.mainWindow.digitalPlots[i].setPen(pen)
def getDBitButtonColor(self, i):
pushButton = getattr(self.view, f"pushButtonBIT{i}")
return self.plotTab.getActiveColor(pushButton)
def setDBitButtonColor(self, i, color):
pushButton = getattr(self.view, f"pushButtonBIT{i}")
return self.plotTab.setActiveColor(pushButton, color)
def getIOOutReg(self):
retval = self.det.patioctrl
self.view.lineEditPatIOCtrl.editingFinished.disconnect()
self.view.lineEditPatIOCtrl.setText("0x{:016x}".format(retval))
self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg)
return retval
def setIOOutReg(self):
self.view.lineEditPatIOCtrl.editingFinished.disconnect()
try:
self.det.patioctrl = int(self.view.lineEditPatIOCtrl.text(), 16)
except Exception as e:
QtWidgets.QMessageBox.warning(self.mainWindow, "IO Out Fail", str(e), QtWidgets.QMessageBox.Ok)
pass
# TODO: handling double event exceptions
self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg)
self.updateIOOut()
def updateCheckBoxIOOut(self, i, out):
checkBox = getattr(self.view, f"checkBoxBIT{i}Out")
checkBox.stateChanged.disconnect()
checkBox.setChecked(bit_is_set(out, i))
checkBox.stateChanged.connect(partial(self.setIOOut, i))
def updateIOOut(self):
retval = self.getIOOutReg()
for i in range(Defines.signals.count):
self.updateCheckBoxIOOut(i, retval)
self.getIOoutRange(retval)
def setIOOut(self, i):
out = self.det.patioctrl
checkBox = getattr(self.view, f"checkBoxBIT{i}Out")
mask = manipulate_bit(checkBox.isChecked(), out, i)
self.det.patioctrl = mask
retval = self.getIOOutReg()
self.updateCheckBoxIOOut(i, retval)
self.getIOoutRange(retval)
def getIOoutRange(self, out):
self.view.checkBoxBIT0_31Out.stateChanged.disconnect()
self.view.checkBoxBIT32_63Out.stateChanged.disconnect()
self.view.checkBoxBIT0_31Out.setChecked((out & Defines.signals.BIT0_31_MASK) == Defines.signals.BIT0_31_MASK)
self.view.checkBoxBIT32_63Out.setChecked((out
& Defines.signals.BIT32_63_MASK) == Defines.signals.BIT32_63_MASK)
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))
def setIOOutRange(self, start_nr, end_nr):
out = self.det.patioctrl
checkBox = getattr(self.view, f"checkBoxBIT{start_nr}_{end_nr - 1}Out")
mask = getattr(Defines.signals, f"BIT{start_nr}_{end_nr - 1}_MASK")
if checkBox.isChecked():
self.det.patioctrl = out | mask
else:
self.det.patioctrl = out & ~mask
self.updateIOOut()
def getDBitOffset(self):
self.view.spinBoxDBitOffset.editingFinished.disconnect()
self.rx_dbitoffset = self.det.rx_dbitoffset
self.view.spinBoxDBitOffset.setValue(self.rx_dbitoffset)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
def setDbitOffset(self):
self.det.rx_dbitoffset = self.view.spinBoxDBitOffset.value()
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"patioctrl {self.view.lineEditPatIOCtrl.text()}")
return commands

View File

@ -0,0 +1,45 @@
from functools import partial
from pathlib import Path
from PyQt5 import uic, QtWidgets
from pyctbgui.utils.defines import Defines
from slsdet import dacIndex
class SlowAdcTab(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
uic.loadUi(Path(__file__).parent.parent / 'ui' / "slowAdcs.ui", parent)
self.view = parent
self.mainWindow = None
self.det = None
def setup_ui(self):
pass
def connect_ui(self):
for i in range(Defines.slowAdc.count):
getattr(self.view, f"pushButtonSlowAdc{i}").clicked.connect(partial(self.updateSlowAdc, i))
self.view.pushButtonTemp.clicked.connect(self.updateTemperature)
def refresh(self):
self.updateSlowAdcNames()
for i in range(Defines.slowAdc.count):
self.updateSlowAdc(i)
self.updateTemperature()
def updateSlowAdcNames(self):
for i, name in enumerate(self.mainWindow.det.getSlowADCNames()):
getattr(self.view, f"labelSlowAdc{i}").setText(name)
def updateSlowAdc(self, i):
slowADCIndex = getattr(dacIndex, f"SLOW_ADC{i}")
label = getattr(self.view, f"labelSlowAdcValue{i}")
slowadc = (self.det.getSlowADC(slowADCIndex))[0] / 1000
label.setText(f'{slowadc:.2f} mV')
def updateTemperature(self):
slowadc = self.det.getTemperature(dacIndex.SLOW_ADC_TEMP)
self.view.labelTempValue.setText(f'{str(slowadc[0])} °C')

View File

@ -0,0 +1,273 @@
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())]

View File

@ -0,0 +1,9 @@
from .ADC import AdcTab
from .Acquisition import AcquisitionTab
from .DACs import DacTab
from .Pattern import PatternTab
from .Plot import PlotTab
from .PowerSupplies import PowerSuppliesTab
from .Signals import SignalsTab
from .SlowADCs import SlowAdcTab
from .Transceiver import TransceiverTab

View File

@ -0,0 +1,779 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1444</width>
<height>943</height>
</rect>
</property>
<property name="windowTitle">
<string>Chip Test Board</string>
</property>
<property name="dockNestingEnabled">
<bool>false</bool>
</property>
<widget class="QWidget" name="centralwidget">
<property name="minimumSize">
<size>
<width>870</width>
<height>890</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>870</width>
<height>890</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>9</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>870</width>
<height>879</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frameControl">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="minimumSize">
<size>
<width>870</width>
<height>870</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>870</width>
<height>870</height>
</size>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabDac">
<attribute name="title">
<string>DACs</string>
</attribute>
<widget class="DacTab" name="widgetDacs" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>851</width>
<height>841</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>711</width>
<height>791</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabPower">
<attribute name="title">
<string>Power Supplies</string>
</attribute>
<widget class="PowerSuppliesTab" name="widgetPowerSupplies" native="true">
<property name="geometry">
<rect>
<x>-1</x>
<y>-1</y>
<width>841</width>
<height>821</height>
</rect>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabSlowAdc">
<attribute name="title">
<string>Slow ADCs</string>
</attribute>
<widget class="SlowAdcTab" name="widgetSlowAdcs" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>871</width>
<height>821</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>871</width>
<height>571</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabSignal">
<attribute name="title">
<string>Signals</string>
</attribute>
<widget class="SignalsTab" name="widgetSignals" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>831</width>
<height>821</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>831</width>
<height>821</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabTransceivers">
<attribute name="title">
<string>Transceivers</string>
</attribute>
<widget class="TransceiverTab" name="widgetTransceiver" native="true">
<property name="geometry">
<rect>
<x>9</x>
<y>19</y>
<width>841</width>
<height>341</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>181</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabAdc">
<attribute name="title">
<string>ADCs</string>
</attribute>
<widget class="AdcTab" name="widgetAdc" native="true">
<property name="geometry">
<rect>
<x>-1</x>
<y>-1</y>
<width>841</width>
<height>821</height>
</rect>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabPattern">
<attribute name="title">
<string>Pattern</string>
</attribute>
<widget class="PatternTab" name="widgetPattern" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>851</width>
<height>831</height>
</rect>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabAcquisition">
<attribute name="title">
<string>Acquisition</string>
</attribute>
<widget class="AcquisitionTab" name="widgetAcquisition" native="true">
<property name="geometry">
<rect>
<x>-10</x>
<y>0</y>
<width>860</width>
<height>800</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>860</width>
<height>800</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="tabPlot">
<attribute name="title">
<string>Plot</string>
</attribute>
<widget class="PlotTab" name="widgetPlot" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>860</width>
<height>800</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>860</width>
<height>800</height>
</size>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1444</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionLoadParameters"/>
<addaction name="actionSaveParameters"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionInfo"/>
<addaction name="actionKeyboardShortcuts"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>568</width>
<height>214</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>524287</width>
<height>524287</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::RightDockWidgetArea</set>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContent">
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="frameAcquisition">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_25">
<item row="1" column="2">
<widget class="QLabel" name="labelCurrentMeasurement">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="5">
<widget class="QProgressBar" name="progressBar">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButtonStart">
<property name="minimumSize">
<size>
<width>0</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>127</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="toolTip">
<string>Shift + Enter is the keyboard shortcut to start/stop acquisition from any tab</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {background-color: rgb(85, 170, 127);}
QPushButton:checked{background-color: red;}</string>
</property>
<property name="text">
<string>Start</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelDetectorStatus">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>IDLE</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_137">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Acquired:</string>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QLabel" name="labelAcquiredFrames">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_134">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Measurement:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<spacer name="horizontalSpacer_24">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QFrame" name="framePatternViewer">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayoutPatternViewer"/>
</widget>
</item>
<item>
<widget class="QFrame" name="framePlot">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayoutPlot">
<item>
<widget class="QLabel" name="labelFrameNumber">
<property name="text">
<string>#</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<action name="actionLoadParameters">
<property name="text">
<string>Load Parameters</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="actionInfo">
<property name="text">
<string>Info</string>
</property>
</action>
<action name="actionKeyboardShortcuts">
<property name="text">
<string>Keyboard Shortcuts</string>
</property>
</action>
<action name="actionSaveParameters">
<property name="text">
<string>Save Parameters</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>PowerSuppliesTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.PowerSupplies</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DacTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.DACs</header>
<container>1</container>
</customwidget>
<customwidget>
<class>SlowAdcTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.SlowADCs</header>
<container>1</container>
</customwidget>
<customwidget>
<class>SignalsTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.Signals</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TransceiverTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.Transceiver</header>
<container>1</container>
</customwidget>
<customwidget>
<class>AdcTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.ADC</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PatternTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.Pattern</header>
<container>1</container>
</customwidget>
<customwidget>
<class>AcquisitionTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.Acquisition</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PlotTab</class>
<extends>QWidget</extends>
<header>pyctbgui.services.Plot</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>actionExit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>753</x>
<y>496</y>
</hint>
</hints>
</connection>
</connections>
</ui>

1198
pyctbgui/pyctbgui/ui/Dacs.ui Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,369 @@
import logging
from PyQt5 import QtWidgets, QtCore, uic
import argparse
import signal
import pyqtgraph as pg
from pathlib import Path
from functools import partial
from slsdet import Detector, dacIndex
from pyctbgui.services import TransceiverTab, DacTab, AdcTab, AcquisitionTab, SignalsTab, PatternTab, \
SlowAdcTab, PlotTab, PowerSuppliesTab
from pyctbgui.utils import alias_utility
from pyctbgui.utils.defines import Defines
class MainWindow(QtWidgets.QMainWindow):
signalShortcutAcquire = QtCore.pyqtSignal()
signalShortcutTabUp = QtCore.pyqtSignal()
signalShortcutTabDown = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--alias', help="Alias file complete path")
arglist, __ = parser.parse_known_args()
self.alias_file = arglist.alias
pg.setConfigOption("background", (247, 247, 247))
pg.setConfigOption("foreground", "k")
pg.setConfigOption('leftButtonPan', False)
super().__init__(*args, **kwargs)
uic.loadUi(Path(__file__).parent / "CtbGui.ui", self)
logging.basicConfig(encoding='utf-8', level=logging.INFO)
self.logger = logging.getLogger(__name__)
self.det = None
self.showLegend = True
self.settings = None
try:
self.det = Detector()
# ensure detector is up
self.det.detectorserverversion[0]
except Exception as e:
QtWidgets.QMessageBox.critical(self, "Connect Fail", str(e) + "Exiting Gui...", QtWidgets.QMessageBox.Ok)
raise
# get Tab Classes
self.plotTab: PlotTab = self.widgetPlot
self.slowAdcTab: SlowAdcTab = self.widgetSlowAdcs
self.dacTab: DacTab = self.widgetDacs
self.powerSuppliesTab: PowerSuppliesTab = self.widgetPowerSupplies
self.signalsTab: SignalsTab = self.widgetSignals
self.transceiverTab: TransceiverTab = self.widgetTransceiver
self.adcTab: AdcTab = self.widgetAdc
self.patternTab: PatternTab = self.widgetPattern
self.acquisitionTab: AcquisitionTab = self.widgetAcquisition
self.tabs_list = [
self.dacTab, self.powerSuppliesTab, self.slowAdcTab, self.signalsTab, self.transceiverTab, self.adcTab,
self.patternTab, self.acquisitionTab, self.plotTab
]
self.setup_ui()
self.acquisitionTab.setup_zmq()
self.tabWidget.setCurrentIndex(Defines.Acquisition_Tab_Index)
self.tabWidget.currentChanged.connect(self.refresh_tab)
self.connect_ui()
for tab in self.tabs_list:
tab.refresh()
# also refreshes timer to start plotting
self.plotTab.plotOptions()
self.plotTab.showPlot()
self.patternTab.getPatViewerColors()
self.patternTab.getPatViewerWaitParameters()
self.patternTab.getPatViewerLoopParameters()
self.patternTab.updatePatViewerParameters()
self.plotTab.showPatternViewer(False)
if self.alias_file is not None:
self.loadAliasFile()
self.signalShortcutAcquire.connect(self.pushButtonStart.click)
self.signalShortcutTabUp.connect(partial(self.changeTabIndex, True))
self.signalShortcutTabDown.connect(partial(self.changeTabIndex, False))
# to catch the ctrl + c to abort
signal.signal(signal.SIGINT, signal.SIG_DFL)
self.firstAnalogImage = True
self.firstDigitalImage = True
self.firstTransceiverImage = True
self.updateSettingValues()
def updateSettingMainWindow(self):
self.settings.beginGroup("mainwindow")
# window size
width = self.settings.value('window_width')
height = self.settings.value('window_height')
if width is not None and height is not None:
self.resize(int(width), int(height))
# print(f'Main window resized to {width}x{height}')
# window position
pos = self.settings.value('window_pos')
if type(pos) is QtCore.QPoint:
# print(f'Moved main window to {pos}')
self.move(pos)
self.settings.endGroup()
def saveSettingMainWindow(self):
self.settings.beginGroup("mainwindow")
self.settings.setValue('window_width', self.rect().width())
self.settings.setValue('window_height', self.rect().height())
self.settings.setValue('window_pos', self.pos())
self.settings.endGroup()
def updateSettingDockWidget(self):
self.settings.beginGroup("dockwidget")
# is docked
if self.settings.contains('window_width') and self.settings.contains('window_height'):
# window size
width = self.settings.value('window_width')
height = self.settings.value('window_height')
if width is not None and height is not None:
# print(f'Plot window - Floating ({width}x{height})')
self.dockWidget.setFloating(True)
self.dockWidget.resize(int(width), int(height))
# window position
pos = self.settings.value('window_pos')
if type(pos) is QtCore.QPoint:
# print(f'Moved plot window to {pos}')
self.dockWidget.move(pos)
self.settings.endGroup()
def saveSettingDockWidget(self):
self.settings.beginGroup("dockwidget")
if self.dockWidget.isFloating():
self.settings.setValue('window_width', self.dockWidget.rect().width())
self.settings.setValue('window_height', self.dockWidget.rect().height())
self.settings.setValue('window_pos', self.dockWidget.pos())
else:
self.settings.remove('window_width')
self.settings.remove('window_height')
self.settings.remove('window_pos')
self.settings.endGroup()
def savePlotTypeAndDetector(self):
self.settings.setValue('isImage', self.plotTab.view.radioButtonImage.isChecked())
self.settings.setValue('detector', self.plotTab.view.comboBoxPlot.currentText())
def updatePlotTypeAndDetector(self):
# load plot type from qsettings
isImage = self.settings.value('isImage', True, type=bool)
self.plotTab.view.radioButtonImage.setChecked(isImage)
self.plotTab.plotOptions()
# load detector from qsettings
if isImage:
self.plotTab.view.comboBoxPlot.setCurrentText(self.settings.value('detector', 'Matterhorn'))
def updateSettingValues(self):
self.settings = QtCore.QSettings('slsdetectorgroup', 'pyctbgui')
self.updateSettingMainWindow()
self.updateSettingDockWidget()
self.updatePlotTypeAndDetector()
def saveSettings(self):
# store in ~/.config/slsdetectorgroup/pyctbgui.conf
self.saveSettingMainWindow()
self.saveSettingDockWidget()
self.savePlotTypeAndDetector()
def closeEvent(self, event):
self.saveSettings()
def loadAliasFile(self):
print(f'Loading Alias file: {self.alias_file}')
try:
bit_names, bit_plots, bit_colors, adc_names, adc_plots, adc_colors, dac_names, slowadc_names, \
voltage_names, pat_file_name = alias_utility.read_alias_file(self.alias_file)
except Exception as e:
QtWidgets.QMessageBox.warning(self, "Alias File Fail",
str(e) + "<br> " + self.alias_file, QtWidgets.QMessageBox.Ok)
return
for i in range(Defines.signals.count):
if bit_names[i]:
self.det.setSignalName(i, bit_names[i])
if bit_plots[i]:
getattr(self.signalsTab.view, f"checkBoxBIT{i}DB").setChecked(bit_plots[i])
getattr(self.signalsTab.view, f"checkBoxBIT{i}Plot").setChecked(bit_plots[i])
if bit_colors[i]:
self.signalsTab.setDBitButtonColor(i, bit_colors[i])
for i in range(Defines.adc.count):
if adc_names[i]:
self.det.setAdcName(i, adc_names[i])
if adc_plots[i]:
getattr(self.adcTab.view, f"checkBoxADC{i}En").setChecked(adc_plots[i])
getattr(self.adcTab.view, f"checkBoxADC{i}Plot").setChecked(adc_plots[i])
if adc_colors[i]:
self.adcTab.setADCButtonColor(i, adc_colors[i])
for i in range(Defines.dac.count):
if dac_names[i]:
iDac = getattr(dacIndex, f"DAC_{i}")
self.det.setDacName(iDac, dac_names[i])
for i in range(Defines.slowAdc.count):
slowadc_index = self.det.getSlowADCList()
if slowadc_names[i]:
self.det.setSlowADCName(slowadc_index[i], slowadc_names[i])
for i in range(len(Defines.powerSupplies)):
voltage_index = self.det.getVoltageList()
if voltage_names[i]:
self.det.setVoltageName(voltage_index[i], voltage_names[i])
if pat_file_name:
self.lineEditPatternFile.setText(pat_file_name)
self.signalsTab.updateSignalNames()
self.adcTab.updateADCNames()
self.slowAdcTab.updateSlowAdcNames()
self.dacTab.updateDACNames()
self.powerSuppliesTab.updateVoltageNames()
# For Action options function
# TODO Only add the components of action option+ functions
# Function to show info
def showInfo(self):
msg = QtWidgets.QMessageBox()
msg.setWindowTitle("About")
msg.setText("This Gui is for Chip Test Boards.\n Current Phase: Development")
msg.exec_()
def showKeyBoardShortcuts(self):
msg = QtWidgets.QMessageBox()
msg.setWindowTitle("Keyboard Shortcuts")
msg.setText(
"Start Acquisition (from any tab): Shift + Return<br>Move Tab Right : Ctrl + '+'<br>Move Tab Left :"
" Ctrl + '-'<br>")
msg.exec_()
def loadParameters(self):
response = QtWidgets.QFileDialog.getOpenFileName(
parent=self,
caption="Select a parameter file to open",
directory=str(Path.cwd()),
# filter='README (*.md *.ui)'
)
if response[0] == '':
return
try:
self.det.parameters = (response[0])
for tab in self.tabs_list:
tab.refresh()
QtWidgets.QMessageBox.information(self, "Load Parameter Success", "Parameters loaded successfully",
QtWidgets.QMessageBox.Ok)
except (RuntimeError, FileNotFoundError) as e:
self.logger.exception(e)
QtWidgets.QMessageBox.warning(self, "Load Parameter Fail", str(e), QtWidgets.QMessageBox.Ok)
def refresh_tab(self, tab_index):
match tab_index:
case 0:
self.dacTab.refresh()
case 1:
self.powerSuppliesTab.refresh()
case 2:
self.slowAdcTab.refresh()
case 3:
self.transceiverTab.refresh()
case 4:
self.signalsTab.refresh()
case 5:
self.adcTab.refresh()
case 6:
self.patternTab.refresh()
case 7:
self.acquisitionTab.refresh()
case 8:
self.plotTab.refresh()
def setup_ui(self):
# To check detector status
self.statusTimer = QtCore.QTimer()
self.statusTimer.timeout.connect(self.acquisitionTab.checkEndofAcquisition)
# To auto trigger the read
self.read_timer = QtCore.QTimer()
self.read_timer.timeout.connect(self.acquisitionTab.read_zmq)
for tab in self.tabs_list:
tab.mainWindow = self
tab.det = self.det
for tab in self.tabs_list:
tab.setup_ui()
def keyPressEvent(self, event):
if event.modifiers() & QtCore.Qt.ShiftModifier:
if event.key() == QtCore.Qt.Key_Return:
self.signalShortcutAcquire.emit()
if event.modifiers() & QtCore.Qt.ControlModifier:
if event.key() == QtCore.Qt.Key_Plus:
self.signalShortcutTabUp.emit()
if event.key() == QtCore.Qt.Key_Minus:
self.signalShortcutTabDown.emit()
def changeTabIndex(self, up):
ind = self.tabWidget.currentIndex()
if up:
ind += 1
if ind == Defines.Max_Tabs:
ind = 0
else:
ind -= 1
if ind == -1:
ind = Defines.Max_Tabs - 1
self.tabWidget.setCurrentIndex(ind)
def connect_ui(self):
# Show info
self.actionInfo.triggered.connect(self.showInfo)
self.actionKeyboardShortcuts.triggered.connect(self.showKeyBoardShortcuts)
self.actionLoadParameters.triggered.connect(self.loadParameters)
self.pushButtonStart.clicked.connect(self.acquisitionTab.toggleAcquire)
self.actionSaveParameters.triggered.connect(self.saveParameters)
for tab in self.tabs_list:
tab.connect_ui()
def saveParameters(self):
response = QtWidgets.QFileDialog.getSaveFileName(self, "Save Parameters", str(self.det.fpath))
if response[0] == '':
return
# save DACs
commands = self.dacTab.saveParameters()
# save signals
commands.extend(self.signalsTab.saveParameters())
# save transceiver
commands.extend(self.transceiverTab.saveParameters())
# save ADCs
commands.extend(self.adcTab.saveParameters())
# save pattern
commands.extend(self.patternTab.saveParameters())
# save acquisition
commands.extend(self.acquisitionTab.saveParameters())
# save power supplies
commands.extend(self.powerSuppliesTab.saveParameters())
# save plot
commands.extend(self.plotTab.saveParameters())
try:
with open(response[0], 'w') as fp:
fp.write('\n'.join(commands))
except Exception as e:
self.logger.exception(e)
QtWidgets.QMessageBox.warning(self, "Save Parameter Fail", str(e), QtWidgets.QMessageBox.Ok)
QtWidgets.QMessageBox.information(self, "Save Parameter Success", "Parameters saved successfully",
QtWidgets.QMessageBox.Ok)

View File

@ -0,0 +1 @@
from .MainWindow import MainWindow

View File

@ -0,0 +1,927 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>870</width>
<height>823</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>870</width>
<height>800</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QFrame" name="frame_20">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>841</width>
<height>71</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_19">
<item row="1" column="5">
<widget class="QSpinBox" name="spinBoxRunF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_398">
<property name="text">
<string>Read Out Mode: </string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBoxROMode">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>32</height>
</size>
</property>
<item>
<property name="text">
<string>Analog</string>
</property>
</item>
<item>
<property name="text">
<string>Digital</string>
</property>
</item>
<item>
<property name="text">
<string>Analog and Digital</string>
</property>
</item>
<item>
<property name="text">
<string>Transceiver</string>
</property>
</item>
<item>
<property name="text">
<string>Digital and Transceiver</string>
</property>
</item>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_70">
<property name="text">
<string>Run Clock Frequency (MHz):</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_13">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>841</width>
<height>51</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_24">
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxTransceiver">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelTransceiver">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Transceiver Samples:</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_15">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>841</width>
<height>201</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="2" column="3">
<widget class="QLabel" name="label_74">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>DBIT Clock Frequency (MHz):</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_71">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>ADC Clock Frequency (MHz):</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QSpinBox" name="spinBoxDBITPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="label_76">
<property name="text">
<string>DBIT Pipeline:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBoxADCF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBoxADCPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_73">
<property name="text">
<string>ADC Pipeline:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_72">
<property name="text">
<string>ADC Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_75">
<property name="text">
<string>DBIT Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QSpinBox" name="spinBoxDBITF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QSpinBox" name="spinBoxDBITPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBoxADCPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelAnalog">
<property name="text">
<string>Analog Samples:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxAnalog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelDigital">
<property name="text">
<string>Digital Samples:</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="spinBoxDigital">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_11">
<property name="geometry">
<rect>
<x>10</x>
<y>370</y>
<width>841</width>
<height>181</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_15">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_127">
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="text">
<string>Output Settings</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_129">
<property name="text">
<string>File name:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditFileName">
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>31</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(200, 219, 230);</string>
</property>
<property name="placeholderText">
<string>File Name</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_131">
<property name="text">
<string>Index:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBoxAcquisitionIndex">
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="checkBoxFileWriteRaw">
<property name="text">
<string>Raw</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButtonFilePath">
<property name="minimumSize">
<size>
<width>0</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditFilePath">
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>31</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(200, 219, 230);</string>
</property>
<property name="placeholderText">
<string>File Path</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_130">
<property name="text">
<string>File path:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="checkBoxFileWriteNumpy">
<property name="text">
<string>Numpy</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Save format:</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_53">
<property name="geometry">
<rect>
<x>10</x>
<y>570</y>
<width>841</width>
<height>141</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Number of frames:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxFrames">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>999999999</number>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_392">
<property name="text">
<string>Period (s):</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QDoubleSpinBox" name="spinBoxPeriod">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>99999.990000000005239</double>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QComboBox" name="comboBoxPeriod">
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<item>
<property name="text">
<string>s</string>
</property>
</item>
<item>
<property name="text">
<string>ms</string>
</property>
</item>
<item>
<property name="text">
<string>μs</string>
</property>
</item>
<item>
<property name="text">
<string>ns</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_393">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Number of triggers:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBoxTriggers">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_132">
<property name="text">
<string>Number of measurements:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBoxMeasurements">
<property name="minimumSize">
<size>
<width>120</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>32</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

4212
pyctbgui/pyctbgui/ui/adc.ui Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1055
pyctbgui/pyctbgui/ui/plot.ui Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,483 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>827</width>
<height>375</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QFrame" name="frame_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>381</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_12">
<item row="2" column="1">
<widget class="QSpinBox" name="spinBoxVC">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (636 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="maximum">
<number>2468</number>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLabel" name="labelID">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxVA">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (636 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="specialValueText">
<string/>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>2468</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="labelIA">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="5" column="3" colspan="2">
<widget class="QPushButton" name="pushButtonPowerOff">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton{background-color: red;}
QPushButton:disabled{background-color: grey;}</string>
</property>
<property name="text">
<string>Power off</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="labelVIO">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLabel" name="labelIC">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxVC">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VC</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBoxVIO">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (1200 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="maximum">
<number>2468</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinBoxVChip">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (1200 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="maximum">
<number>2468</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBoxVB">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VB</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QLabel" name="labelIIO">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="labelVB">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxVA">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VA</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="labelVD">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxVD">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VD</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_136">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VCHIP</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="labelVC">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBoxVD">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (636 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="maximum">
<number>2468</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBoxVIO">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>VIO</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="labelIB">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelVA">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBoxVB">
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="toolTip">
<string>Only accepts value range (636 - 2468)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> mV</string>
</property>
<property name="maximum">
<number>2468</number>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_22">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,472 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>571</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>571</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QFrame" name="frame_4">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>571</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QLabel" name="labelSlowAdc0">
<property name="text">
<string>SENSE 0:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="labelSlowAdcValue0">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc0">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="icon">
<iconset theme="update">
<normaloff>../../../../.designer</normaloff>../../../../.designer</iconset>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="labelSlowAdcValue1">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="labelSlowAdcValue3">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc3">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelSlowAdc4">
<property name="text">
<string>SENSE 4:</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="labelTempValue">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc4">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelSlowAdc5">
<property name="text">
<string>SENSE 5:</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="labelSlowAdcValue5">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc5">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelSlowAdc6">
<property name="text">
<string>SENSE 6:</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="labelSlowAdcValue6">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelSlowAdc1">
<property name="text">
<string>SENSE 1:</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc1">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelSlowAdc2">
<property name="text">
<string>SENSE 2:</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="labelSlowAdcValue4">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="labelSlowAdcValue2">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc2">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelSlowAdc3">
<property name="text">
<string>SENSE 3:</string>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc6">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="labelSlowAdc7">
<property name="text">
<string>SENSE 7:</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="labelSlowAdcValue7">
<property name="text">
<string>***</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QPushButton" name="pushButtonSlowAdc7">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="labelTemp">
<property name="text">
<string>Temperature</string>
</property>
</widget>
</item>
<item row="8" column="4">
<widget class="QPushButton" name="pushButtonTemp">
<property name="minimumSize">
<size>
<width>150</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(199, 213, 207);</string>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,542 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>239</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>181</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QFrame" name="frame_37">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>841</width>
<height>181</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>181</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_45">
<item row="5" column="0" colspan="7">
<widget class="QFrame" name="frame_38">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_46">
<item row="0" column="2">
<widget class="QLineEdit" name="lineEditTransceiverMask">
<property name="minimumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="text">
<string>0xFFFF</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_87">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Enable mask:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_43">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="checkBoxTransceiver2Plot">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Plot</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="checkBoxTransceiver1Plot">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Plot</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelTransceiver0">
<property name="minimumSize">
<size>
<width>80</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Transceiver 0</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBoxTransceiver2">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>En</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelTransceiver2">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Transceiver 2</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButtonTransceiver1">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBoxTransceiver1">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>En</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBoxTransceiver0">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>En</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelTransceiver1">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Transceiver 1</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="checkBoxTransceiver0Plot">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Plot</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelTransceiver3">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Transceiver 3</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="checkBoxTransceiver3Plot">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Plot</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="pushButtonTransceiver2">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="5">
<spacer name="horizontalSpacer_44">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkBoxTransceiver3">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>En</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="pushButtonTransceiver3">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="pushButtonTransceiver0">
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

View File

@ -0,0 +1,101 @@
from pathlib import Path
def read_alias_file(alias_file):
with open(alias_file) as fp:
lines_alias = fp.readlines()
return parse_alias_lines(lines_alias)
def parse_alias_lines(lines_alias):
bit_names = [None] * 64
bit_plots = [None] * 64
bit_colors = [None] * 64
adc_names = [None] * 32
adc_plots = [None] * 32
adc_colors = [None] * 32
dac_names = [None] * 18
sense_names = [None] * 8
power_names = [None] * 5
pat_file_name = None
for line_nr, line in enumerate(lines_alias):
ignore_list = ['PATCOMPILER']
# skip empty lines
if line == '\n' or len(line) == 0:
continue
# skip comments
if line.startswith('#'):
continue
cmd, *args = line.split()
if not args:
raise Exception(
f"Alias file parsing failed: Require atleast one argument in addition to command. ({line_nr}:{line})")
if cmd.startswith("BIT"):
process_alias_bit_or_adc(cmd, args, bit_names, bit_plots, bit_colors)
elif cmd.startswith("ADC"):
process_alias_bit_or_adc(cmd, args, adc_names, adc_plots, adc_colors)
elif cmd.startswith("DAC"):
if len(args) > 1:
raise Exception(f"Too many arguments {len(args)} (expected max: 1) for this type. ({line_nr}:{line})")
i = int(cmd[3:])
dac_names[i] = args[0]
elif cmd.startswith("SENSE"):
if len(args) > 1:
raise Exception(f"Too many arguments {len(args)} (expected max: 1) for this type. ({line_nr}:{line})")
i = int(cmd[5:])
sense_names[i] = args[0]
elif cmd in ["VA", "VB", "VC", "VD", "VIO"]:
if len(args) > 1:
raise Exception(f"Too many arguments {len(args)} (expected max: 1) for this type. ({line_nr}:{line})")
match cmd:
case "VA":
i = 0
case "VB":
i = 1
case "VC":
i = 2
case "VD":
i = 3
case "VIO":
i = 4
power_names[i] = args[0]
elif cmd == "PATFILE":
if len(args) > 1:
raise Exception(f"Too many arguments {len(args)} (expected max: 1) for this type. ({line_nr}:{line})")
pat_file_name = args[0]
path = Path(pat_file_name)
if not path.is_file():
raise Exception("Pattern file provided in alias file does not exist.<br><br>Pattern file:" +
pat_file_name)
elif cmd in ignore_list:
pass
else:
raise Exception(f"Command: {cmd} not supported. Line {line_nr}:{line}")
return bit_names, bit_plots, bit_colors, adc_names, adc_plots, adc_colors, dac_names, sense_names, power_names,\
pat_file_name
def process_alias_bit_or_adc(cmd, args, names, plots, colors):
n_args = len(args)
i = int(cmd[3:])
names[i] = args[0]
if n_args > 1:
plots[i] = bool(int(args[1]))
if n_args > 2:
colors[i] = args[2]
if n_args > 3:
raise Exception(f"Too many arguments {args} (expected max: 3) for this type in line.")

View File

@ -0,0 +1,16 @@
def set_bit(value, bit_nr):
return value | 1 << bit_nr
def remove_bit(value, bit_nr):
return value & ~(1 << bit_nr)
def bit_is_set(value, bit_nr):
return (value >> bit_nr) & 1 == 1
def manipulate_bit(is_set, value, bit_nr):
if is_set:
return set_bit(value, bit_nr)
return remove_bit(value, bit_nr)

View File

@ -0,0 +1,51 @@
from pyctbgui.utils.defines import Defines
from pyctbgui._decoder import * #bring in the function from the compiled extension
import numpy as np
"""
Python implementation, keep as a reference. Change name and replace
with C version to swap it out in the GUI
"""
def moench04(analog_buffer):
nAnalogCols = Defines.Moench04.nCols
nAnalogRows = Defines.Moench04.nRows
adcNumbers = Defines.Moench04.adcNumbers
nPixelsPerSC = Defines.Moench04.nPixelsPerSuperColumn
scWidth = Defines.Moench04.superColumnWidth
analog_frame = np.zeros((nAnalogCols, nAnalogRows), dtype=analog_buffer.dtype)
for iPixel in range(nPixelsPerSC):
for iSC, iAdc in enumerate(adcNumbers):
col = ((iAdc % 16) * scWidth) + (iPixel % scWidth)
if iSC < 16:
row = 199 - int(iPixel / scWidth)
else:
row = 200 + int(iPixel / scWidth)
index_min = iPixel * 32 + iSC
pixel_value = analog_buffer[index_min]
analog_frame[row, col] = pixel_value
return analog_frame
def matterhorn(trans_buffer):
nTransceiverRows = Defines.Matterhorn.nRows
nTransceiverCols = Defines.Matterhorn.nCols
transceiver_frame = np.zeros((nTransceiverCols, nTransceiverRows), dtype=trans_buffer.dtype)
offset = 0
nSamples = Defines.Matterhorn.nPixelsPerTransceiver
for row in range(Defines.Matterhorn.nRows):
for col in range(Defines.Matterhorn.nHalfCols):
#print(f'row:{row} col:{col} offset: {offset}')
for iTrans in range(Defines.Matterhorn.nTransceivers):
transceiver_frame[iTrans * Defines.Matterhorn.nHalfCols + col,
row] = trans_buffer[offset + nSamples * iTrans]
offset += 1
if (col + 1) % nSamples == 0:
offset += nSamples
return transceiver_frame

View File

@ -0,0 +1,111 @@
from enum import Enum
class Defines:
Time_Wait_For_Packets_ms = 0.5
Time_Status_Refresh_ms = 100
Time_Plot_Refresh_ms = 20
Zmq_hwm_high_speed = 2
Zmq_hwm_low_speed = -1
Acquisition_Tab_Index = 7
Max_Tabs = 9
class adc:
tabIndex = 5
count = 32
half = 16
BIT0_15_MASK = 0x0000FFFF
BIT16_31_MASK = 0xFFFF0000
class dac:
tabIndex = 0
count = 18
class signals:
tabIndex = 3
count = 64
half = 32
BIT0_31_MASK = 0x00000000FFFFFFFF
BIT32_63_MASK = 0xFFFFFFFF00000000
class pattern:
tabIndex = 6
loops_count = 6
class transceiver:
count = 4
tabIndex = 4
class slowAdc:
tabIndex = 2
count = 8
colCount = 4
powerSupplies = ('A', 'B', 'C', 'D', 'IO')
class ImageIndex(Enum):
Matterhorn = 0
Moench04 = 1
class Matterhorn:
nRows = 48
nHalfCols = 24
nCols = 48
nTransceivers = 2
tranceiverEnable = 0x3
nPixelsPerTransceiver = 4
class Moench04:
nRows = 400
nCols = 400
adcNumbers = [
9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
26, 25, 24
]
nPixelsPerSuperColumn = 5000
superColumnWidth = 25
Color_map = [
'viridis', 'plasma', 'inferno', 'magma', 'cividis', 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper',
'gist_rainbow', 'rainbow', 'jet', 'turbo'
]
Default_Color_Map = 'viridis'
# pattern viewer defines
# pattern plot
Colors_plot = ['Blue', 'Orange']
# Wait colors and line styles (6 needed from 0 to 5)
# Colors_wait = ['b', 'g', 'r', 'c', 'm', 'y']
Colors_wait = ['Blue', 'Green', 'Red', 'Cyan', 'Magenta', 'Yellow']
Linestyles_wait = ['--', '--', '--', '--', '--', '--']
Alpha_wait = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
Alpha_wait_rect = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
# Loop colors and line styles (6 needed from 0 to 5)
Colors_loop = ['Green', 'Red', 'Purple', 'Brown', 'Pink', 'Grey']
Linestyles_loop = ['-.', '-.', '-.', '-.', '-.', '-.']
Alpha_loop = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
Alpha_loop_rect = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
# Display the count of clocks
Clock_vertical_lines_spacing = 50
Show_clocks_number = True
Line_width = 2.0
Colors = [
'Blue', 'Orange', 'Green', 'Red', 'Purple', 'Brown', 'Pink', 'Gray', 'Olive', 'Cyan', 'Magenta', 'Yellow',
'Black', 'White'
]
LineStyles = ['-', '--', '-.', ':']
class colorRange(Enum):
all = 0
center = 1
fixed = 2

View File

@ -0,0 +1,224 @@
"""
Wrapper to be able to append frames to a numpy file
numpy header v1
- 6bytes \x93NUMPY
- 1 byte major version number \x01
- 1 byte minor version number \x00
- 2 bytes (unsigned short) HEADER_LEN length of header to follow
- Header as an ASCII dict terminated by \n padded with space \x20 to make sure
we get len(magic string) + 2 + len(length) + HEADER_LEN divisible with 64
Allocate enough space to allow for the data to grow
"""
import ast
import os
import zipfile
from pathlib import Path
import numpy as np
class NumpyFileManager:
"""
class used to read and write into .npy files that can't be loaded completely into memory
for read mode implements numpy like interface and file-like object function
"""
magic_str = np.lib.format.magic(1, 0)
headerLength = np.uint16(128)
FSEEK_FILE_END = 2
BUFFER_MAX = 500
def __init__(
self,
file: str | Path | zipfile.ZipExtFile,
mode: str = 'r',
frameShape: tuple = None,
dtype=None,
):
"""
initiates a NumpyFileManager class for reading or writing bytes directly to/from a .npy file
@param file: path to the file to open or create
@param frameShape: shape of the frame ex: (5000,) for waveforms or (400,400) for image
@param dtype: type of the numpy array's header
@param mode: file open mode must be in 'rwx'
"""
if mode not in ['r', 'w', 'x', 'r+']:
raise ValueError('file mode should be either r,w,x,r+')
if isinstance(file, zipfile.ZipExtFile):
if mode != 'r':
raise ValueError('NumpyFileManager only supports read mode for zipfiles')
else:
if mode == 'x' and Path.is_file(Path(file)):
raise FileExistsError(f'file {file} exists while given mode is x')
self.dtype = np.dtype(dtype) # in case we pass a type like np.float32
self.frameShape = frameShape
self.frameCount = 0
self.cursorPosition = self.headerLength
self.mode = mode
# if newFile frameShape and dtype should be present
if mode == 'w' or mode == 'x':
assert frameShape is not None
assert dtype is not None
# create/clear the file with mode wb+
self.file = open(file, 'wb+')
self.updateHeader()
else:
# opens file for read and check if the header of the file corresponds to the given function
# arguments
if isinstance(file, zipfile.ZipExtFile):
self.file = file
else:
mode = 'rb' if self.mode == 'r' else 'rb+'
self.file = open(file, mode)
self.file.seek(10)
headerStr = self.file.read(np.uint16(self.headerLength - 10)).decode("UTF-8")
header_dict = ast.literal_eval(headerStr)
self.frameShape = header_dict['shape'][1:]
if frameShape is not None:
assert frameShape == self.frameShape, \
f"shape in arguments ({frameShape}) is not the same as the shape of the stored " \
f"file ({self.frameShape})"
self.dtype = np.lib.format.descr_to_dtype(header_dict['descr'])
if dtype is not None:
assert dtype == self.dtype, \
f"dtype in argument ({dtype}) is not the same as the dtype of the stored file ({self.dtype})"
self.frameCount = header_dict['shape'][0]
assert not header_dict['fortran_order'], "fortran_order in the stored file is not False"
self.__frameSize = np.dtype(self.dtype).itemsize * np.prod(self.frameShape)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
def restoreCursorPosition(func):
"""
decorator function used to restore the file descriptors
cursor position after using read or write functions
"""
def wrapper(self, *args, **kwargs):
tmp = self.cursorPosition
result = func(self, *args, **kwargs)
self.cursorPosition = tmp
self.file.seek(tmp)
return result
return wrapper
@restoreCursorPosition
def updateHeader(self):
"""
updates the header of the .npy file with the class attributes
@note: fortran_order is always set to False
"""
if self.mode == 'r':
return
self.file.seek(0)
header_dict = {
'descr': np.lib.format.dtype_to_descr(self.dtype),
'fortran_order': False,
'shape': (self.frameCount, *self.frameShape)
}
np.lib.format.write_array_header_1_0(self.file, header_dict)
self.flush()
@restoreCursorPosition
def writeOneFrame(self, frame: np.ndarray):
"""
write one frame without buffering
@param frame: numpy array for a frame
"""
if frame.shape != self.frameShape:
raise ValueError(f"frame shape given {frame.shape} is not the same as the file's shape {self.frameShape}")
if frame.dtype != self.dtype:
raise ValueError(f"frame dtype given {frame.dtype} is not the same as the file's dtype {self.dtype}")
self.file.seek(0, self.FSEEK_FILE_END)
self.frameCount += 1
self.file.write(frame.tobytes())
def flush(self):
"""
persist data into disk
"""
self.file.flush()
os.fsync(self.file)
@restoreCursorPosition
def readFrames(self, frameStart: int, frameEnd: int) -> np.ndarray:
"""
read frames from .npy file without loading the whole file to memory with np.load
@param frameStart: number of the frame to start reading from
@param frameEnd: index of the last frame (not inclusive)
@return: np.ndarray of frames of the shape [frameEnd-frameStart,*self.frameShape]
"""
frameCount = frameEnd - frameStart
if frameStart < 0:
raise NotImplementedError("frameStart must be bigger than 0")
if frameCount < 0:
if frameStart <= 0:
raise NotImplementedError("frameEnd must be bigger than frameStart")
frameCount = 0
self.file.seek(self.headerLength + frameStart * self.__frameSize)
data = self.file.read(frameCount * self.__frameSize)
return np.frombuffer(data, self.dtype).reshape([-1, *self.frameShape])
def read(self, frameCount):
"""
file like interface to read frameCount frames from the already stored position
@param frameCount: number of frames to read
@return: numpy array containing frameCount frames
"""
assert frameCount > 0
data = self.file.read(frameCount * self.__frameSize)
self.cursorPosition += frameCount * self.__frameSize
return np.frombuffer(data, self.dtype).reshape([-1, *self.frameShape])
def seek(self, frameNumber):
"""
file-like interface to move the file's cursor position to the frameNumber
"""
assert frameNumber >= 0
self.cursorPosition = self.headerLength + frameNumber * self.__frameSize
self.file.seek(self.cursorPosition)
def close(self):
self.updateHeader()
self.file.close()
def __getitem__(self, item):
isSlice = False
if isinstance(item, slice):
isSlice = True
if item.step is not None:
raise NotImplementedError("step parameter is not implemented yet")
if isSlice:
return self.readFrames(item.start, item.stop)
frame = self.readFrames(item, item + 1)
if frame.size != 0:
frame = frame.squeeze(0)
return frame
def __del__(self):
"""
in case the user forgot to close the file
"""
if hasattr(self, 'file') and not self.file.closed:
try:
self.close()
except ImportError:
self.file.close()

View File

@ -0,0 +1,91 @@
from pathlib import Path
import shutil
import zipfile
import io
import numpy as np
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
class NpzFileWriter:
"""
Write data to npz file incrementally rather than compute all and write
once, as in ``np.save``. This class can be used with ``contextlib.closing``
to ensure closed after usage.
"""
def __init__(self, tofile: str, mode='w', compress_file=False):
"""
:param tofile: the ``npz`` file to write
:param mode: must be one of {'x', 'w', 'a'}. See
https://docs.python.org/3/library/zipfile.html for detail
"""
self.__openedFiles = {}
self.compression = zipfile.ZIP_DEFLATED if compress_file else zipfile.ZIP_STORED
self.tofile = tofile
self.mode = mode
self.file = zipfile.ZipFile(self.tofile, mode=self.mode, compression=self.compression)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
def writeArray(self, key: str, data: np.ndarray | bytes) -> None:
"""
overwrite existing data of name ``key``.
:param key: the name of data to write
:param data: the data
"""
key += '.npy'
with io.BytesIO() as cbuf:
np.save(cbuf, data)
cbuf.seek(0)
with self.file.open(key, mode='w', force_zip64=True) as outfile:
shutil.copyfileobj(cbuf, outfile)
def readFrames(self, file: str, frameStart: int, frameEnd: int):
file += '.npy'
with self.file.open(file, mode='r') as outfile:
npw = NumpyFileManager(outfile)
return npw.readFrames(frameStart, frameEnd)
@staticmethod
def zipNpyFiles(filename: str,
files: list[str | Path],
fileKeys: list[str],
deleteOriginals=False,
compressed=False):
compression = zipfile.ZIP_DEFLATED if compressed else zipfile.ZIP_STORED
with zipfile.ZipFile(filename, mode='w', compression=compression, allowZip64=True) as zipf:
for idx, file in enumerate(files):
zipf.write(file, arcname=fileKeys[idx] + '.npy')
if deleteOriginals:
for file in files:
Path.unlink(file)
def __getitem__(self, item: str) -> NumpyFileManager:
"""
returns NumpyFileManager file handling the .npy file under the key item inside of the .npz file
@param item:
@return:
"""
if not isinstance(item, str):
raise TypeError('given item is not of type str')
if item not in self.__openedFiles:
outfile = self.file.open(item + '.npy', mode='r')
self.__openedFiles[item] = NumpyFileManager(outfile)
return self.__openedFiles[item]
def namelist(self):
return sorted([key[:-4] for key in self.file.namelist()])
def close(self):
if hasattr(self, 'file') and self.file is not None:
self.file.close()
def __del__(self):
self.close()

View File

@ -0,0 +1,71 @@
# Using numpyWriter module
## concept
numpyWriter is used to write and load huge numpy arrays that can't be fully loaded in RAM.
It is designed to write frames of a constant shape (defined by user) and incrementally add to .npy and .npz files without accessing all of its contents
### NumpyFileManager
class to handle writing in .npy files frame by frame.
its positional parameter `file` can be of type: str,pathlib.Path, zipfile.ZipExtFile. This way we can use NumpyFileManager to open files by getting their path or
**in read mode** it can receiver file-like objects to read their data.
the complexity of initializing from file-like objects is added to be able to read from .npz files which are simply a zip of .npy files. Furthermore now we can save our files .npz files and read from them (even when compressed (⊙_⊙) ) without loading the whole .npy or .npz in memory.
### NpzFileWriter
class used to handle .npz file functionalities. it can zip existing .npy files, write a whole array in an .npz file without loading the whole .npz in memory,
and read frames from .npy files inside the .npz file
## Usage
```python
# create .npy file
npw = NumpyFileManager('file.npy', 'w', (400, 400), np.int32)
npw.addFrame(np.ones([400, 400], dtype=np.int32))
npw.close()
# read frames from existing .npy file
npw = NumpyFileManager('file.npy')
# if arr is stored in the .npy file this statement will return arr[50:100]
npw.readFrames(50, 100)
# Numpy like interface
# NumpyFileManager is also subscriptable
npw[50:100] # returns the array arr[50:100]
npw[0] # returns the array arr[0]
# File like interface
# the npw class's cursors is initialized on the first frame
npw.read(5) # reads five frames and updates the cursor
npw.seek(99) # updates the cursor to point it to the 99-th frame
# to ensure that files are written to disk
npw.flush()
# zip existing .npy files (stored on disk)
# filePaths: the paths to .npy files
# keys: name of the arrays inside of the .npz file
NpzFileWriter.zipNpyFiles('file.npz', filePaths, keys, compressed=True)
# add numpy arrays incrementally to a .npz file
with NpzFileWriter('tmp.npz', 'w', compress_file=True) as npz:
npz.writeArray('adc', arr1)
npz.writeArray('tx', arr2)
# read frames from adc.npy inside of tmp.npz
with NpzFileWriter('tmp.npz', 'r') as npz:
frames = npz.readFrames('adc', 5, 8)
# NpzFileWriter is also subscriptable and returns a NumpyFileManager initialized
# to open the the file with the given key inside the .npz file
npz = NpzFileWriter('tmp.npz', 'r')
npz.writeArray('adc', arr1)
npz['adc'] # returns a NumpyFileManager
npz['adc'][50:100] # returns the array from 50 to 100
# note once a NumpyFileManager instance is created internally NpzFileWriter stores it
# this is done to avoid opening and closing the same file
# also file-like interface can be used
npz['adc'].read(5) # returns arr[:5]
npz['adc'].seek(100) # updates the cursor
npz['adc'].read(2) # returns arr[100:2]
```

View File

@ -0,0 +1,61 @@
import numpy as np
# generate pixelmaps for various CTB detectors
def moench03():
out = np.zeros((400, 400), dtype=np.uint32)
adc_numbers = np.array(
(12, 13, 14, 15, 12, 13, 14, 15, 8, 9, 10, 11, 8, 9, 10, 11, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3, 0, 1, 2, 3),
dtype=np.int_)
for n_pixel in range(5000):
for i_sc in range(32):
adc_nr = adc_numbers[i_sc]
col = ((adc_nr * 25) + (n_pixel % 25))
row = 0
if (i_sc // 4 % 2 == 0):
row = 199 - (n_pixel // 25)
else:
row = 200 + (n_pixel // 25)
i_analog = n_pixel * 32 + i_sc
out[row, col] = i_analog
return out
def moench04_analog():
out = np.zeros((400, 400), dtype=np.uint32)
adc_numbers = np.array((9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 23, 22, 21, 20, 19, 18, 17, 16, 31,
30, 29, 28, 27, 26, 25, 24),
dtype=np.int_)
for n_pixel in range(5000):
for i_sc in range(32):
adc_nr = adc_numbers[i_sc]
col = ((adc_nr % 16) * 25) + (n_pixel % 25)
row = 0
if i_sc < 16:
row = 199 - (n_pixel // 25)
else:
row = 200 + (n_pixel // 25)
i_analog = n_pixel * 32 + i_sc
out[row, col] = i_analog
return out
def matterhorn_transceiver():
out = np.zeros((48, 48), dtype=np.uint32)
offset = 0
nSamples = 4
for row in range(48):
for col in range(24):
for iTrans in range(2):
out[iTrans * 24 + col, row] = offset + nSamples * iTrans
offset += 1
if (col + 1) % nSamples == 0:
offset += nSamples
return out

View File

@ -0,0 +1,726 @@
#!/usr/bin/env python3
"""
Created on Wed May 24 09:44:53 2017
Plot the pattern for New Chip Test Box (.pat)
Changes:
- 2017-11-21 Adapt it to python-3
- 2017-09-25 All can be plotted
- 2017-09-22 Can be plotted but the loop and wait not work yet
@author: Jiaguo Zhang and Julian Heymes
"""
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
class PlotPattern:
def __init__(self, pattern, signalNames, colors_plot, colors_wait, linestyles_wait, alpha_wait, alpha_wait_rect,
colors_loop, linestyles_loop, alpha_loop, alpha_loop_rect, clock_vertical_lines_spacing,
show_clocks_number, line_width):
self.pattern = pattern
self.signalNames = signalNames
self.verbose = False
# TODO: send alias
self.colors_plot = colors_plot.copy()
self.colors_wait = colors_wait.copy()
self.linestyles_wait = linestyles_wait.copy()
self.alpha_wait = alpha_wait.copy()
self.alpha_wait_rect = alpha_wait_rect.copy()
self.colors_loop = colors_loop.copy()
self.linestyles_loop = linestyles_loop.copy()
self.alpha_loop = alpha_loop.copy()
self.alpha_loop_rect = alpha_loop_rect.copy()
self.clock_vertical_lines_spacing = clock_vertical_lines_spacing
self.show_clocks_number = show_clocks_number
self.line_width = line_width
self.colors_plot[0] = f'xkcd:{colors_plot[0].lower()}'
self.colors_plot[1] = f'xkcd:{colors_plot[1].lower()}'
for i in range(6):
self.colors_wait[i] = f'xkcd:{colors_wait[i].lower()}'
self.colors_loop[i] = f'xkcd:{colors_loop[i].lower()}'
if self.verbose:
self.printPatViewerParameters()
def printPatViewerParameters(self):
print('Pattern Viewer Parameters:')
print(f'\tcolor1: {self.colors_plot[0]}, color2: {self.colors_plot[1]}')
print(f"\twait color: {self.colors_wait}")
print(f"\twait linestyles: {self.linestyles_wait}")
print(f"\twait alpha: {self.alpha_wait}")
print(f"\twait alpha rect: {self.alpha_wait_rect}")
print(f"\tloop color: {self.colors_loop}")
print(f"\tloop linestyles: {self.linestyles_loop}")
print(f"\tloop alpha: {self.alpha_loop}")
print(f"\tloop alpha rect: {self.alpha_loop_rect}")
print(f'\tclock vertical lines spacing: {self.clock_vertical_lines_spacing}')
print(f'\tshow clocks number: {self.show_clocks_number}')
print(f'\tline width: {self.line_width}')
print('\n')
def dec2binary(self, dec_num, width=None):
return np.binary_repr(int(dec_num), width=width)
def hex2dec(self, string_num):
return str(int(string_num.upper(), 16))
def hex2binary(self, string_num, width=None):
return self.dec2binary(self.hex2dec(string_num.upper()), width=width)
def patternPlot(self):
# Define a hex to binary function
# global definition
# base = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F]
self.base = [str(x) for x in range(10)] + [chr(x) for x in range(ord('A'), ord('A') + 6)]
# Load the pattern and get all lines
# Loop all lines
# with open(Folder + "/" + File_pat + ".pat") as f_pat:
with open(self.pattern) as f_pat:
lines_pat = f_pat.readlines()
# number of lines for pattern file
nlines_pat = len(lines_pat)
# a counter
cnt = 0
if self.verbose:
print("The total number of lines of pattern:", nlines_pat)
# Loop all lines of pattern
waittime0 = None
waittime1 = None
waittime2 = None
waittime3 = None
waittime4 = None
waittime5 = None
nloop0 = None
nloop1 = None
nloop2 = None
nloop3 = None
nloop4 = None
nloop5 = None
for k in range(nlines_pat):
# content of line
words_line = lines_pat[k].split()
if len(words_line) < 2:
continue
if words_line[0] == "patword":
# print words_line from b0 to b63
bits = self.hex2binary(words_line[-1], 64)[::-1]
if self.verbose:
print("The bits for line-", k + 1, "is:", bits)
# convert string bits to decimal array
num_bits = np.array(list(map(str, bits)), dtype="uint16")
if cnt == 0:
mat_pat = num_bits
else:
# add bits to matrix
mat_pat = np.concatenate((mat_pat, num_bits), axis=0)
cnt = cnt + 1
# print("The matrix of pattern:", mat_pat.reshape(int(cnt), int(len(num_bits))))
# Look at the io: 0 for sending to ASIC, 1 for reading from ASIC
if words_line[0] == "patioctrl":
# print words_line
if self.verbose:
print(words_line[-1])
bits = self.hex2binary(words_line[-1], 64)[::-1]
if self.verbose:
print(bits)
# convert string bits to decimal array
self.out_bits = np.array(list(map(str, bits)), dtype="uint16")
if self.verbose:
print(words_line)
# Deal with waiting point
# ====== WAIT ======
if words_line[0] == "patwait" and words_line[1] == "0":
wait0 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 0 at:", wait0)
if words_line[0] == "patwaittime" and words_line[1] == "0":
waittime0 = int(words_line[2])
if self.verbose:
print("wait 0 for:", waittime0)
if words_line[0] == "patwait" and words_line[1] == "1":
wait1 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 1 at:", wait1)
if words_line[0] == "patwaittime" and words_line[1] == "1":
waittime1 = int(words_line[2])
if self.verbose:
print("wait 1 for:", waittime1)
if words_line[0] == "patwait" and words_line[1] == "2":
wait2 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 2 at:", wait2)
if words_line[0] == "patwaittime" and words_line[1] == "2":
waittime2 = int(words_line[2])
if self.verbose:
print("wait 2 for:", waittime2)
if words_line[0] == "patwait" and words_line[1] == "3":
wait3 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 0 at:", wait3)
if words_line[0] == "patwaittime" and words_line[1] == "3":
waittime3 = int(words_line[2])
if self.verbose:
print("wait 0 for:", waittime3)
if words_line[0] == "patwait" and words_line[1] == "4":
wait4 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 1 at:", wait4)
if words_line[0] == "patwaittime" and words_line[1] == "4":
waittime4 = int(words_line[2])
if self.verbose:
print("wait 1 for:", waittime4)
if words_line[0] == "patwait" and words_line[1] == "5":
wait5 = int(self.hex2dec(words_line[2]))
if self.verbose:
print("wait 2 at:", wait5)
if words_line[0] == "patwaittime" and words_line[1] == "5":
waittime5 = int(words_line[2])
if self.verbose:
print("wait 2 for:", waittime5)
# ====== LOOPS ======
if words_line[0] == "patloop" and words_line[1] == "0":
loop0_start = int(self.hex2dec(words_line[2]))
loop0_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 0 start:", loop0_start, ", end:", loop0_end)
if words_line[0] == "patnloop" and words_line[1] == "0":
nloop0 = int(words_line[2])
if self.verbose:
print("loop 0 times:", nloop0)
if words_line[0] == "patloop" and words_line[1] == "1":
loop1_start = int(self.hex2dec(words_line[2]))
loop1_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 1 start:", loop1_start, ", end:", loop1_end)
if words_line[0] == "patnloop" and words_line[1] == "1":
nloop1 = int(words_line[2])
if self.verbose:
print("loop 1 times:", nloop1)
if words_line[0] == "patloop" and words_line[1] == "2":
loop2_start = int(self.hex2dec(words_line[2]))
loop2_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 2 start:", loop2_start, ", end:", loop2_end)
if words_line[0] == "patnloop" and words_line[1] == "2":
nloop2 = int(words_line[2])
if self.verbose:
print("loop 2 times:", nloop2)
if words_line[0] == "patloop" and words_line[1] == "3":
loop3_start = int(self.hex2dec(words_line[2]))
loop3_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 3 start:", loop3_start, ", end:", loop3_end)
if words_line[0] == "patnloop" and words_line[1] == "3":
nloop3 = int(words_line[2])
if self.verbose:
print("loop 3 times:", nloop3)
if words_line[0] == "patloop" and words_line[1] == "4":
loop4_start = int(self.hex2dec(words_line[2]))
loop4_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 4 start:", loop4_start, ", end:", loop4_end)
if words_line[0] == "patnloop" and words_line[1] == "4":
nloop4 = int(words_line[2])
if self.verbose:
print("loop 4 times:", nloop4)
if words_line[0] == "patloop" and words_line[1] == "5":
loop5_start = int(self.hex2dec(words_line[2]))
loop5_end = int(self.hex2dec(words_line[3]))
if self.verbose:
print("loop 5 start:", loop5_start, ", end:", loop5_end)
if words_line[0] == "patnloop" and words_line[1] == "5":
nloop5 = int(words_line[2])
if self.verbose:
print("loop 5 times:", nloop5)
# no patioctrl commands read
if not hasattr(self, 'out_bits'):
raise Exception("No patioctrl command found in pattern file")
# print(self.out_bits)
# internal counter
avail_index = []
avail_name = []
# Remove non-used bits
for i in range(64):
# if self.out_bits[0][i] == 1:
if self.out_bits[i] == 1:
avail_index.append(i)
avail_name.append(self.signalNames[i])
if self.verbose:
print(avail_index)
print(avail_name)
# number of effective used bits
nbiteff = len(avail_name)
# subMat = mat_ext[:,index]
# print(mat_pat.shape)
subMat = mat_pat.reshape(int(cnt), int(len(num_bits)))[0:, avail_index]
# subMat = mat_pat[avail_index]
# timing = np.linspace(0, subMat.shape[0] - 1, subMat.shape[0])
plt.rcParams['figure.figsize'] = 15, 5
# ============= PLOTTING =============
plt.rcParams["font.weight"] = "bold"
plt.rcParams["axes.labelweight"] = "bold"
fig, axs = plt.subplots(nbiteff, sharex='all')
plt.subplots_adjust(wspace=0, hspace=0)
# axs[nbiteff - 1].set(xlabel='Timing [clk]')
for idx, i in enumerate(range(nbiteff)):
axs[idx].tick_params(axis='x', labelsize=6)
axs[idx].plot(subMat.T[i],
"-",
drawstyle="steps-post",
linewidth=self.line_width,
color=self.colors_plot[idx % 2])
x_additional = range(len(subMat.T[i]) - 1, len(subMat.T[i]) + 2)
additional_stuff = [subMat.T[i][-1]] * 3
axs[idx].plot(x_additional,
additional_stuff,
"--",
drawstyle="steps-post",
linewidth=self.line_width,
color=self.colors_plot[idx % 2],
alpha=0.5)
axs[idx].yaxis.set_ticks([0.5], minor=False)
axs[idx].xaxis.set_ticks(np.arange(0, len(subMat.T[i]) + 10, self.clock_vertical_lines_spacing))
axs[idx].yaxis.set_ticklabels([avail_name[i]])
axs[idx].get_yticklabels()[0].set_color(self.colors_plot[idx % 2])
axs[idx].grid(1, 'both', 'both', alpha=0.5)
axs[idx].yaxis.grid(which="both", color=self.colors_plot[idx % 2], alpha=0.2)
if idx != nbiteff - 1:
if not self.show_clocks_number:
axs[idx].xaxis.set_ticklabels([])
axs[idx].set(xlabel=' ', ylim=(-0.2, 1.2))
else:
axs[idx].set(xlabel='Timing [clk]', ylim=(-0.2, 1.2))
# axs[idx].set_xlim(left=0)
axs[idx].set_xlim(left=0, right=len(subMat.T[i]) + 1)
axs[idx].spines['top'].set_visible(False)
axs[idx].spines['right'].set_alpha(0.2)
axs[idx].spines['right'].set_visible(True)
axs[idx].spines['bottom'].set_visible(False)
axs[idx].spines['left'].set_visible(False)
# =====================================================================================================
# Plot the wait lines
# Wait 0
if waittime0 is not None:
if waittime0 == 0:
axs[idx].plot([wait0, wait0], [-10, 10],
linestyle=self.linestyles_wait[0],
color=self.colors_wait[0],
alpha=self.alpha_wait[0],
linewidth=self.line_width)
axs[idx].plot([wait0 + 1, wait0 + 1], [-10, 10],
linestyle=self.linestyles_wait[0],
color=self.colors_wait[0],
linewidth=self.line_width,
alpha=self.alpha_wait[0])
axs[idx].add_patch(
Rectangle((wait0, -10),
1,
20,
label="wait 0: skipped" if idx == 0 else "",
facecolor=self.colors_wait[0],
alpha=self.alpha_wait_rect[0],
hatch='\\\\'))
else:
axs[idx].plot([wait0, wait0], [-10, 10],
linestyle=self.linestyles_wait[0],
color=self.colors_wait[0],
label="wait 0: " + str(waittime0) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[0])
# Wait 1
if waittime1 is not None:
if waittime1 == 0:
axs[idx].plot([wait1, wait1], [-10, 10],
linestyle=self.linestyles_wait[1],
color=self.colors_wait[1],
alpha=self.alpha_wait[1],
linewidth=self.line_width)
axs[idx].plot([wait1 + 1, wait1 + 1], [-10, 10],
linestyle=self.linestyles_wait[1],
color=self.colors_wait[1],
linewidth=self.line_width,
alpha=self.alpha_wait[1])
axs[idx].add_patch(
Rectangle((wait1, -10),
1,
20,
label="wait 1: skipped" if idx == 0 else "",
facecolor=self.colors_wait[1],
alpha=self.alpha_wait_rect[1],
hatch='\\\\'))
else:
axs[idx].plot([wait1, wait1], [-10, 10],
linestyle=self.linestyles_wait[1],
color=self.colors_wait[1],
label="wait 1: " + str(waittime1) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[1])
# Wait 2
if waittime2 is not None:
if waittime2 == 0:
axs[idx].plot([wait2, wait2], [-10, 10],
linestyle=self.linestyles_wait[2],
color=self.colors_wait[2],
alpha=self.alpha_wait[2],
linewidth=self.line_width)
axs[idx].plot([wait2 + 1, wait2 + 1], [-10, 10],
linestyle=self.linestyles_wait[2],
color=self.colors_wait[2],
linewidth=self.line_width,
alpha=self.alpha_wait[2])
axs[idx].add_patch(
Rectangle((wait2, -10),
1,
20,
label="wait 2: skipped" if idx == 0 else "",
facecolor=self.colors_wait[2],
alpha=self.alpha_wait_rect[2],
hatch='\\\\'))
else:
axs[idx].plot([wait2, wait2], [-10, 10],
linestyle=self.linestyles_wait[2],
color=self.colors_wait[2],
label="wait 2: " + str(waittime2) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[2])
# Wait 3
if waittime3 is not None:
if waittime3 == 0:
axs[idx].plot([wait3, wait3], [-10, 10],
linestyle=self.linestyles_wait[3],
color=self.colors_wait[3],
alpha=self.alpha_wait[3],
linewidth=self.line_width)
axs[idx].plot([wait3 + 1, wait3 + 1], [-10, 10],
linestyle=self.linestyles_wait[3],
color=self.colors_wait[3],
linewidth=self.line_width,
alpha=self.alpha_wait[3])
axs[idx].add_patch(
Rectangle((wait3, -10),
1,
20,
label="wait 3: skipped" if idx == 0 else "",
facecolor=self.colors_wait[3],
alpha=self.alpha_wait_rect[3],
hatch='\\\\'))
else:
axs[idx].plot([wait3, wait3], [-10, 10],
linestyle=self.linestyles_wait[3],
color=self.colors_wait[3],
label="wait 3: " + str(waittime3) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[3])
# Wait 4
if waittime4 is not None:
if waittime4 == 0:
axs[idx].plot([wait4, wait4], [-10, 10],
linestyle=self.linestyles_wait[4],
color=self.colors_wait[4],
alpha=self.alpha_wait[4],
linewidth=self.line_width)
axs[idx].plot([wait4 + 1, wait4 + 1], [-10, 10],
linestyle=self.linestyles_wait[4],
color=self.colors_wait[4],
linewidth=self.line_width,
alpha=self.alpha_wait[4])
axs[idx].add_patch(
Rectangle((wait4, -10),
1,
20,
label="wait 4: skipped" if idx == 0 else "",
facecolor=self.colors_wait[4],
alpha=self.alpha_wait_rect[4],
hatch='\\\\'))
else:
axs[idx].plot([wait4, wait4], [-10, 10],
linestyle=self.linestyles_wait[4],
color=self.colors_wait[4],
label="wait 4: " + str(waittime4) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[4])
# Wait 5
if waittime5 is not None:
if waittime5 == 0:
axs[idx].plot([wait5, wait5], [-10, 10],
linestyle=self.linestyles_wait[5],
color=self.colors_wait[5],
alpha=self.alpha_wait[5],
linewidth=self.line_width)
axs[idx].plot([wait5 + 1, wait5 + 1], [-10, 10],
linestyle=self.linestyles_wait[5],
color=self.colors_wait[5],
linewidth=self.line_width,
alpha=self.alpha_wait[5])
axs[idx].add_patch(
Rectangle((wait5, -10),
1,
20,
label="wait 5: skipped" if idx == 0 else "",
facecolor=self.colors_wait[5],
alpha=self.alpha_wait_rect[5],
hatch='\\\\'))
else:
axs[idx].plot([wait5, wait5], [-10, 10],
linestyle=self.linestyles_wait[5],
color=self.colors_wait[5],
label="wait 5: " + str(waittime5) + " clk" if idx == 0 else "",
linewidth=self.line_width,
alpha=self.alpha_wait[5])
# =====================================================================================================
# Plot the loop lines
# Loop 0
if nloop0 is not None:
if nloop0 == 0:
axs[idx].plot([loop0_start, loop0_start], [-10, 10],
linestyle=self.linestyles_loop[0],
color=self.colors_loop[0],
alpha=self.alpha_loop[0],
linewidth=self.line_width)
axs[idx].plot([loop0_end + 1, loop0_end + 1], [-10, 10],
linestyle=self.linestyles_loop[0],
color=self.colors_loop[0],
alpha=self.alpha_loop[0],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop0_start, -10),
loop0_end + 1 - loop0_start,
20,
label="loop 0: skipped" if idx == 0 else "",
facecolor=self.colors_loop[0],
alpha=self.alpha_loop_rect[0],
hatch='//'))
else:
axs[idx].plot([loop0_start, loop0_start], [-10, 10],
linestyle=self.linestyles_loop[0],
color=self.colors_loop[0],
alpha=self.alpha_loop[0],
label="loop 0: " + str(nloop0) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop0_end, loop0_end], [-10, 10],
linestyle=self.linestyles_loop[0],
color=self.colors_loop[0],
alpha=self.alpha_loop[0],
linewidth=self.line_width)
# Loop 1
if nloop1 is not None:
if nloop1 == 0:
axs[idx].plot([loop1_start, loop1_start], [-10, 10],
linestyle=self.linestyles_loop[1],
color=self.colors_loop[1],
alpha=self.alpha_loop[1],
linewidth=self.line_width)
axs[idx].plot([loop1_end + 1, loop1_end + 1], [-10, 10],
linestyle=self.linestyles_loop[1],
color=self.colors_loop[1],
alpha=self.alpha_loop[1],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop1_start, -10),
loop1_end + 1 - loop1_start,
20,
label="loop 1: skipped" if idx == 0 else "",
facecolor=self.colors_loop[1],
alpha=self.alpha_loop_rect[1],
hatch='//'))
else:
axs[idx].plot([loop1_start, loop1_start], [-10, 10],
linestyle=self.linestyles_loop[1],
color=self.colors_loop[1],
alpha=self.alpha_loop[1],
label="loop 1: " + str(nloop1) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop1_end, loop1_end], [-10, 10],
linestyle=self.linestyles_loop[1],
color=self.colors_loop[1],
alpha=self.alpha_loop[1],
linewidth=self.line_width)
# Loop 2
if nloop2 is not None:
if nloop2 == 0:
axs[idx].plot([loop2_start, loop2_start], [-10, 10],
linestyle=self.linestyles_loop[2],
color=self.colors_loop[2],
alpha=self.alpha_loop[2],
linewidth=self.line_width)
axs[idx].plot([loop2_end + 1, loop2_end + 1], [-10, 10],
linestyle=self.linestyles_loop[2],
color=self.colors_loop[2],
alpha=self.alpha_loop[2],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop2_start, -10),
loop2_end + 1 - loop2_start,
20,
label="loop 2: skipped" if idx == 0 else "",
facecolor=self.colors_loop[2],
alpha=self.alpha_loop_rect[2],
hatch='//'))
else:
axs[idx].plot([loop2_start, loop2_start], [-10, 10],
linestyle=self.linestyles_loop[2],
color=self.colors_loop[2],
alpha=self.alpha_loop[2],
label="loop 2: " + str(nloop2) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop2_end, loop2_end], [-10, 10],
linestyle=self.linestyles_loop[2],
color=self.colors_loop[2],
alpha=self.alpha_loop[2],
linewidth=self.line_width)
# Loop 3
if nloop3 is not None:
if nloop3 == 0:
axs[idx].plot([loop3_start, loop3_start], [-10, 10],
linestyle=self.linestyles_loop[3],
color=self.colors_loop[3],
alpha=self.alpha_loop[3],
linewidth=self.line_width)
axs[idx].plot([loop3_end + 1, loop3_end + 1], [-10, 10],
linestyle=self.linestyles_loop[3],
color=self.colors_loop[3],
alpha=self.alpha_loop[3],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop3_start, -10),
loop3_end + 1 - loop3_start,
20,
label="loop 3: skipped" if idx == 0 else "",
facecolor=self.colors_loop[3],
alpha=self.alpha_loop_rect[3],
hatch='//'))
else:
axs[idx].plot([loop3_start, loop3_start], [-10, 10],
linestyle=self.linestyles_loop[3],
color=self.colors_loop[3],
alpha=self.alpha_loop[3],
label="loop 3: " + str(nloop3) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop3_end, loop3_end], [-10, 10],
linestyle=self.linestyles_loop[3],
color=self.colors_loop[3],
alpha=self.alpha_loop[3],
linewidth=self.line_width)
# Loop 4
if nloop4 is not None:
if nloop4 == 0:
axs[idx].plot([loop4_start, loop4_start], [-10, 10],
linestyle=self.linestyles_loop[4],
color=self.colors_loop[4],
alpha=self.alpha_loop[4],
linewidth=self.line_width)
axs[idx].plot([loop4_end + 1, loop4_end + 1], [-10, 10],
linestyle=self.linestyles_loop[4],
color=self.colors_loop[4],
alpha=self.alpha_loop[4],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop4_start, -10),
loop4_end + 1 - loop4_start,
20,
label="loop 4: skipped" if idx == 0 else "",
facecolor=self.colors_loop[4],
alpha=self.alpha_loop_rect[4],
hatch='//'))
else:
axs[idx].plot([loop4_start, loop4_start], [-10, 10],
linestyle=self.linestyles_loop[4],
color=self.colors_loop[4],
alpha=self.alpha_loop[4],
label="loop 4: " + str(nloop4) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop4_end, loop4_end], [-10, 10],
linestyle=self.linestyles_loop[4],
color=self.colors_loop[4],
alpha=self.alpha_loop[4],
linewidth=self.line_width)
# Loop 5
if nloop5 is not None:
if nloop5 == 0:
axs[idx].plot([loop5_start, loop5_start], [-10, 10],
linestyle=self.linestyles_loop[5],
color=self.colors_loop[5],
alpha=self.alpha_loop[5],
linewidth=self.line_width)
axs[idx].plot([loop5_end + 1, loop5_end + 1], [-10, 10],
linestyle=self.linestyles_loop[5],
color=self.colors_loop[5],
alpha=self.alpha_loop[5],
linewidth=self.line_width)
axs[idx].add_patch(
Rectangle((loop5_start, -10),
loop5_end + 1 - loop5_start,
20,
label="loop 5: skipped" if idx == 0 else "",
facecolor=self.colors_loop[5],
alpha=self.alpha_loop_rect[5],
hatch='//'))
else:
axs[idx].plot([loop5_start, loop5_start], [-10, 10],
linestyle=self.linestyles_loop[5],
color=self.colors_loop[5],
alpha=self.alpha_loop[5],
label="loop 5: " + str(nloop5) + " times" if idx == 0 else "",
linewidth=self.line_width)
axs[idx].plot([loop5_end, loop5_end], [-10, 10],
linestyle=self.linestyles_loop[5],
color=self.colors_loop[5],
alpha=self.alpha_loop[5],
linewidth=self.line_width)
n_cols = np.count_nonzero([
waittime0 != 0, waittime1 != 0, waittime2 != 0, waittime3 != 0, waittime4 != 0, waittime5 != 0, nloop0
!= 0, nloop1 != 0, nloop2 != 0, nloop3 != 0, nloop4 != 0, nloop5 != 0
])
if n_cols > 0:
fig.legend(loc="upper center", ncol=n_cols)
return fig

View File

@ -0,0 +1,100 @@
import logging
from pathlib import Path
import numpy as np
__frameCount = 0
__pedestalSum = np.array(0, np.float64)
__pedestal = np.array(0, np.float32)
__loadedPedestal = False
def reset(plotTab):
global __frameCount, __pedestalSum, __pedestal, __loadedPedestal
__frameCount = 0
__pedestalSum = np.array(0, np.float64)
__pedestal = np.array(0, np.float64)
__loadedPedestal = False
plotTab.updateLabelPedestalFrames()
def getFramesCount():
return __frameCount
def getPedestal():
return __pedestal
def calculatePedestal():
global __pedestalSum, __pedestal
if __loadedPedestal:
return __pedestal
if __frameCount == 0:
__pedestal = np.array(0, np.float64)
else:
__pedestal = __pedestalSum / __frameCount
return __pedestal
def savePedestal(path=Path('/tmp/pedestal')):
pedestal = calculatePedestal()
np.save(path, pedestal)
def loadPedestal(path: Path):
global __pedestal, __loadedPedestal
__loadedPedestal = True
__pedestal = np.load(path)
__logger = logging.getLogger('recordOrApplyPedestal')
def recordOrApplyPedestal(func):
"""
decorator function used to apply pedestal functionalities
@param func: processing function that needs to be wrapped
@return: wrapper function to be called
"""
def wrapper(obj, *args, **kwargs):
"""
wrapeer that calls func (a raw data _processing function) and calculates or applies a pedestal to it
@param obj: reference to func's class instance (self of its class)
@return: if record mode: return frame untouched, if apply mode: return frame - pedestal
"""
global __frameCount, __pedestal, __pedestalSum
frame = func(obj, *args, **kwargs)
if not np.array_equal(0, __pedestalSum) and __pedestalSum.shape != frame.shape:
# check if __pedestalSum has same different shape as the frame
__logger.info('pedestal shape mismatch. resetting pedestal...')
reset(obj.plotTab)
if obj.plotTab.pedestalRecord:
if __loadedPedestal:
# reset loaded pedestal if we acquire in record mode
__logger.warning('resetting loaded pedestal...')
reset(obj.plotTab)
__frameCount += 1
__pedestalSum = np.add(__pedestalSum, frame, dtype=np.float64)
obj.plotTab.updateLabelPedestalFrames()
return frame
if obj.plotTab.pedestalApply:
# apply pedestal
# check if pedestal is calculated
if __loadedPedestal and frame.shape != __pedestal.shape:
__logger.warning('pedestal shape mismatch. resetting pedestal...')
obj.plotTab.mainWindow.statusbar.setStyleSheet("color:red")
obj.plotTab.mainWindow.statusbar.showMessage('pedestal shape mismatch. resetting pedestal...')
reset(obj.plotTab)
return frame - calculatePedestal()
return frame
return wrapper

55
pyctbgui/pyproject.toml Normal file
View File

@ -0,0 +1,55 @@
[build-system]
requires = ["setuptools", "numpy"]
build-backend = "setuptools.build_meta"
[tool.ruff]
line-length = 119
select = ["E","F","UP","PT","RET","SLF","TID","PTH","NPY"]
# other usefule rules "N" "PL"
# rules to ignore
# PTH123 causes issues with gh actions
ignore = ["UP032","PTH123"]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
target-version = "py311"
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]
"pyctbgui/utils/decoder.py" = ["F403"]
[tool.yapf]
based_on_style = "pep8"
COLUMN_LIMIT = 119
[tool.coverage.run]
branch = false
[tool.coverage.report]
include = [
"pyctbgui/*"
]

44
pyctbgui/setup.py Normal file
View File

@ -0,0 +1,44 @@
import setuptools
import numpy as np
c_ext = setuptools.Extension("pyctbgui._decoder",
sources=["src/decoder.c", "src/pm_decode.c"],
include_dirs=[
np.get_include(),
"src/",
],
extra_compile_args=['-std=c99', '-Wall', '-Wextra'])
c_ext.language = 'c'
setuptools.setup(
name='pyctbgui',
version='2023.8.17',
description='Experimental GUI for the chip test board',
packages=setuptools.find_packages(exclude=[
'tests',
]),
include_package_data=True,
ext_modules=[c_ext],
scripts=[
'CtbGui',
],
python_requires='>=3.10', # using match statement
install_requires=[
'numpy',
'pyzmq',
'pillow',
'PyQt5',
'pyqtgraph',
'matplotlib',
# 'slsdet', not yet available on pypi, maybe v8
],
extras_require={
'dev': [
'pytest==7.4.0',
'ruff==0.0.285',
'yapf==0.40.1',
'pytest-ruff==0.1.1',
'pre-commit',
'pytest-qt',
],
})

177
pyctbgui/src/decoder.c Normal file
View File

@ -0,0 +1,177 @@
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <numpy/arrayobject.h>
#include <pthread.h>
#include <stdbool.h>
#include "pm_decode.h"
#include "thread_utils.h"
/*Decode various types of CTB data using a pixel map. Works on single frames and
on stacks of frames*/
static PyObject *decode(PyObject *Py_UNUSED(self), PyObject *args,
PyObject *kwds) {
// Function arguments to be parsed
PyObject *raw_data_obj = NULL;
PyObject *data_obj = NULL;
PyObject *pm_obj = NULL;
size_t n_threads = 1;
static char *kwlist[] = {"raw_data", "pixel_map", "out", "n_threads", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|On", kwlist, &raw_data_obj,
&pm_obj, &data_obj, &n_threads)) {
return NULL;
}
// Create a handle to the numpy array from the generic python object
PyObject *raw_data = PyArray_FROM_OTF(
raw_data_obj, NPY_UINT16,
NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_ALIGNED);
if (!raw_data) {
return NULL;
}
// Handle to the pixel map
PyObject *pixel_map = PyArray_FROM_OTF(
pm_obj, NPY_UINT32, NPY_ARRAY_C_CONTIGUOUS); // Make 64bit?
if (!pixel_map) {
return NULL;
}
if (PyArray_NDIM((PyArrayObject *)pixel_map) != 2) {
PyErr_SetString(PyExc_TypeError, "The pixel map needs to be 2D");
return NULL;
}
npy_intp n_rows = PyArray_DIM((PyArrayObject *)pixel_map, 0);
npy_intp n_cols = PyArray_DIM((PyArrayObject *)pixel_map, 1);
// If called with an output array get an handle to it, otherwise allocate
// the output array
PyObject *data_out = NULL;
if (data_obj) {
data_out =
PyArray_FROM_OTF(data_obj, NPY_UINT16, NPY_ARRAY_C_CONTIGUOUS);
} else {
int ndim = PyArray_NDIM((PyArrayObject *)raw_data) + 1;
npy_intp dims_arr[3] = {PyArray_DIM((PyArrayObject *)raw_data, 0),
n_rows, n_cols};
npy_intp *dims = NULL;
if (ndim == 2)
dims = &dims_arr[1];
else
dims = &dims_arr[0];
// Allocate output array
data_out = PyArray_SimpleNew(ndim, dims, NPY_UINT16);
}
// Check that raw_data has one less dimension than frame
// eg raw_data[n_frames, pixels] frame[nframes, nrows, ncols]
// raw data is an array of values and data_out is 2/3D
int rd_dim = PyArray_NDIM((PyArrayObject *)raw_data);
int f_dim = PyArray_NDIM((PyArrayObject *)data_out);
if (rd_dim != (f_dim - 1)) {
PyErr_SetString(
PyExc_TypeError,
"Raw data and data needs to have the one less dim"); // eg -1
return NULL;
}
uint16_t *src = (uint16_t *)PyArray_DATA((PyArrayObject *)raw_data);
uint16_t *dst = (uint16_t *)PyArray_DATA((PyArrayObject *)data_out);
uint32_t *pm = (uint32_t *)PyArray_DATA((PyArrayObject *)pixel_map);
// Check sizes
npy_intp rd_size = PyArray_SIZE((PyArrayObject *)raw_data);
npy_intp fr_size = PyArray_SIZE((PyArrayObject *)data_out);
npy_intp pm_size = PyArray_SIZE((PyArrayObject *)pixel_map);
// TODO! Add exceptions
if (rd_size != fr_size) {
PyErr_SetString(PyExc_TypeError,
"Raw data size and data size needs to match");
return NULL;
}
int64_t n_frames = 1;
if (rd_dim == 2)
n_frames = PyArray_DIM((PyArrayObject *)raw_data, 0);
// printf("n_frames: %lu\n", n_frames);
// do the correct size check
if (rd_size / n_frames != pm_size) {
PyErr_SetString(PyExc_TypeError,
"Pixel map size needs to match with frame size");
return NULL;
}
if (n_threads == 1) {
pm_decode(src, dst, pm, n_frames, n_rows * n_cols);
} else {
// Multithreaded processing
pthread_t *threads = malloc(sizeof(pthread_t *) * n_threads);
thread_args *arguments = malloc(sizeof(thread_args) * n_threads);
size_t frames_per_thread = n_frames / n_threads;
size_t assigned_frames = 0;
for (size_t i = 0; i < n_threads; i++) {
arguments[i].src = src + (i * frames_per_thread * pm_size);
arguments[i].dst = dst + (i * frames_per_thread * pm_size);
arguments[i].pm = pm;
arguments[i].n_frames =
frames_per_thread; // TODO! not matching frames.
arguments[i].n_pixels = n_rows * n_cols;
assigned_frames += frames_per_thread;
}
arguments[n_threads - 1].n_frames += n_frames - assigned_frames;
for (size_t i = 0; i < n_threads; i++) {
pthread_create(&threads[i], NULL, (void *)thread_pmdecode,
&arguments[i]);
}
for (size_t i = 0; i < n_threads; i++) {
pthread_join(threads[i], NULL);
}
free(threads);
free(arguments);
}
Py_DECREF(raw_data);
Py_DECREF(pixel_map);
return data_out;
}
// Module docstring, shown as a part of help(creader)
static char module_docstring[] = "C functions decode CTB data";
// Module methods
static PyMethodDef creader_methods[] = {
{"decode", (PyCFunction)(void (*)(void))decode,
METH_VARARGS | METH_KEYWORDS, "Decode analog data using a pixel map"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
// Module defenition
static struct PyModuleDef decoder_def = {
PyModuleDef_HEAD_INIT,
"_decoder",
module_docstring,
-1,
creader_methods, // m_methods
NULL, // m_slots
NULL, // m_traverse
NULL, // m_clear
NULL // m_free
};
// Initialize module and add classes
PyMODINIT_FUNC PyInit__decoder(void) {
PyObject *m = PyModule_Create(&decoder_def);
if (m == NULL)
return NULL;
import_array(); // Needed for numpy
return m;
}

18
pyctbgui/src/pm_decode.c Normal file
View File

@ -0,0 +1,18 @@
#include "pm_decode.h"
#include "thread_utils.h"
void thread_pmdecode(void *args) {
thread_args *a;
a = (thread_args *)args;
pm_decode(a->src, a->dst, a->pm, a->n_frames, a->n_pixels);
}
void pm_decode(uint16_t *src, uint16_t *dst, uint32_t *pm, size_t n_frames,
size_t n_pixels) {
for (size_t i = 0; i < n_frames; i++) {
for (size_t j = 0; j < n_pixels; j++) {
*dst++ = src[pm[j]];
}
src += n_pixels;
}
}

8
pyctbgui/src/pm_decode.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// Wrapper to be used with pthreads
void thread_pmdecode(void *args);
void pm_decode(uint16_t *src, uint16_t *dst, uint32_t *pm, size_t n_frames,
size_t n_pixels);

View File

@ -0,0 +1,10 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef struct {
uint16_t *src;
uint16_t *dst;
uint32_t *pm;
size_t n_frames;
size_t n_pixels;
} thread_args;

View File

View File

@ -0,0 +1,11 @@
import pytest
from pyctbgui.ui import MainWindow
@pytest.fixture(scope='package')
def main():
main = MainWindow()
main.show()
yield main
main.close()

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,232 @@
patword 0x0000 0x000000006b2e8001
patword 0x0001 0x000000006b2e8001
patword 0x0002 0x000000006b2e8001
patword 0x0003 0x000000006b2e8001
patword 0x0004 0x000000006b2e8001
patword 0x0005 0x000000006b2e8001
patword 0x0006 0x000000006b2e8001
patword 0x0007 0x000000006b2e8001
patword 0x0008 0x000000006b2e8001
patword 0x0009 0x000000006b2e8001
patword 0x000a 0x000000006b2e8001
patword 0x000b 0x000000006b2e8001
patword 0x000c 0x00000000692e8001
patword 0x000d 0x00000000692e8001
patword 0x000e 0x00000000692e8001
patword 0x000f 0x00000000692e8001
patword 0x0010 0x00000000692e8001
patword 0x0011 0x00000000692e8001
patword 0x0012 0x00000000692e8001
patword 0x0013 0x00000000692e8001
patword 0x0014 0x00000000692e8001
patword 0x0015 0x00000000692e8001
patword 0x0016 0x00000000682e8001
patword 0x0017 0x00000000682e8001
patword 0x0018 0x00000000682e8001
patword 0x0019 0x00000000682e8001
patword 0x001a 0x00000000482c8001
patword 0x001b 0x00000000482c8001
patword 0x001c 0x00000000482c8001
patword 0x001d 0x00000000482c8001
patword 0x001e 0x00000000482c8001
patword 0x001f 0x00000000482c8001
patword 0x0020 0x00000000482c8001
patword 0x0021 0x00000000482c8001
patword 0x0022 0x00000000482c8001
patword 0x0023 0x00000000482c8001
patword 0x0024 0x00000000482c8001
patword 0x0025 0x00000000482c8001
patword 0x0026 0x00000000482c8001
patword 0x0027 0x00000000482c8001
patword 0x0028 0x00000000482c8001
patword 0x0029 0x00000000482c8001
patword 0x002a 0x00000000482c8001
patword 0x002b 0x00000000482c8001
patword 0x002c 0x00000000482c8001
patword 0x002d 0x00000000482c8001
patword 0x002e 0x00000000582c8001
patword 0x002f 0x00000000582c8001
patword 0x0030 0x00000000582c8001
patword 0x0031 0x00000000582c8001
patword 0x0032 0x00000000582c8001
patword 0x0033 0x00000000582c8001
patword 0x0034 0x00000000582c8001
patword 0x0035 0x00000000582c8001
patword 0x0036 0x00000000582c8001
patword 0x0037 0x00000000582c8001
patword 0x0038 0x00000000582c8001
patword 0x0039 0x00000000582c8001
patword 0x003a 0x00000000582c8001
patword 0x003b 0x00000000582c8001
patword 0x003c 0x00000000582c8001
patword 0x003d 0x00000000582c8001
patword 0x003e 0x00000000582c8001
patword 0x003f 0x00000000582c8001
patword 0x0040 0x00000000582c8001
patword 0x0041 0x00000000582c8001
patword 0x0042 0x00000000582c9011
patword 0x0043 0x00000000582c9011
patword 0x0044 0x00000000582c8001
patword 0x0045 0x00000000582c8001
patword 0x0046 0x00000000582c8001
patword 0x0047 0x00000000582c8001
patword 0x0048 0x00000000582c8001
patword 0x0049 0x00000000582c8001
patword 0x004a 0x00000000582c8001
patword 0x004b 0x00000000582c8001
patword 0x004c 0x00000000582c8001
patword 0x004d 0x00000000582c8001
patword 0x004e 0x00000000582c8001
patword 0x004f 0x00000000582c8001
patword 0x0050 0x00000000582c8001
patword 0x0051 0x00000000582c8001
patword 0x0052 0x00000000582c8001
patword 0x0053 0x00000000582c8001
patword 0x0054 0x00000000582c8001
patword 0x0055 0x00000000582c8001
patword 0x0056 0x00000000582c8001
patword 0x0057 0x00000000582c8001
patword 0x0058 0x00000000582c8001
patword 0x0059 0x00000000582c8001
patword 0x005a 0x00000000582c8041
patword 0x005b 0x00000000582c8041
patword 0x005c 0x00000000582c8141
patword 0x005d 0x00000000582c8041
patword 0x005e 0x00000000582c8041
patword 0x005f 0x00000000582c8041
patword 0x0060 0x00000000582c8041
patword 0x0061 0x00000000582c8041
patword 0x0062 0x00000000582c8041
patword 0x0063 0x00000000582c8041
patword 0x0064 0x00000000582c8041
patword 0x0065 0x00000000582c8041
patword 0x0066 0x00000000582c8041
patword 0x0067 0x00000000582c8041
patword 0x0068 0x00000000582c8041
patword 0x0069 0x00000000582c8041
patword 0x006a 0x00000000582c8041
patword 0x006b 0x00000000582c8041
patword 0x006c 0x00000000582c8041
patword 0x006d 0x00000000582c8041
patword 0x006e 0x00000000582c8041
patword 0x006f 0x00000000582c8041
patword 0x0070 0x00000000582c8041
patword 0x0071 0x00000000582c8041
patword 0x0072 0x00000000582c8041
patword 0x0073 0x00000000582c8041
patword 0x0074 0x00000000d82c8941
patword 0x0075 0x00000000d82c8041
patword 0x0076 0x00000000582c8001
patword 0x0077 0x00000000582c8001
patword 0x0078 0xc0000000582c8001
patword 0x0079 0xc0000000582c8801
patword 0x007a 0xc0000000582c8001
patword 0x007b 0xc0000000582c8801
patword 0x007c 0xc0000000582c8001
patword 0x007d 0xc0000000582c8801
patword 0x007e 0xc0000000582c8001
patword 0x007f 0xc0000000582c8801
patword 0x0080 0xc0000000582c8001
patword 0x0081 0xc0000000582c8801
patword 0x0082 0xc0000000582c8001
patword 0x0083 0xc0000000582c8801
patword 0x0084 0xc0000000582c8001
patword 0x0085 0xc0000000582c8801
patword 0x0086 0xc0000000582c8001
patword 0x0087 0xc0000000582c8801
patword 0x0088 0xc0000000582c8001
patword 0x0089 0xc0000000582c8801
patword 0x008a 0xc0000000582c8001
patword 0x008b 0xc0000000582c8801
patword 0x008c 0xc0000000582c8001
patword 0x008d 0xc0000000582c8801
patword 0x008e 0xc0000000582c8001
patword 0x008f 0xc0000000582c8801
patword 0x0090 0xc0000000582c8001
patword 0x0091 0xc0000000582c8901
patword 0x0092 0xc0000000582c8001
patword 0x0093 0xc0000000582c8801
patword 0x0094 0xc0000000582c8001
patword 0x0095 0xc0000000582c8801
patword 0x0096 0xc0000000582c8001
patword 0x0097 0xc0000000582c8801
patword 0x0098 0xc0000000582c8001
patword 0x0099 0xc0000000582c8801
patword 0x009a 0xc0000000582c8001
patword 0x009b 0xc0000000582c8801
patword 0x009c 0xc0000000582c8001
patword 0x009d 0xc0000000582c8801
patword 0x009e 0xc0000000582c8001
patword 0x009f 0xc0000000582c8801
patword 0x00a0 0xc0000000582c8001
patword 0x00a1 0xc0000000582c8801
patword 0x00a2 0xc0000000582c8001
patword 0x00a3 0xc0000000582c8801
patword 0x00a4 0xc0000000582c8001
patword 0x00a5 0xc0000000582c8801
patword 0x00a6 0xc0000000582c8001
patword 0x00a7 0xc0000000582c8801
patword 0x00a8 0xc0000000582c8001
patword 0x00a9 0xc0000000d82c8901
patword 0x00aa 0xc0000000d82c8001
patword 0x00ab 0xc0000000582c8801
patword 0x00ac 0xc0000000582c8001
patword 0x00ad 0xc0000000582c8801
patword 0x00ae 0xc0000000582c8001
patword 0x00af 0xc0000000582c8801
patword 0x00b0 0xc0000000582c8001
patword 0x00b1 0xc0000000582c8801
patword 0x00b2 0xc0000000582c8001
patword 0x00b3 0xc0000000582c8801
patword 0x00b4 0xc0000000582c8001
patword 0x00b5 0xc0000000582c8801
patword 0x00b6 0xc0000000582c8001
patword 0x00b7 0xc0000000582c8801
patword 0x00b8 0xc0000000582c8001
patword 0x00b9 0xc0000000582c8801
patword 0x00ba 0xc0000000582c8001
patword 0x00bb 0xc0000000582c8801
patword 0x00bc 0xc0000000582c8001
patword 0x00bd 0xc0000000582c8801
patword 0x00be 0xc0000000582c8001
patword 0x00bf 0xc0000000582c8801
patword 0x00c0 0xc0000000582c8001
patword 0x00c1 0xc0000000582c8801
patword 0x00c2 0xc0000000582c8001
patword 0x00c3 0xc0000000582c8901
patword 0x00c4 0xc0000000582c8001
patword 0x00c5 0xc0000000582c8801
patword 0x00c6 0xc0000000582c8001
patword 0x00c7 0xc0000000582c8801
patword 0x00c8 0xc0000000582c8001
patword 0x00c9 0xc0000000582c8801
patword 0x00ca 0xc0000000582c8001
patword 0x00cb 0xc0000000582c8801
patword 0x00cc 0xc0000000582c8001
patword 0x00cd 0xc0000000582c8801
patword 0x00ce 0xc0000000582c8001
patword 0x00cf 0xc0000000582c8801
patword 0x00d0 0xc0000000582c8001
patword 0x00d1 0xc0000000582c8801
patword 0x00d2 0xc0000000582c8001
patword 0x00d3 0xc0000000582c8801
patword 0x00d4 0xc0000000582c8001
patword 0x00d5 0xc0000000582c8801
patword 0x00d6 0xc0000000582c8001
patword 0x00d7 0xc0000000582c8801
patword 0x00d8 0xc0000000582c8001
patword 0x00d9 0xc0000000582c8801
patword 0x00da 0xc0000000582c8001
patword 0x00db 0x00000000582c8001
patword 0x00dc 0x00000000582c8001
patword 0x00dd 0x00000000482c8901
patword 0x00de 0x00000000482c8001
patword 0x00df 0x00000000482c8901
patword 0x00e0 0x00000000482c8001
patword 0x00e1 0x000000006b2e8001
patlimits 0x0000 0x00e1
patioctrl 0x01000000fb7fdd55
patloop 0 0x00a9 0x00da
patnloop 0 199
patwait 0 0x0018
patwaittime 0 800

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,9 @@
hostname localhost
rx_hostname localhost
udp_dstip auto
udp_srcip auto
romode analog
asamples 5000
tsamples 288

View File

@ -0,0 +1,57 @@
from pathlib import Path
import numpy as np
from pytestqt.qt_compat import qt_api
from .utils import setup_gui, defaultParams
def test_image_acq(main, qtbot, tmp_path):
"""
tests Analog image acquisition and numpy saving
"""
params = defaultParams()
params.detector = "Moench04"
params.mode = "Analog"
params.enabled = list(range(32))
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'moench04_image_analog.npy')
assert testArray.shape == (1, 400, 400)
assert np.array_equal(dataArray, testArray)
def test_waveform_acq(main, qtbot, tmp_path):
"""
tests Analog waveform acquisition and numpy saving
"""
params = defaultParams()
params.image = False
params.detector = "Moench04"
params.mode = "Analog"
params.enabled = list(range(32))
params.plotted = params.enabled
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'moench04_waveform_adc.npz')
files = [f"ADC{i}" for i in params.enabled]
assert testArray.files == files
for i in files:
assert np.array_equal(dataArray[i], testArray[i])

View File

@ -0,0 +1,27 @@
from pathlib import Path
from pytestqt.qt_compat import qt_api
from pyctbgui.utils.defines import Defines
from tests.gui.utils import defaultParams
def test_view_pattern(main, qtbot, tmp_path):
"""
Tests pattern file viewing
"""
params = defaultParams()
params.image = False
main.tabWidget.setCurrentIndex(Defines.pattern.tabIndex)
qtbot.keyClicks(main.patternTab.view.lineEditPatternFile, "tests/gui/data/pattern.pat")
qtbot.mouseClick(main.patternTab.view.pushButtonViewPattern, qt_api.QtCore.Qt.MouseButton.LeftButton)
qtbot.wait_until(lambda: main.patternTab.figure is not None)
assert main.patternTab.figure is not None
# save pattern
main.patternTab.figure.savefig(tmp_path / "pattern.png")
assert Path(tmp_path / "pattern.png").exists()
# pattern files generated from python3.10 libraries differ from python3.11. this would make this
# test flaky so we skip it for now
# assert filecmp.cmp("tests/gui/data/pattern.png", tmp_path / "pattern.png")

View File

@ -0,0 +1,34 @@
import numpy as np
from pytestqt.qt_compat import qt_api
from tests.gui.utils import defaultParams, setup_gui
def test_pedestal_substraction(main, qtbot, tmp_path):
"""
tests Transceiver image acquisition, numpy saving and pedestal substraction
"""
# record 10 frames
params = defaultParams()
params.pedestalRecord = True
params.nFrames = 10
params.numpy = False
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
qtbot.wait_until(lambda: main.plotTab.view.labelPedestalFrames.text() == 'recorded frames: 10')
# apply pedestal and save
params.pedestalRecord = False
params.numpy = True
params.nFrames = 2
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
assert testArray.shape == (2, 48, 48)
assert np.array_equal(testArray, np.zeros((2, 48, 48)))

View File

@ -0,0 +1,28 @@
# from pathlib import Path
#
# import numpy as np
# from pytestqt.qt_compat import qt_api
#
# from .utils import setup_gui, defaultParams
#
#
# def test_waveform_signals(main, qtbot, tmp_path):
# """
# tests signals waveform acquisition and numpy saving
# """
# params = defaultParams()
# params.image = False
# params.mode = "Signal"
# params.enabled = list(range(128))
# params.plotted = params.enabled
#
# setup_gui(qtbot, main, params, tmp_path=tmp_path)
#
# qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
#
# acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
# newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
#
# qtbot.wait_until(lambda: newPath.is_file())
# testArray = np.load(newPath)
#

View File

@ -0,0 +1,50 @@
from pathlib import Path
import numpy as np
from pytestqt.qt_compat import qt_api
from .utils import setup_gui, defaultParams
def test_image_acq(main, qtbot, tmp_path):
"""
tests Transceiver image acquisition and numpy saving
"""
setup_gui(qtbot, main, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'matterhorm_image_transceiver.npy')
assert testArray.shape == (1, 48, 48)
assert np.array_equal(dataArray, testArray)
def test_waveform_acq(main, qtbot, tmp_path):
"""
tests Transceiver waveform acquisition and numpy saving
"""
params = defaultParams()
params.image = False
params.enabled = [0, 1]
params.plotted = [0, 1]
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'matterhorn_waveform_transceiver1and2.npz')
assert testArray.files == ['Transceiver 0', 'Transceiver 1']
assert np.array_equal(dataArray['Transceiver 0'], testArray['Transceiver 0'])
assert np.array_equal(dataArray['Transceiver 1'], testArray['Transceiver 1'])

View File

@ -0,0 +1,78 @@
from pathlib import Path
from pyctbgui.utils.defines import Defines
class defaultParams:
image = True
detector = "Matterhorn"
numpy = True
mode = "Transceiver"
outputDir = "/tmp"
filename = "run"
nFrames = 1
enabled = []
plotted = []
pedestalRecord = True
pattern = False
def setup_gui(qtbot, widget, params=defaultParams(), tmp_path=Path('/tmp')):
if params.image:
widget.plotTab.view.radioButtonImage.setChecked(True)
widget.plotTab.view.radioButtonWaveform.setChecked(False)
if params.mode == "Transceiver":
params.enabled = [0, 1]
else:
params.enabled = range(128)
else:
widget.plotTab.view.radioButtonWaveform.setChecked(True)
widget.plotTab.view.radioButtonImage.setChecked(False)
if params.mode == "Transceiver":
widget.tabWidget.setCurrentIndex(Defines.transceiver.tabIndex)
for i in range(Defines.transceiver.count):
# check or uncheck enable/plot checkboxes
enable = getattr(widget.transceiverTab.view, f"checkBoxTransceiver{i}")
enable.setChecked(i in params.enabled)
enable = getattr(widget.transceiverTab.view, f"checkBoxTransceiver{i}Plot")
enable.setChecked(i in params.plotted)
elif params.mode == "Analog":
widget.tabWidget.setCurrentIndex(Defines.adc.tabIndex)
for i in range(Defines.adc.count):
# check or uncheck enable/plot checkboxes
enable = getattr(widget.adcTab.view, f"checkBoxADC{i}En")
enable.setChecked(i in params.enabled)
enable = getattr(widget.adcTab.view, f"checkBoxADC{i}Plot")
enable.setChecked(i in params.plotted)
qtbot.wait_until(lambda: widget.plotTab.view.radioButtonImage.isChecked() == params.image)
qtbot.keyClicks(widget.plotTab.view.comboBoxPlot, params.detector)
qtbot.wait_until(lambda: widget.plotTab.view.comboBoxPlot.currentText() == params.detector)
widget.acquisitionTab.view.checkBoxFileWriteNumpy.setChecked(params.numpy)
widget.acquisitionTab.view.comboBoxROMode.setCurrentIndex(-1)
qtbot.keyClicks(widget.acquisitionTab.view.comboBoxROMode, params.mode)
qtbot.wait_until(lambda: widget.acquisitionTab.view.comboBoxROMode.currentText() == params.mode)
widget.acquisitionTab.view.lineEditFilePath.setText(str(tmp_path))
widget.acquisitionTab.setFilePath()
widget.acquisitionTab.view.lineEditFileName.setText(params.filename)
widget.acquisitionTab.setFileName()
widget.acquisitionTab.view.spinBoxFrames.setValue(params.nFrames)
widget.acquisitionTab.setFrames()
widget.plotTab.view.radioButtonPedestalRecord.setChecked(params.pedestalRecord)
widget.plotTab.view.radioButtonPedestalApply.setChecked(not params.pedestalRecord)
qtbot.wait_until(lambda: widget.acquisitionTab.view.spinBoxFrames.value() == params.nFrames)
assert widget.acquisitionTab.view.comboBoxROMode.currentText() == params.mode
assert widget.plotTab.view.comboBoxPlot.currentText() == params.detector
assert widget.acquisitionTab.writeNumpy == params.numpy
assert widget.acquisitionTab.view.spinBoxFrames.value() == params.nFrames
assert widget.acquisitionTab.outputDir == Path(str(tmp_path))

View File

@ -0,0 +1,129 @@
BIT0 gHG
BIT1 DGS6 1
BIT2 pulse
BIT3 DGS7 1
BIT4 clearSSR
BIT5 DGS8 1
BIT6 inSSR
BIT7 DGS9 1
BIT8 clkSSR
BIT9 clk_fb
BIT10 prechargeConnect
BIT11 clk
BIT12 clear
BIT13 shr_out_15
BIT14 bypassCDS
BIT15 Sto2
BIT16 ENprechPre
BIT17 Sto0_bot
BIT18 pulseOFF
BIT19 Sto1
BIT20 BYPASS
BIT21 connCDS
BIT22 Dsg3
BIT23 OutSSRbot
BIT24 resCDS
BIT25 res
BIT26 shr_out_31
BIT27 Dsg1
BIT28 READ
BIT29 Sto0_top
BIT30 resDGS
BIT31 shr_in
BIT48 DGS23 1
BIT49 DGS31 1
BIT50 DGS22 1
BIT51 DGS30 1
BIT52 DGS21 1
BIT53 DGS29 1
BIT54 DGS20 1
BIT55 DGS28 1
BIT56 DGS19 1
BIT57 DGS27 1
BIT58 DGS18 1
BIT59 DGS26 1
BIT60 DGS17 1
BIT61 DGS25 1
BIT62 DGS16 1
BIT63 DGS24 1
#BIT62 dbit_ena
#BIT63 adc_ena
SENSE3 T_boa.(C)
SENSE1 Va+
SENSE6 Vdd_ps
SENSE4 Vsh
SENSE2 Vcc_int
SENSE0 Vcc_iochip
SENSE7 Vcc1.8A
SENSE5 Vcc1.8D
DAC0 VprechPre
DAC1 prechargeV
DAC2 vb_sda
DAC3 vbp_colbuf
DAC4 vcasc_SFP
DAC5 ibias_SFP
DAC6 vIpreCDS
DAC7 vin_com_bot
DAC8 vIpre
DAC9 s2dVinTest
DAC10 VPH
DAC11 vIpreDGS
DAC12 vrefDGS
DAC13 empty13
DAC14 vin_com_top
DAC15 VPL
DAC16 vout_com
DAC17 empty17
ADC0 SCOL9 1
ADC1 SCOL8 1
ADC2 SCOL11 1
ADC3 SCOL10 1
ADC4 SCOL13 1
ADC5 SCOL12 1
ADC6 SCOL15 1
ADC7 SCOL14 1
ADC8 SCOL1 1
ADC9 SCOL0 1
ADC10 SCOL3 1
ADC11 SCOL2 1
ADC12 SCOL5 1
ADC13 SCOL4 1
ADC14 SCOL7 1
ADC15 SCOL6 1
ADC16 SCOL23 1
ADC17 SCOL22 1
ADC18 SCOL21 1
ADC19 SCOL20 1
ADC20 SCOL19 1
ADC21 SCOL18 1
ADC22 SCOL17 1
ADC23 SCOL16 1
ADC24 SCOL31 1
ADC25 SCOL30 1
ADC26 SCOL29 1
ADC27 SCOL28 1
ADC28 SCOL27 1
ADC29 SCOL26 1
ADC30 SCOL25 1
ADC31 SCOL24 1
VA VddA
VB VddPre
VIO VddD
#location of the pattern compiler
#PATCOMPILER /afs/psi.ch/project/sls_det_software/slsDetectorsPackage/slsDetectorSoftware/patternGenerator/generate.sh
PATCOMPILER /afs/psi.ch/project/sls_det_software/sabina/slsDetectorPackage/ctbGui/patternGenerator/generate.sh
#location of the pattern to run
#PATFILE /afs/psi.ch/user/d/dinapoli/jctb/moench02_rob/patterns_newctb/moench02_pulsing_marco.p
#PATFILE /afs/psi.ch/project/sls_det_software/sabina/moench04/patterns/moench04_readout_g4.p
#PATFILE /afs/psi.ch/user/m/maliakal_d/setupfiles/ctb_julian.pat
#PATFILE /tmp/bla.p
#PATFILE /afs/psi.ch/project/mythen/Moench04/moench04_pulsing_readout_g4.p

View File

@ -0,0 +1,63 @@
import pytest
from pathlib import Path
from pyctbgui import alias_utility as at
def test_read_non_existing_file_throws():
with pytest.raises(FileNotFoundError):
at.read_alias_file('saijvcaiewjrvijaerijvaeoirvjveiojroiajgv')
def test_parse_sample_file():
fpath = Path(__file__).parent / 'data/moench04_start_trigger.alias'
bit_names, bit_plots, bit_colors, adc_names, adc_plots, adc_colors, dac_names, sense_names, power_names, \
pat_file_name = at.read_alias_file(fpath)
assert len(bit_names) == 64
true_names = [
'gHG', 'DGS6', 'pulse', 'DGS7', 'clearSSR', 'DGS8', 'inSSR', 'DGS9', 'clkSSR', 'clk_fb', 'prechargeConnect',
'clk', 'clear', 'shr_out_15', 'bypassCDS', 'Sto2', 'ENprechPre', 'Sto0_bot', 'pulseOFF', 'Sto1', 'BYPASS',
'connCDS', 'Dsg3', 'OutSSRbot', 'resCDS', 'res', 'shr_out_31', 'Dsg1', 'READ', 'Sto0_top', 'resDGS', 'shr_in',
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'DGS23',
'DGS31', 'DGS22', 'DGS30', 'DGS21', 'DGS29', 'DGS20', 'DGS28', 'DGS19', 'DGS27', 'DGS18', 'DGS26', 'DGS17',
'DGS25', 'DGS16', 'DGS24'
]
true_plot = [
None, True, None, True, None, True, None, True, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True, True
]
# Make sure we didn't mess up anything in this file
assert len(true_names) == len(bit_names)
for value, reference in zip(bit_names, true_names):
assert value == reference
assert len(true_plot) == 64
for value, reference in zip(bit_plots, true_plot):
assert value == reference
# sense names
true_sese = ['Vcc_iochip', 'Va+', 'Vcc_int', 'T_boa.(C)', 'Vsh', 'Vcc1.8D', 'Vdd_ps', 'Vcc1.8A']
assert len(true_sese) == 8
assert true_sese == sense_names
# ADC
true_adc = [
'SCOL9', 'SCOL8', 'SCOL11', 'SCOL10', 'SCOL13', 'SCOL12', 'SCOL15', 'SCOL14', 'SCOL1', 'SCOL0', 'SCOL3',
'SCOL2', 'SCOL5', 'SCOL4', 'SCOL7', 'SCOL6', 'SCOL23', 'SCOL22', 'SCOL21', 'SCOL20', 'SCOL19', 'SCOL18',
'SCOL17', 'SCOL16', 'SCOL31', 'SCOL30', 'SCOL29', 'SCOL28', 'SCOL27', 'SCOL26', 'SCOL25', 'SCOL24'
]
assert len(true_adc) == 32
assert true_adc == adc_names
def test_single_value_parse_gives_exception():
# Check that we get the correct exception
with pytest.raises(Exception, match=r'Alias file parsing failed'):
at.parse_alias_lines(['hej'])

View File

@ -0,0 +1,27 @@
import numpy as np
from pyctbgui import bit_utils as bt
def test_set_bit():
num = np.int32(0)
num = bt.set_bit(num, 5)
assert num == 2**5
def test_remove_bit():
num = np.int32(2**5)
num = bt.remove_bit(num, 5)
assert num == 0
def test_manipulate_bit():
num = np.int32(0)
num = bt.manipulate_bit(True, num, 5) # True means setting bit
assert num == 2**5
def test_manipulate_bit2():
num = np.int32(2**8)
num = bt.manipulate_bit(False, num, 8) # False means clearing the bit
assert num == 0

View File

@ -0,0 +1,42 @@
import numpy as np
import sys
from pyctbgui.utils import decoder
from pyctbgui.utils.pixelmap import moench04_analog, matterhorn_transceiver
def test_simple_decode():
pixel_map = np.zeros((2, 2), dtype=np.uint32)
pixel_map.flat = [0, 1, 2, 3]
raw_data = np.zeros(4, dtype=np.uint16)
raw_data.flat = [8, 9, 10, 11]
data = decoder.decode(raw_data, pixel_map)
assert data[0, 0] == 8
assert data[0, 1] == 9
assert data[1, 0] == 10
assert data[1, 1] == 11
# Make sure we didn't mess up the reference counts
assert sys.getrefcount(data) == 2
assert sys.getrefcount(raw_data) == 2
assert sys.getrefcount(pixel_map) == 2
def test_compare_python_and_c_decoding():
"""
Check that the python and C implementation give the same results
provides a regression test in case we change the C implementation
"""
pixel_map = moench04_analog()
raw_data = np.arange(400 * 400, dtype=np.uint16)
c_data = decoder.decode(raw_data, pixel_map)
py_data = decoder.moench04(raw_data)
assert (c_data == py_data).all()
pixel_map = matterhorn_transceiver()
raw_data = np.arange(48 * 48, dtype=np.uint16)
c_data = decoder.decode(raw_data, pixel_map)
py_data = decoder.matterhorn(raw_data)
assert (c_data == py_data).all()

View File

@ -0,0 +1,160 @@
import filecmp
from pathlib import Path
import pytest
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
import numpy as np
def test_create_new_file(tmp_path):
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', (400, 400), np.int32)
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.close()
arr = np.load(tmp_path / 'tmp.npy')
assert arr.dtype == np.int32
assert arr.shape == (4, 400, 400)
assert np.array_equal(arr, np.ones([4, 400, 400], dtype=np.int32))
np.save(tmp_path / 'tmp2.npy', np.ones([4, 400, 400], dtype=np.int32))
assert filecmp.cmp(tmp_path / 'tmp.npy', tmp_path / 'tmp2.npy')
def test_open_old_file(tmp_path):
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', (4000, ), np.float32)
npw.writeOneFrame(np.ones(4000, dtype=np.float32))
npw.writeOneFrame(np.ones(4000, dtype=np.float32))
npw.close()
npw2 = NumpyFileManager(tmp_path / 'tmp.npy', 'r+')
assert npw2.frameCount == 2
assert npw2.frameShape == (4000, )
assert npw2.dtype == np.float32
npw2.writeOneFrame(np.ones(4000, dtype=np.float32))
del npw2
np.save(tmp_path / 'tmp2.npy', np.ones([3, 4000], dtype=np.float32))
assert filecmp.cmp(tmp_path / 'tmp.npy', tmp_path / 'tmp2.npy')
@pytest.mark.parametrize('mode', ['w', 'x'])
def test_init_parameters2(mode, tmp_path):
# test opening files with missing parameters for write
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx', mode)
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx2', mode, frameShape=(12, 34))
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', mode, dtype=np.int64)
# opening new file with required parameters (this should work)
NumpyFileManager(tmp_path / 'abaababababa.npyx3', mode, dtype=np.int64, frameShape=(6, 6))
assert Path.is_file(tmp_path / 'abaababababa.npyx3')
def test_init_parameters(tmp_path):
with pytest.raises(TypeError):
NumpyFileManager()
# test opening file that does not exist
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx')
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx2', frameShape=(12, 34))
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int64)
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int64, frameShape=(6, 6))
# re-opening the same file
NumpyFileManager(tmp_path / 'abaababababa.npyx3', 'w', dtype=np.int64, frameShape=(6, 6))
NumpyFileManager(tmp_path / 'abaababababa.npyx3')
# re-opening the file with wrong parameters
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', frameShape=(6, 2))
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int32)
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.float32, frameShape=(5, 5))
# test resetting an existing file
npw = NumpyFileManager(tmp_path / 'tmp4.npy', 'w', dtype=np.float32, frameShape=(5, 5))
npw.writeOneFrame(np.ones((5, 5), dtype=np.float32))
npw.close()
assert np.load(tmp_path / 'tmp4.npy').shape == (1, 5, 5)
npw = NumpyFileManager(tmp_path / 'tmp4.npy', 'w', dtype=np.int64, frameShape=(7, 7))
npw.flush()
assert np.load(tmp_path / 'tmp4.npy').shape == (0, 7, 7)
# test adding frames with the wrong shape to an existing file
with pytest.raises(ValueError, match=r'frame shape given \(9, 4, 4\) '):
npw.writeOneFrame(np.ones((9, 4, 4)))
def test_get_item(tmp_path):
rng = np.random.default_rng(seed=42)
arr = rng.random((1000, 20, 20))
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', frameShape=(20, 20), dtype=arr.dtype)
for frame in arr:
npw.writeOneFrame(frame)
assert np.array_equal(npw[50:100], arr[50:100])
assert np.array_equal(npw[0:1], arr[0:1])
assert np.array_equal(npw[0:10000], arr)
assert np.array_equal(npw[999:1000], arr[999:1000])
assert np.array_equal(npw[999:1005], arr[999:1000])
assert np.array_equal(npw[49:300], arr[49:300])
assert np.array_equal(npw[88:88], arr[88:88])
assert np.array_equal(npw[0:0], arr[0:0])
assert np.array_equal(npw[0:77], arr[0:77])
assert np.array_equal(npw[77:0], arr[77:0])
with pytest.raises(NotImplementedError):
npw[-1:-3]
with pytest.raises(NotImplementedError):
npw[10:20:2]
with pytest.raises(NotImplementedError):
npw[-5:-87:5]
with pytest.raises(NotImplementedError):
npw[-5:-87:-5]
with pytest.raises(NotImplementedError):
npw.readFrames(-1, -4)
with pytest.raises(NotImplementedError):
npw.readFrames(0, -77)
with pytest.raises(NotImplementedError):
npw.readFrames(-5, -5)
def test_file_functions(tmp_path):
rng = np.random.default_rng(seed=42)
arr = rng.random((1000, 20, 20))
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', frameShape=(20, 20), dtype=arr.dtype)
for frame in arr:
npw.writeOneFrame(frame)
assert np.array_equal(npw.read(10), arr[:10])
assert np.array_equal(npw.read(10), arr[10:20])
assert np.array_equal(npw.read(10), arr[20:30])
npw.readFrames(500, 600)
assert np.array_equal(npw.read(10), arr[30:40])
npw.readFrames(0, 2)
assert np.array_equal(npw.read(100), arr[40:140])
npw.writeOneFrame(arr[700])
assert np.array_equal(npw.read(5), arr[140:145])
npw.seek(900)
assert np.array_equal(npw.read(20), arr[900:920])
npw.seek(5)
npw.readFrames(500, 600)
assert np.array_equal(npw.read(10), arr[5:15])
def test_with_statement(tmp_path):
arr = np.ones((5, 5))
with NumpyFileManager(tmp_path / 'tmp.npy', 'w', (5, 5), arr.dtype) as npw:
npw.writeOneFrame(arr)
np.save(tmp_path / 'tmp2.npy', np.expand_dims(arr, 0))
assert filecmp.cmp(tmp_path / 'tmp2.npy', tmp_path / 'tmp.npy')

View File

@ -0,0 +1,194 @@
import filecmp
from pathlib import Path
import pytest
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
import numpy as np
from pyctbgui.utils.numpyWriter.npz_writer import NpzFileWriter
@pytest.mark.parametrize('compressed', [True, False])
def test_incremental_npz(compressed, tmp_path):
arr1 = np.ones((10, 5, 5))
arr2 = np.zeros((10, 5, 5), dtype=np.int32)
arr3 = np.ones((10, 5, 5), dtype=np.float32)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed) as npz:
npz.writeArray('adc', arr1)
npz.writeArray('tx', arr2)
npz.writeArray('signal', arr3)
npzFile = np.load(tmp_path / 'tmp.npz')
assert sorted(npzFile.files) == sorted(('adc', 'tx', 'signal'))
assert np.array_equal(npzFile['adc'], np.ones((10, 5, 5)))
assert np.array_equal(npzFile['tx'], np.zeros((10, 5, 5), dtype=np.int32))
assert np.array_equal(npzFile['signal'], np.ones((10, 5, 5), dtype=np.float32))
if compressed:
np.savez_compressed(tmp_path / 'tmp2.npz', adc=arr1, tx=arr2, signal=arr3)
else:
np.savez(tmp_path / 'tmp2.npz', adc=arr1, tx=arr2, signal=arr3)
assert filecmp.cmp(tmp_path / 'tmp2.npz', tmp_path / 'tmp.npz')
@pytest.mark.parametrize('compressed', [True, False])
def test_zipping_npy_files(compressed, tmp_path):
data = {
'arr1': np.ones((10, 5, 5)),
'arr2': np.zeros((10, 5, 5), dtype=np.int32),
'arr3': np.ones((10, 5, 5), dtype=np.float32)
}
filePaths = [tmp_path / (file + '.npy') for file in data.keys()]
for file in data:
np.save(tmp_path / (file + '.npy'), data[file])
NpzFileWriter.zipNpyFiles(tmp_path / 'file.npz', filePaths, list(data.keys()), compressed=compressed)
npz = np.load(tmp_path / 'file.npz')
assert npz.files == list(data.keys())
for file in data:
assert np.array_equal(npz[file], data[file])
if compressed:
np.savez_compressed(tmp_path / 'numpy.npz', **data)
else:
np.savez(tmp_path / 'numpy.npz', **data)
numpyz = np.load(tmp_path / 'numpy.npz')
for file in data:
assert np.array_equal(numpyz[file], npz[file])
assert npz.files == numpyz.files
# different files :(
# for some reason numpy savez (most likely a trick with zipfile library) doesn't write the time
# of last modification
# assert filecmp.cmp(prefix / 'numpy.npz', prefix / 'file.npz')
@pytest.mark.parametrize('compressed', [True, False])
def test_npy_writer_with_zipfile_in_init(compressed, tmp_path):
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
rng = np.random.default_rng(42)
arr = rng.random((8000, 5, 5))
npz.writeArray('adc', arr)
with npz.file.open('adc.npy', mode='r') as outfile:
npw = NumpyFileManager(outfile)
assert np.array_equal(npw.readFrames(720, 7999), arr[720:7999])
def test_compression(tmp_path):
arr = np.zeros((1000, 5, 5), dtype=np.int32)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=True) as npz:
npz.writeArray('adc', arr)
np.savez(tmp_path / 'tmp2.npz', adc=arr)
assert Path(tmp_path / 'tmp2.npz').stat().st_size > Path(tmp_path / 'tmp.npz').stat().st_size
@pytest.mark.parametrize('compressed', [True, False])
@pytest.mark.parametrize('isPath', [True, False])
@pytest.mark.parametrize('deleteOriginals', [True, False])
def test_delete_files(compressed, isPath, deleteOriginals, tmp_path):
data = {
'arr1': np.ones((10, 5, 5)),
'arr2': np.zeros((10, 5, 5), dtype=np.int32),
'arr3': np.ones((10, 5, 5), dtype=np.float32)
}
filePaths = [tmp_path / (file + '.npy') for file in data.keys()]
for file in data:
np.save(tmp_path / (file + '.npy'), data[file])
path = tmp_path / 'file.npz'
path = str(path) if isPath else path
NpzFileWriter.zipNpyFiles(path,
filePaths,
list(data.keys()),
deleteOriginals=deleteOriginals,
compressed=compressed)
if deleteOriginals:
for file in filePaths:
assert not Path.exists(file)
else:
for file in filePaths:
assert Path.exists(file)
def test_npz_read_frames(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'r') as npz:
frames = npz.readFrames('adc', 5, 8)
assert np.array_equal(frames, arr1[5:8])
def test_file_modes(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
# check reopening with mode w
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
assert npz.file.namelist() == []
# check reopening with mode x
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with pytest.raises(FileExistsError):
with NpzFileWriter(tmp_path / 'tmp.npz', 'x'):
pass
# check reopening with mode r
with NpzFileWriter(tmp_path / 'tmp.npz', 'r') as npz:
assert np.array_equal(npz.readFrames('adc', 4, 6), arr1[4:6])
with pytest.raises(ValueError, match=r'write\(\) requires mode \'w\'\, \'x\'\, or \'a\''):
npz.writeArray('adc2', arr1)
@pytest.mark.filterwarnings('ignore::UserWarning')
def test_file_mode_a(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
# check reopening with mode a
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'a') as npz:
npz.writeArray('adc2', arr1)
npz.writeArray('adc', arr1)
@pytest.mark.parametrize('compressed', [True, False])
def test_get_item(compressed, tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
arr2 = rng.random((3, 2, 2))
# check reopening with mode a
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
npz.writeArray('adc1', arr1)
npz.writeArray('adc2', arr2)
npz.writeArray('adc3', arr1)
assert np.array_equal(npz['adc1'].read(3), arr1[:3])
assert np.array_equal(npz['adc2'].read(1), arr2[:1])
assert np.array_equal(npz['adc2'].read(1), arr2[1:2])
assert np.array_equal(npz['adc2'].read(1), arr2[2:3])
assert np.array_equal(npz['adc1'].read(3), arr1[3:6])
assert np.array_equal(npz['adc1'].read(3), arr1[6:9])
@pytest.mark.parametrize('compressed', [True, False])
def test_namelist(compressed, tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
arr2 = rng.random((3, 2, 2))
# check reopening with mode a
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
npz.writeArray('adc1', arr1)
npz.writeArray('adc2', arr2)
npz.writeArray('adc3', arr1)
assert npz.namelist() == ['adc1', 'adc2', 'adc3']

View File

@ -10,7 +10,14 @@ import sys
from setuptools import setup, find_packages
from pybind11.setup_helpers import Pybind11Extension, build_ext
__version__ = os.environ.get('GIT_DESCRIBE_TAG', 'developer')
import subprocess
def get_git_tag():
try:
return subprocess.check_output(['git', 'describe', '--tags', '--abbrev=0']).strip().decode('utf-8')
except subprocess.CalledProcessError:
return 'developer'
__version__ = get_git_tag()
def get_conda_path():

View File

@ -28,3 +28,13 @@ scanParameters = _slsdet.scanParameters
currentSrcParameters = _slsdet.currentSrcParameters
DurationWrapper = _slsdet.DurationWrapper
pedestalParameters = _slsdet.pedestalParameters
import subprocess
def get_git_tag():
try:
return subprocess.check_output(['git', 'describe', '--tags', '--abbrev=0']).strip().decode('utf-8')
except subprocess.CalledProcessError:
return 'developer'
__version__ = get_git_tag()

View File

@ -743,7 +743,7 @@ class Detector(CppDetectorApi):
@property
@element
def nextframenumber(self):
"""[Eiger][Jungfrau][Moench][CTB][Xilinx CTB] Next frame number. Stopping acquisition might result in different frame numbers for different modules. """
"""[Eiger][Jungfrau][Moench][CTB][Xilinx CTB][Gotthard2] Next frame number. Stopping acquisition might result in different frame numbers for different modules. So, after stopping, next frame number (max + 1) is set for all the modules afterwards."""
return self.getNextFrameNumber()
@nextframenumber.setter
@ -1043,7 +1043,7 @@ class Detector(CppDetectorApi):
Note
----
If path does not exist, it will try to create it.
If path does not exist and fwrite enabled, it will try to create it at start of acquisition.
Example
--------
@ -1059,7 +1059,7 @@ class Detector(CppDetectorApi):
@property
@element
def fwrite(self):
"""Enable or disable receiver file write. Default is enabled. """
"""Enable or disable receiver file write. Default is disabled. """
return self.getFileWrite()
@fwrite.setter
@ -1210,31 +1210,6 @@ class Detector(CppDetectorApi):
else:
raise ValueError("Unknown argument type")
@property
@element
def rx_zmqip(self):
"""
Zmq Ip Address from which data is to be streamed out of the receiver.
Note
-----
Also restarts receiver zmq streaming if enabled. \n
Default is from rx_hostname. \n
Modified only when using an intermediate process after receiver.
Example
-------
>>> d.rx_zmqip
192.168.0.101
>>> d.rx_zmqip = '192.168.0.101'
"""
return self.getRxZmqIP()
@rx_zmqip.setter
def rx_zmqip(self, ip):
ip = ut.make_ip(ip) #Convert from int or string to IpAddr
ut.set_using_dict(self.setRxZmqIP, ip)
@property
@element
def zmqip(self):
@ -2014,23 +1989,59 @@ class Detector(CppDetectorApi):
@property
def versions(self):
version_list = {'type': self.type,
'package': self.packageversion,
'client': self.clientversion}
type = "Unknown"
firmware = "Unknown"
detectorserver = "Unknown"
kernel = "Unknown"
hardware = "Unknown"
receiverversion = "Unknown"
eiger = False
firmware_febl = "Unknown"
firmware_febr = "Unknown"
firmware_beb = "Unknown"
receiver_in_shm = False
if self.type == detectorType.EIGER:
version_list ['firmware (Beb)'] = self.firmwareversion
version_list ['firmware(Febl)'] = self.getFrontEndFirmwareVersion(slsDetectorDefs.fpgaPosition.FRONT_LEFT)
version_list ['firmware (Febr)'] = self.getFrontEndFirmwareVersion(slsDetectorDefs.fpgaPosition.FRONT_RIGHT)
release = self.packageversion
client = self.clientversion
if self.nmod != 0:
# shared memory has detectors
type = self.type
eiger = (self.type == detectorType.EIGER)
receiver_in_shm = self.use_receiver
if receiver_in_shm:
# cannot connect to receiver
try:
receiverversion = self.rx_version
except Exception as e:
pass
# cannot connect to Detector
try:
firmware = self.firmwareversion
detectorserver = self.detectorserverversion
kernel = self.kernelversion
hardware = self.hardwareversion
if eiger:
firmware_beb = self.firmwareversion
firmware_febl = self.getFrontEndFirmwareVersion(slsDetectorDefs.fpgaPosition.FRONT_LEFT)
firmware_febr = self.getFrontEndFirmwareVersion(slsDetectorDefs.fpgaPosition.FRONT_RIGHT)
except Exception as e:
pass
version_list = {'type': {type},
'package': {release},
'client': {client}}
if eiger:
version_list ['firmware (Beb)'] = {firmware_beb}
version_list ['firmware(Febl)'] = {firmware_febl}
version_list ['firmware (Febr)'] = {firmware_febr}
else:
version_list ['firmware'] = self.firmwareversion
version_list ['detectorserver'] = self.detectorserverversion
version_list ['kernel'] = self.kernelversion
version_list ['hardware'] = self.hardwareversion
if self.use_receiver:
version_list ['receiver'] = self.rx_version
version_list ['firmware'] = {firmware}
version_list ['detectorserver'] = {detectorserver}
version_list ['kernel'] = kernel
version_list ['hardware'] = hardware
if receiver_in_shm:
version_list ['receiver'] = {receiverversion}
return version_list
@ -2100,7 +2111,7 @@ class Detector(CppDetectorApi):
Note
-----
[Jungfrau][Moench] FULL_SPEED, HALF_SPEED (Default), QUARTER_SPEED
[Jungfrau][Moench][Mythen3] FULL_SPEED, HALF_SPEED (Default), QUARTER_SPEED
[Eiger] FULL_SPEED (Default), HALF_SPEED, QUARTER_SPEED
[Moench] FULL_SPEED (Default), HALF_SPEED, QUARTER_SPEED
[Gottthard2] G2_108MHZ (Default), G2_144MHZ
@ -2899,10 +2910,36 @@ class Detector(CppDetectorApi):
def pedestalmode(self, value):
ut.set_using_dict(self.setPedestalMode, value)
@property
@element
def timing_info_decoder(self):
"""[Jungfrau] [Jungfrau] Advanced Command and only for SWISSFEL and SHINE. Sets the bunch id or timing info decoder. Default is SWISSFEL.
Enum: timingInfoDecoder
"""
return self.getTimingInfoDecoder()
@timing_info_decoder.setter
def timing_info_decoder(self, value):
ut.set_using_dict(self.setTimingInfoDecoder, value)
@property
@element
def collectionmode(self):
"""[Jungfrau] Sets collection mode to HOLE or ELECTRON. Default is HOLE.
Enum: collectionMode
"""
return self.getCollectionMode()
@collectionmode.setter
def collectionmode(self, value):
ut.set_using_dict(self.setCollectionMode, value)
@property
def maxclkphaseshift(self):
"""
[Gotthard2][Mythen3] Absolute maximum Phase shift of clocks.
[Gotthard2][Mythen3] Absolute maximum Phase shift of clocks.\n
[Gotthard2] Clock index range: 0-5\n
[Mythen3] Clock index range: 0
:setter: Not Implemented
@ -3963,7 +4000,9 @@ class Detector(CppDetectorApi):
@property
def clkphase(self):
"""
[Gotthard2][Mythen3] Phase shift of all clocks.
[Gotthard2][Mythen3] Phase shift of all clocks.\n
[Gotthard2] Clock index range: 0-5\n
[Mythen3] Clock index range: 0
Example
-------
@ -3981,7 +4020,9 @@ class Detector(CppDetectorApi):
@property
def clkdiv(self):
"""
[Gotthard2][Mythen3] Clock Divider of all clocks. Must be greater than 1.
[Gotthard2][Mythen3] Clock Divider of all clocks. Must be greater than 1.\n
[Gotthard2] Clock index range: 0-5\n
[Mythen3] Clock index range: 0
Example
-------
@ -4037,7 +4078,10 @@ class Detector(CppDetectorApi):
@property
def clkfreq(self):
"""
[Gotthard2][Mythen3] Frequency of clock in Hz.
[Gotthard2][Mythen3] Frequency of clock in Hz.\n
[Gotthard2] Clock index range: 0-5\n
[Mythen3] Clock index range: 0
:setter: Not implemented. Use clkdiv to set frequency

Some files were not shown because too many files have changed in this diff Show More