Compare commits

..

No commits in common. "9e514216aff13090a0971c3c3932dee827a372ec" and "2db8f90ae62a18102ee95e8b55a6293a12d8ccdb" have entirely different histories.

19 changed files with 102 additions and 1014 deletions

View File

@ -150,7 +150,6 @@
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp", "variant": "cpp",
"qmainwindow": "cpp", "qmainwindow": "cpp"
"qchartview": "cpp"
} }
} }

View File

@ -1,120 +0,0 @@
#include "CanvasClass.h"
#include <QValueAxis>
#include <QRandomGenerator>
#include <QGroupBox>
#include <QStandardItemModel>
#include <QLabel>
#include <QRandomGenerator>
Canvas::Canvas(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent) : QMainWindow(parent){
this->digi = digi;
this->nDigi = nDigi;
setWindowTitle("Canvas");
setGeometry(0, 0, 1000, 800);
//setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint );
QWidget * layoutWidget = new QWidget(this);
setCentralWidget(layoutWidget);
QVBoxLayout * layout = new QVBoxLayout(layoutWidget);
layoutWidget->setLayout(layout);
//========================
QGroupBox * controlBox = new QGroupBox("Control", this);
layout->addWidget(controlBox);
QGridLayout * ctrlLayout = new QGridLayout(controlBox);
controlBox->setLayout(ctrlLayout);
QPushButton * bnClearHist = new QPushButton("Clear Hist.", this);
ctrlLayout->addWidget(bnClearHist, 0, 0);
connect(bnClearHist, &QPushButton::clicked, this, [=](){
for( int i = 0; i < MaxNDigitizer; i++){
for( int j = 0; j < MaxNChannels; j++){
if( hist[i][j] ) hist[i][j]->Clear();
}
}
});
cbDigi = new RComboBox(this);
for( unsigned int i = 0; i < nDigi; i++) cbDigi->addItem("Digi-" + QString::number( digi[i]->GetSerialNumber() ), i);
ctrlLayout->addWidget(cbDigi, 1, 0);
connect( cbDigi, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
cbCh = new RComboBox(this);
for( int i = 0; i < MaxNChannels; i++) cbCh->addItem("ch-" + QString::number( i ), i);
ctrlLayout->addWidget(cbCh, 1, 1);
connect( cbCh, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
//========================
histBox = new QGroupBox("Histgrams", this);
layout->addWidget(histBox);
histLayout = new QGridLayout(histBox);
histBox->setLayout(histLayout);
double xMax = 4000;
double xMin = 0;
double nBin = 100;
for( unsigned int i = 0; i < MaxNDigitizer; i++){
for( int j = 0; j < MaxNChannels; j++){
if( i < nDigi ) {
hist[i][j] = new Histogram("Digi-" + QString::number(digi[i]->GetSerialNumber()) +", Ch-" + QString::number(j), xMin, xMax, nBin);
histView[i][j] = new TraceView(hist[i][j]->GetTrace());
histView[i][j]->SetVRange(0, 10);
}else{
hist[i][j] = nullptr;
}
}
}
histLayout->addWidget(histView[0][0], 0, 0);
oldBd = -1;
oldCh = -1;
}
Canvas::~Canvas(){
for( int i = 0; i < MaxNDigitizer; i++){
for( int j = 0; j < MaxNChannels; j++){
if( hist[i][j] ) {
delete hist[i][j];
delete histView[i][j];
}
}
}
}
void Canvas::ChangeHistView(){
if( oldCh >= 0 ) {
histLayout->removeWidget(histView[oldBd][oldCh]);
histView[oldBd][oldCh]->setParent(nullptr);
}
int bd = cbDigi->currentIndex();
int ch = cbCh->currentIndex();
histLayout->addWidget(histView[bd][ch], 0, 0);
oldBd = bd;
oldCh = ch;
}
void Canvas::UpdateCanvas(){
for( int i = 0; i < nDigi; i++){
digiMTX[i].lock();
for( int ch = 0; ch < digi[i]->GetNChannels(); ch ++ ){
int lastIndex = digi[i]->GetData()->EventIndex[ch];
int nDecoded = digi[i]->GetData()->NumEventsDecoded[ch];
for( int j = lastIndex - nDecoded + 1; j <= lastIndex; j ++){
hist[i][ch]->Fill( digi[i]->GetData()->Energy[ch][j]);
}
}
digiMTX[i].unlock();
}
}

View File

@ -1,59 +0,0 @@
#ifndef CANVAS_H
#define CANVAS_H
#include <QMainWindow>
#include <QChart>
#include <QChartView>
#include <QSpinBox>
#include <QLabel>
#include <QPushButton>
#include <QCheckBox>
#include <QLineEdit>
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLineSeries>
#include <QRubberBand>
#include <QMouseEvent>
#include <QGestureEvent>
#include "macro.h"
#include "ClassDigitizer.h"
#include "CustomThreads.h"
#include "CustomWidgets.h"
//^====================================================
//^====================================================
class Canvas : public QMainWindow{
Q_OBJECT
public:
Canvas(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr);
~Canvas();
public slots:
void UpdateCanvas();
void ChangeHistView();
private:
Digitizer ** digi;
unsigned short nDigi;
Histogram * hist[MaxNDigitizer][MaxNChannels];
TraceView * histView[MaxNDigitizer][MaxNChannels];
RComboBox * cbDivision;
RComboBox * cbDigi;
RComboBox * cbCh;
QGroupBox * histBox;
QGridLayout * histLayout;
int oldBd, oldCh;
};
#endif

View File

@ -80,7 +80,7 @@ class Data{
void CloseSaveFile(); void CloseSaveFile();
unsigned int GetFileSize() const {return outFileSize;} unsigned int GetFileSize() const {return outFileSize;}
uint64_t GetTotalFileSize() const {return FinishedOutFilesSize + outFileSize;} uint64_t GetTotalFileSize() const {return FinishedOutFilesSize + outFileSize;}
void ZeroTotalFileSize() { FinishedOutFilesSize = 0; }
protected: protected:
@ -188,7 +188,6 @@ inline void Data::ClearData(){
} }
inline void Data::ClearBuffer(){ inline void Data::ClearBuffer(){
printf("==== Data::%s \n", __func__);
delete buffer; delete buffer;
buffer = nullptr; buffer = nullptr;
AllocatedSize = 0; AllocatedSize = 0;
@ -223,11 +222,6 @@ inline bool Data::OpenSaveFile(std::string fileNamePrefix){
inline void Data::SaveData(){ inline void Data::SaveData(){
if( buffer == nullptr) {
printf("buffer is null.\n");
return;
}
if( outFileSize > (unsigned int) MaxSaveFileSize){ if( outFileSize > (unsigned int) MaxSaveFileSize){
FinishedOutFilesSize += ftell(outFile); FinishedOutFilesSize += ftell(outFile);
CloseSaveFile(); CloseSaveFile();

View File

@ -406,7 +406,6 @@ void Digitizer::StopACQ(){
AcqRun = false; AcqRun = false;
data->ClearTriggerRate(); data->ClearTriggerRate();
data->ClearBuffer(); data->ClearBuffer();
data->ZeroTotalFileSize();
} }
unsigned int Digitizer::CalByteForBuffer(){ unsigned int Digitizer::CalByteForBuffer(){
@ -662,7 +661,7 @@ void Digitizer::ProgramSettingsToBoard(){
if( DPPType == V1730_DPP_PSD_CODE ){ if( DPPType == V1730_DPP_PSD_CODE ){
for( int p = 0; p < (int) RegisterPSDList.size(); p++){ for( int p = 0; p < (int) RegisterPSDList.size(); p++){
if( RegisterPSDList[p].GetType() == RW::ReadWrite){ if( RegisterPSDList[p].GetType() == RW::ReadWrite){
haha = RegisterPSDList[p]; haha = RegisterPHAList[p];
WriteRegister(haha, GetSettingFromMemory(haha, ch), ch, false); WriteRegister(haha, GetSettingFromMemory(haha, ch), ch, false);
usleep(1 * 1000); usleep(1 * 1000);
} }
@ -731,13 +730,13 @@ int Digitizer::LoadSettingBinaryToMemory(std::string fileName){
}else{ }else{
/// load binary to memoery /// load binary to memoery
DPPType = fileDPP; DPPType = fileDPP;
printf("DPPType in the file is %s(0x%X). Board Type is %s \n", GetDPPString(fileDPP).c_str(), fileDPP, GetDPPString().c_str()); printf("DPPType in the file is %s(0x%X). \n", GetDPPString(fileDPP).c_str(), fileDPP);
settingFile = fopen(fileName.c_str(), "r"); settingFile = fopen(fileName.c_str(), "r");
size_t dummy = fread( setting, SETTINGSIZE * sizeof(unsigned int), 1, settingFile); size_t dummy = fread( setting, SETTINGSIZE * sizeof(unsigned int), 1, settingFile);
fclose (settingFile); fclose (settingFile);
if( dummy != 0 ) printf("reach the end of file (read %ld).\n", dummy); if( dummy == 0 ) printf("reach the end of file\n");
uint32_t boardInfo = GetSettingFromMemory(DPP::BoardInfo_R); uint32_t boardInfo = GetSettingFromMemory(DPP::BoardInfo_R);
if( (boardInfo & 0xFF) == 0x0E ) ch2ns = 4.0; if( (boardInfo & 0xFF) == 0x0E ) ch2ns = 4.0;

View File

@ -103,8 +103,8 @@ class Digitizer{
CAEN_DGTZ_BoardInfo_t GetBoardInfo() const {return BoardInfo;} CAEN_DGTZ_BoardInfo_t GetBoardInfo() const {return BoardInfo;}
std::string GetModelName() const {return BoardInfo.ModelName;} std::string GetModelName() const {return BoardInfo.ModelName;}
int GetSerialNumber() const {return BoardInfo.SerialNumber;} int GetSerialNumber() const {return BoardInfo.SerialNumber;}
int GetChannelMask() { channelMask = GetSettingFromMemory(DPP::ChannelEnableMask); return channelMask;} int GetChannelMask() const {return channelMask;}
bool GetChannelOnOff(unsigned ch) { channelMask = GetSettingFromMemory(DPP::ChannelEnableMask); return (channelMask & ( 1 << ch) );} bool GetChannelOnOff(unsigned ch) const {return (channelMask & ( 1 << ch) );}
float GetCh2ns() const {return ch2ns;} float GetCh2ns() const {return ch2ns;}
int GetNChannels() const {return NChannel;} int GetNChannels() const {return NChannel;}
int GetHandle() const {return handle;} int GetHandle() const {return handle;}
@ -152,10 +152,10 @@ class Digitizer{
// bool IsEnabledAutoDataFlush() {return ( GetSettingFromMemory(DPP::BoardConfiguration) & 0x1 );} // bool IsEnabledAutoDataFlush() {return ( GetSettingFromMemory(DPP::BoardConfiguration) & 0x1 );}
// bool IsDecimateTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 1) & 0x1 );} // bool IsDecimateTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 1) & 0x1 );}
// bool IsTriggerPropagate() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 2) & 0x1 );} // bool IsTriggerPropagate() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 2) & 0x1 );}
bool IsDualTrace_PHA() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 11) & 0x1 );} bool IsDualTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 11) & 0x1 );}
// unsigned short AnaProbe1Type() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 12) & 0x3 );} // unsigned short AnaProbe1Type() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 12) & 0x3 );}
// unsigned short AnaProbe2Type() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 14) & 0x3 );} // unsigned short AnaProbe2Type() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 14) & 0x3 );}
bool IsRecordTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 16) & 0x1 );} // bool IsRecordTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 16) & 0x1 );}
// bool IsEnabledExtra2() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 17) & 0x1 );} // bool IsEnabledExtra2() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 17) & 0x1 );}
// bool IsRecordTimeStamp() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 18) & 0x1 );} // bool IsRecordTimeStamp() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 18) & 0x1 );}
// bool IsRecordEnergy() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 19) & 0x1 );} // bool IsRecordEnergy() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 19) & 0x1 );}

View File

@ -18,72 +18,47 @@ public:
this->ID = digiID; this->ID = digiID;
isSaveData = false; isSaveData = false;
isScope = false; isScope = false;
readCount = 0;
stop = false;
} }
void Stop() { this->stop = true;}
void SetSaveData(bool onOff) {this->isSaveData = onOff;} void SetSaveData(bool onOff) {this->isSaveData = onOff;}
void SetScopeMode(bool onOff) {this->isScope = onOff;} void SetScopeMode(bool onOff) {this->isScope = onOff;}
void run(){ void run(){
clock_gettime(CLOCK_REALTIME, &t0); clock_gettime(CLOCK_REALTIME, &ta);
ta = t0; while(true){
// clock_gettime(CLOCK_REALTIME, &t1);
stop = false;
do{
if( stop) break;
digiMTX[ID].lock(); digiMTX[ID].lock();
int ret = digi->ReadData(); int ret = digi->ReadData();
digiMTX[ID].unlock(); digiMTX[ID].unlock();
readCount ++;
if( stop) break; if( ret == CAEN_DGTZ_Success ){
if( ret == CAEN_DGTZ_Success && !stop){
digiMTX[ID].lock(); digiMTX[ID].lock();
digi->GetData()->DecodeBuffer(!isScope, 0); digi->GetData()->DecodeBuffer(!isScope);
if( isSaveData ) digi->GetData()->SaveData(); if( isSaveData ) digi->GetData()->SaveData();
digiMTX[ID].unlock(); digiMTX[ID].unlock();
// clock_gettime(CLOCK_REALTIME, &t2);
// if( t2.tv_sec - t1.tv_sec > 2 ) {
// printf("----Digi-%d read %ld / sec.\n", ID, readCount / 3);
// readCount = 0;
// t1 = t2;
// }
}else{ }else{
printf("ReadDataThread::%s------------ ret : %d \n", __func__, ret); printf("ReadDataThread::%s------------ ret : %d \n", __func__, ret);
digiMTX[ID].lock();
digi->StopACQ(); digi->StopACQ();
digiMTX[ID].unlock();
break; break;
} }
if( isSaveData && !stop ) { if( isSaveData ) {
clock_gettime(CLOCK_REALTIME, &tb); clock_gettime(CLOCK_REALTIME, &tb);
if( tb.tv_sec - ta.tv_sec > 2 ) { if( tb.tv_sec - ta.tv_sec > 2 ) {
digiMTX[ID].lock(); emit sendMsg("FileSize ("+ QString::number(digi->GetSerialNumber()) +"): " + QString::number(digi->GetData()->GetTotalFileSize()/1024./1024.) + " MB");
emit sendMsg("FileSize ("+ QString::number(digi->GetSerialNumber()) +"): " + QString::number(digi->GetData()->GetTotalFileSize()/1024./1024., 'f', 4) + " MB [" + QString::number(tb.tv_sec-t0.tv_sec) + " sec]");
//digi->GetData()->PrintStat();
digiMTX[ID].unlock();
ta = tb; ta = tb;
} }
} }
}while(!stop); }
printf("ReadDataThread stopped.\n"); printf("ReadDataThread stopped.\n");
} }
signals: signals:
void sendMsg(const QString &msg); void sendMsg(const QString &msg);
private: private:
Digitizer * digi; Digitizer * digi;
bool stop;
int ID; int ID;
timespec ta, tb, t1, t2, t0; timespec ta, tb;
bool isSaveData; bool isSaveData;
bool isScope; bool isScope;
unsigned long readCount;
}; };
//^#======================================================= Timing Thread //^#======================================================= Timing Thread

View File

@ -13,11 +13,8 @@
#include <QRubberBand> #include <QRubberBand>
#include <QMouseEvent> #include <QMouseEvent>
#include <QGestureEvent> #include <QGestureEvent>
#include <QLineSeries>
#include <QAreaSeries>
#include <QValueAxis>
//^==================================================== //^=======================================
class RSpinBox : public QDoubleSpinBox{ class RSpinBox : public QDoubleSpinBox{
Q_OBJECT Q_OBJECT
public : public :
@ -49,7 +46,7 @@ class RSpinBox : public QDoubleSpinBox{
} }
}; };
//^==================================================== //^=======================================
class RComboBox : public QComboBox{ class RComboBox : public QComboBox{
public : public :
RComboBox(QWidget * parent = nullptr): QComboBox(parent){ RComboBox(QWidget * parent = nullptr): QComboBox(parent){
@ -93,7 +90,6 @@ private:
}; };
//^====================================================
class TraceView : public QChartView{ class TraceView : public QChartView{
public: public:
TraceView(QChart * chart, QWidget * parent = nullptr): QChartView(chart, parent){ TraceView(QChart * chart, QWidget * parent = nullptr): QChartView(chart, parent){
@ -105,21 +101,13 @@ public:
m_coordinateLabel->setVisible(false); m_coordinateLabel->setVisible(false);
m_coordinateLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_coordinateLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
setMouseTracking(true); setMouseTracking(true);
setRenderHints(QPainter::Antialiasing);
vRangeMin = -(0x1FFF);
vRangeMax = 0x1FFF;
} }
void SetHRange(int min, int max) { void SetHRange(int min, int max) {
this->hRangeMin = min; this->hRangeMin = min;
this->hRangeMax = max; this->hRangeMax = max;
}
void SetVRange(int min, int max) {
this->vRangeMin = min;
this->vRangeMax = max;
} }
protected: protected:
bool viewportEvent(QEvent *event) override{ bool viewportEvent(QEvent *event) override{
if (event->type() == QEvent::TouchBegin) { if (event->type() == QEvent::TouchBegin) {
@ -133,6 +121,7 @@ protected:
QChartView::mousePressEvent(event); QChartView::mousePressEvent(event);
} }
void mouseMoveEvent(QMouseEvent *event) override{ void mouseMoveEvent(QMouseEvent *event) override{
QPointF chartPoint = this->chart()->mapToValue(event->pos()); QPointF chartPoint = this->chart()->mapToValue(event->pos());
QString coordinateText = QString("x: %1, y: %2").arg(QString::number(chartPoint.x(), 'f', 0)).arg(QString::number(chartPoint.y(), 'f', 0)); QString coordinateText = QString("x: %1, y: %2").arg(QString::number(chartPoint.x(), 'f', 0)).arg(QString::number(chartPoint.y(), 'f', 0));
m_coordinateLabel->setText(coordinateText); m_coordinateLabel->setText(coordinateText);
@ -140,6 +129,7 @@ protected:
m_coordinateLabel->setVisible(true); m_coordinateLabel->setVisible(true);
if (m_isTouching) return; if (m_isTouching) return;
QChartView::mouseMoveEvent(event); QChartView::mouseMoveEvent(event);
} }
void mouseReleaseEvent(QMouseEvent *event) override{ void mouseReleaseEvent(QMouseEvent *event) override{
if (m_isTouching) m_isTouching = false; if (m_isTouching) m_isTouching = false;
@ -159,126 +149,20 @@ protected:
case Qt::Key_Up: chart()->scroll(0, 10); break; case Qt::Key_Up: chart()->scroll(0, 10); break;
case Qt::Key_Down: chart()->scroll(0, -10); break; case Qt::Key_Down: chart()->scroll(0, -10); break;
case Qt::Key_R : case Qt::Key_R :
//chart()->axes(Qt::Vertical).first()->setRange(-(0x1FFF), 0x1FFF); chart()->axes(Qt::Vertical).first()->setRange(-(0x1FFF), 0x1FFF);
chart()->axes(Qt::Vertical).first()->setRange(vRangeMin, vRangeMax);
//chart()->axes(Qt::Horizontal).first()->setRange(hRangeMin, hRangeMax); //chart()->axes(Qt::Horizontal).first()->setRange(hRangeMin, hRangeMax);
break; break;
default: QGraphicsView::keyPressEvent(event); break; default: QGraphicsView::keyPressEvent(event); break;
} }
} }
private: private:
bool m_isTouching; bool m_isTouching;
int hRangeMin; int hRangeMin;
int hRangeMax; int hRangeMax;
int vRangeMin;
int vRangeMax;
QLabel * m_coordinateLabel; QLabel * m_coordinateLabel;
}; };
//^====================================================
class Histogram {
public:
Histogram(QString title, double xMin, double xMax, int nBin){
plot = new Trace();
dataSeries = new QLineSeries();
Rebin(xMin, xMax, nBin);
maxBin = -1;
maxBinValue = 0;
//dataSeries->setPen(QPen(Qt::blue, 1));
areaSeries = new QAreaSeries(dataSeries);
areaSeries->setName(title);
areaSeries->setBrush(Qt::blue);
plot->addSeries(areaSeries);
plot->setAnimationDuration(1); // msec
plot->setAnimationOptions(QChart::NoAnimation);
plot->createDefaultAxes();
QValueAxis * xaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Horizontal).first());
xaxis->setRange(xMin, xMax);
xaxis->setTickCount( nBin + 1 > 11 ? 11 : nBin + 1);
//xaxis->setLabelFormat("%.1f");
//xaxis->setTitleText("Time [ns]");
QValueAxis * yaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Vertical).first());
yaxis->setRange(0, 10);
}
~Histogram(){
delete areaSeries;
delete dataSeries;
delete plot;
}
Trace * GetTrace() { return plot;}
void Clear(){
for( int i = 0; i <= nBin; i++) {
dataSeries->replace(2*i, xMin + i * dX, 0);
dataSeries->replace(2*i+1, xMin + i * dX, 0);
}
}
void SetColor(Qt::GlobalColor color){ areaSeries->setBrush(color);}
void Rebin(double xMin, double xMax, int nBin){
dataSeries->clear();
this->xMin = xMin;
this->xMax = xMax;
this->nBin = nBin;
dX = (xMax-xMin)/nBin;
for( int i = 0; i <= nBin; i++) {
dataSeries->append(xMin + i * dX, 0 );
dataSeries->append(xMin + i * dX, 0 );
}
}
void Fill(double value){
double bin = (value - xMin)/dX;
if( bin < 0 || bin >= nBin ) return;
int index1 = 2*qFloor(bin) + 1;
int index2 = index1 + 1;
QPointF point1 = dataSeries->at(index1);
dataSeries->replace(index1, point1.x(), point1.y() + 1);
QPointF point2 = dataSeries->at(index2);
dataSeries->replace(index2, point2.x(), point2.y() + 1);
if( point2.y() + 1 > maxBinValue ){
maxBinValue = point2.y() + 1;
maxBin = index2/2;
}
QValueAxis * yaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Vertical).first());
yaxis->setRange(0, maxBinValue < 10 ? 10 : ((double)maxBinValue) * 1.2 );
//yaxis->setTickInterval(1);
//yaxis->setTickCount(10);
//yaxis->setLabelFormat("%.0f");
}
private:
Trace * plot;
QLineSeries * dataSeries;
QAreaSeries * areaSeries;
double dX, xMin, xMax;
int nBin;
int maxBin;
int maxBinValue;
};
//^====================================================
#endif #endif

View File

@ -174,7 +174,6 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
leSaveFilePath[iDigi] = new QLineEdit(this); leSaveFilePath[iDigi] = new QLineEdit(this);
leSaveFilePath[iDigi]->setReadOnly(true); leSaveFilePath[iDigi]->setReadOnly(true);
buttonLayout->addWidget(leSaveFilePath[iDigi], rowID, 1, 1, 3); buttonLayout->addWidget(leSaveFilePath[iDigi], rowID, 1, 1, 3);
leSaveFilePath[iDigi]->setText(QString::fromStdString(digi[ID]->GetSettingFileName()));
rowID ++; //--------------------------- rowID ++; //---------------------------
bnRefreshSetting = new QPushButton("Refresh Settings", this); bnRefreshSetting = new QPushButton("Refresh Settings", this);
@ -194,7 +193,7 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
bnClearBuffer = new QPushButton("Clear Buffer/FIFO", this); bnClearBuffer = new QPushButton("Clear Buffer/FIFO", this);
buttonLayout->addWidget(bnClearBuffer, rowID, 2); buttonLayout->addWidget(bnClearBuffer, rowID, 2);
connect(bnClearBuffer, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareClear_W, 1); UpdateBoardAndChannelsStatus();}); connect(bnClearBuffer, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareClear_W, 1);});
bnLoadSettings = new QPushButton("Load Settings", this); bnLoadSettings = new QPushButton("Load Settings", this);
buttonLayout->addWidget(bnLoadSettings, rowID, 3); buttonLayout->addWidget(bnLoadSettings, rowID, 3);
@ -203,11 +202,11 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
rowID ++; //--------------------------- rowID ++; //---------------------------
bnSendSoftwareTriggerSignal = new QPushButton("Send SW Trigger Signal", this); bnSendSoftwareTriggerSignal = new QPushButton("Send SW Trigger Signal", this);
buttonLayout->addWidget(bnSendSoftwareTriggerSignal, rowID, 0); buttonLayout->addWidget(bnSendSoftwareTriggerSignal, rowID, 0);
connect(bnSendSoftwareTriggerSignal, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareTrigger_W, 1); UpdateBoardAndChannelsStatus();}); connect(bnSendSoftwareTriggerSignal, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareTrigger_W, 1);});
bnSendSoftwareClockSyncSignal = new QPushButton("Send SW Clock-Sync Signal", this); bnSendSoftwareClockSyncSignal = new QPushButton("Send SW Clock-Sync Signal", this);
buttonLayout->addWidget(bnSendSoftwareClockSyncSignal, rowID, 1); buttonLayout->addWidget(bnSendSoftwareClockSyncSignal, rowID, 1);
connect(bnSendSoftwareClockSyncSignal, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareClockSync_W, 1); UpdateBoardAndChannelsStatus();}); connect(bnSendSoftwareClockSyncSignal, &QPushButton::clicked, this, [=](){ digi[ID]->WriteRegister(DPP::SoftwareClockSync_W, 1);});
bnSaveSettings = new QPushButton("Save Settings (bin)", this); bnSaveSettings = new QPushButton("Save Settings (bin)", this);
buttonLayout->addWidget(bnSaveSettings, rowID, 2); buttonLayout->addWidget(bnSaveSettings, rowID, 2);
@ -396,14 +395,6 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
}); });
cbBdReg->currentIndexChanged(0); cbBdReg->currentIndexChanged(0);
connect(cbCh, &RComboBox::currentIndexChanged, this, [=](int index){
if( !enableSignalSlot ) return;
int regIndex = cbChReg->currentIndex();
uint32_t value = digi[ cbDigi->currentIndex() ] ->ReadRegister(chRegList[regIndex], cbCh->currentIndex(), index);
leChRegValue->setText( "0x" + QString::number(value, 16).toUpper());
});
connect(cbChReg, &RComboBox::currentIndexChanged, this, [=](int index){ connect(cbChReg, &RComboBox::currentIndexChanged, this, [=](int index){
if( !enableSignalSlot ) return; if( !enableSignalSlot ) return;
@ -466,8 +457,7 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
uint32_t value = std::stoul(text.toStdString(), nullptr, 16); uint32_t value = std::stoul(text.toStdString(), nullptr, 16);
int index = cbDigi->currentIndex(); int index = cbDigi->currentIndex();
int regID = cbChReg->currentIndex(); int regID = cbChReg->currentIndex();
int ch = cbCh->currentIndex(); digi[index]->WriteRegister(chRegList[regID], value);
digi[index]->WriteRegister(chRegList[regID], value, ch);
leChRegSet->setStyleSheet(""); leChRegSet->setStyleSheet("");
cbChReg->currentIndexChanged(regID); cbChReg->currentIndexChanged(regID);
@ -655,7 +645,6 @@ void DigiSettingsPanel::SetUpCheckBox(QCheckBox * &chkBox, QString label, QGridL
digi[ID]->SetBits(para, bit, state ? 1 : 0, chID); digi[ID]->SetBits(para, bit, state ? 1 : 0, chID);
if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->SetBits(para, bit, state ? 1 : 0, chID%2 == 0 ? chID + 1 : chID - 1); if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->SetBits(para, bit, state ? 1 : 0, chID%2 == 0 ? chID + 1 : chID - 1);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
}); });
} }
@ -684,7 +673,6 @@ void DigiSettingsPanel::SetUpComboBoxBit(RComboBox * &cb, QString label, QGridLa
digi[ID]->SetBits(para, bit, cb->currentData().toUInt(), chID); digi[ID]->SetBits(para, bit, cb->currentData().toUInt(), chID);
if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->SetBits(para, bit, cb->currentData().toUInt(), chID%2 == 0 ? chID + 1 : chID - 1); if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->SetBits(para, bit, cb->currentData().toUInt(), chID%2 == 0 ? chID + 1 : chID - 1);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
}); });
} }
@ -713,7 +701,6 @@ void DigiSettingsPanel::SetUpComboBox(RComboBox * &cb, QString label, QGridLayou
digi[ID]->WriteRegister(para, cb->currentData().toUInt(), chID); digi[ID]->WriteRegister(para, cb->currentData().toUInt(), chID);
if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->WriteRegister(para, cb->currentData().toUInt(), chID%2 == 0 ? chID + 1 : chID - 1); if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->WriteRegister(para, cb->currentData().toUInt(), chID%2 == 0 ? chID + 1 : chID - 1);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
}); });
} }
@ -765,21 +752,18 @@ void DigiSettingsPanel::SetUpSpinBox(RSpinBox * &sb, QString label, QGridLayout
if( para == DPP::ChannelDCOffset ){ if( para == DPP::ChannelDCOffset ){
digi[ID]->WriteRegister(para, 0xFFFF * (1.0 - sb->value() / 100. ), chID); digi[ID]->WriteRegister(para, 0xFFFF * (1.0 - sb->value() / 100. ), chID);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
return; return;
} }
if( para == DPP::PSD::CFDSetting ){ if( para == DPP::PSD::CFDSetting ){
digi[ID]->SetBits(para, DPP::PSD::Bit_CFDSetting::CFDDealy, sb->value()/digi[ID]->GetCh2ns(), chID); digi[ID]->SetBits(para, DPP::PSD::Bit_CFDSetting::CFDDealy, sb->value()/digi[ID]->GetCh2ns(), chID);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
return; return;
} }
if( para == DPP::DPPAlgorithmControl ){ if( para == DPP::DPPAlgorithmControl ){
digi[ID]->SetBits(para, {5,0}, sb->value(), chID); digi[ID]->SetBits(para, {5,0}, sb->value(), chID);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
return; return;
} }
@ -789,7 +773,6 @@ void DigiSettingsPanel::SetUpSpinBox(RSpinBox * &sb, QString label, QGridLayout
if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->WriteRegister(para, bit, chID%2 == 0 ? chID + 1 : chID - 1); if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->WriteRegister(para, bit, chID%2 == 0 ? chID + 1 : chID - 1);
UpdatePanelFromMemory(); UpdatePanelFromMemory();
emit UpdateOtherPanels();
}); });
} }
@ -1218,11 +1201,6 @@ void DigiSettingsPanel::SetUpChannelMask(){
bnChEnableMask[ID][i]->setStyleSheet(""); bnChEnableMask[ID][i]->setStyleSheet("");
digi[ID]->SetBits(DPP::ChannelEnableMask, {1, i}, 0, i); digi[ID]->SetBits(DPP::ChannelEnableMask, {1, i}, 0, i);
} }
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHASetting();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDSetting();
emit UpdateOtherPanels();
}); });
} }
@ -2114,10 +2092,10 @@ void DigiSettingsPanel::SetUpPSDChannel(){
QLabel * lb4 = new QLabel("Local Trig. Valid. [G]", this); lb4->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb4, 0, 9); QLabel * lb4 = new QLabel("Local Trig. Valid. [G]", this); lb4->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb4, 0, 9);
} }
SetUpCheckBox(chkDisableSelfTrigger[ID][ch], "Disable Self Trigger", tabLayout, ch + 1, 1, DPP::DPPAlgorithmControl, DPP::Bit_DPPAlgorithmControl_PHA::DisableSelfTrigger, ch); SetUpCheckBox(chkDisableSelfTrigger[ID][ch], "Disable Self Trigger", tabLayout, ch + 1, 1, DPP::DPPAlgorithmControl, DPP::Bit_DPPAlgorithmControl_PHA::DisableSelfTrigger, ch);
SetUpSpinBox(sbThreshold[ID][ch], "", tabLayout, ch + 1, 2, DPP::PSD::TriggerThreshold, ch); SetUpSpinBox(sbThreshold[ID][ch], "", tabLayout, ch + 1, 2, DPP::PHA::TriggerThreshold, ch);
SetUpComboBoxBit(cbTrigMode[ID][ch], "", tabLayout, ch + 1, 4, DPP::Bit_DPPAlgorithmControl_PHA::ListTrigMode, DPP::DPPAlgorithmControl, DPP::Bit_DPPAlgorithmControl_PHA::TriggerMode, 1, ch); SetUpComboBoxBit(cbTrigMode[ID][ch], "", tabLayout, ch + 1, 4, DPP::Bit_DPPAlgorithmControl_PHA::ListTrigMode, DPP::DPPAlgorithmControl, DPP::Bit_DPPAlgorithmControl_PHA::TriggerMode, 1, ch);
SetUpSpinBox(sbTriggerHoldOff[ID][ch], "", tabLayout, ch + 1, 6, DPP::PSD::TriggerHoldOffWidth, ch); SetUpSpinBox(sbTriggerHoldOff[ID][ch], "", tabLayout, ch + 1, 6, DPP::PHA::TriggerHoldOffWidth, ch);
SetUpComboBoxBit(cbLocalTriggerValid[ID][ch], "", tabLayout, ch + 1, 8, DPP::PSD::Bit_DPPAlgorithmControl2::ListLocalTrigValidMode, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalTrigValidMode, 1, ch); SetUpComboBoxBit(cbLocalTriggerValid[ID][ch], "", tabLayout, ch + 1, 8, DPP::PHA::Bit_DPPAlgorithmControl2::ListLocalTrigValidMode, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalTrigValidMode, 1, ch);
} }
if( i == 1 ){ if( i == 1 ){
@ -2127,8 +2105,9 @@ void DigiSettingsPanel::SetUpPSDChannel(){
QLabel * lb1 = new QLabel("Trig. Counter Flag [G]", this); lb1->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb1, 0, 6); QLabel * lb1 = new QLabel("Trig. Counter Flag [G]", this); lb1->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb1, 0, 6);
} }
SetUpSpinBox(sbShapedTrigWidth[ID][ch], "", tabLayout, ch + 1, 1, DPP::PSD::ShapedTriggerWidth, ch); SetUpSpinBox(sbShapedTrigWidth[ID][ch], "", tabLayout, ch + 1, 1, DPP::PSD::ShapedTriggerWidth, ch);
SetUpComboBoxBit(cbLocalShapedTrigger[ID][ch], "", tabLayout, ch + 1, 3, DPP::PSD::Bit_DPPAlgorithmControl2::ListLocalShapeTrigMode, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalShapeTriggerMode, 1, ch); SetUpComboBoxBit(cbLocalShapedTrigger[ID][ch], "", tabLayout, ch + 1, 3, DPP::PHA::Bit_DPPAlgorithmControl2::ListLocalShapeTrigMode, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalShapeTriggerMode, 1, ch);
SetUpComboBoxBit(cbTrigCount[ID][ch], "", tabLayout, ch + 1, 5, DPP::PSD::Bit_DPPAlgorithmControl2::ListTrigCounter, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::TriggerCounterFlag, 1, ch); SetUpComboBoxBit(cbTrigCount[ID][ch], "", tabLayout, ch + 1, 5, DPP::PHA::Bit_DPPAlgorithmControl2::ListTrigCounter, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::TriggerCounterFlag, 1, ch);
} }
if( i == 2 ){ if( i == 2 ){
@ -2235,7 +2214,7 @@ void DigiSettingsPanel::SetUpPSDChannel(){
QTabWidget * othersTab = new QTabWidget(this); QTabWidget * othersTab = new QTabWidget(this);
otherLayout->addWidget(othersTab); otherLayout->addWidget(othersTab);
QStringList tabName = {"Tab-1", "Test Pulse", "Veto", "Extra"}; QStringList tabName = {"Tab-1", "Test Pulse", "Veto", "Extra2"};
const int nTab = tabName.count(); const int nTab = tabName.count();
@ -2294,7 +2273,7 @@ void DigiSettingsPanel::SetUpPSDChannel(){
if( i == 3 ){ if( i == 3 ){
if( ch == 0 ){ if( ch == 0 ){
QLabel * lb2 = new QLabel("Extra Option [G]", this); lb2->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb2, 0, 2); QLabel * lb2 = new QLabel("Extra2 Option [G]", this); lb2->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb2, 0, 2);
} }
SetUpComboBoxBit(cbExtra2Option[ID][ch], "", tabLayout, ch + 1, 1, DPP::PHA::Bit_DPPAlgorithmControl2::ListExtra2, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::Extra2Option, 2, ch); SetUpComboBoxBit(cbExtra2Option[ID][ch], "", tabLayout, ch + 1, 1, DPP::PHA::Bit_DPPAlgorithmControl2::ListExtra2, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::Extra2Option, 2, ch);
} }
@ -2391,6 +2370,8 @@ void DigiSettingsPanel::UpdatePanelFromMemory(){
chkTraceRecording[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::RecordTrace) ); chkTraceRecording[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::RecordTrace) );
chkEnableExtra2[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::EnableExtra2) ); chkEnableExtra2[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::EnableExtra2) );
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) { if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) {
chkDecimateTrace[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::DecimateTrace) ); chkDecimateTrace[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::DecimateTrace) );
chkDualTrace[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::DualTrace) ); chkDualTrace[ID]->setChecked( Digitizer::ExtractBits(BdCfg, DPP::Bit_BoardConfig::DualTrace) );
@ -2572,6 +2553,8 @@ void DigiSettingsPanel::UpdatePanelFromMemory(){
} }
} }
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHASetting(); if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHASetting();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDSetting(); if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDSetting();
@ -2649,8 +2632,6 @@ void DigiSettingsPanel::SyncSpinBox(RSpinBox *(&spb)[][MaxNChannels+1]){
const int value = spb[ID][0]->value(); const int value = spb[ID][0]->value();
for( int i = 1; i < nCh; i ++){ for( int i = 1; i < nCh; i ++){
if( spb[ID][i]->value() == value ) count++; if( spb[ID][i]->value() == value ) count++;
spb[ID][i]->setEnabled(bnChEnableMask[ID][i]->styleSheet() == "" ? false : true );
} }
//printf("%d =? %d , %d, %f\n", count, nCh, value, spb[ID][0]->value()); //printf("%d =? %d , %d, %f\n", count, nCh, value, spb[ID][0]->value());
@ -2682,7 +2663,6 @@ void DigiSettingsPanel::SyncComboBox(RComboBox *(&cb)[][MaxNChannels+1]){
const QString text = cb[ID][0]->currentText(); const QString text = cb[ID][0]->currentText();
for( int i = 1; i < nCh; i ++){ for( int i = 1; i < nCh; i ++){
if( cb[ID][i]->currentText() == text ) count++; if( cb[ID][i]->currentText() == text ) count++;
cb[ID][i]->setEnabled(bnChEnableMask[ID][i]->styleSheet() == "" ? false : true );
} }
//printf("%d =? %d , %s\n", count, nCh, text.toStdString().c_str()); //printf("%d =? %d , %s\n", count, nCh, text.toStdString().c_str());
@ -2711,7 +2691,6 @@ void DigiSettingsPanel::SyncCheckBox(QCheckBox *(&chk)[][MaxNChannels+1]){
const Qt::CheckState state = chk[ID][0]->checkState(); const Qt::CheckState state = chk[ID][0]->checkState();
for( int i = 1; i < nCh; i ++){ for( int i = 1; i < nCh; i ++){
if( chk[ID][i]->checkState() == state ) count++; if( chk[ID][i]->checkState() == state ) count++;
chk[ID][i]->setEnabled(bnChEnableMask[ID][i]->styleSheet() == "" ? false : true );
} }
//printf("%d =? %d , %s\n", count, nCh, text.toStdString().c_str()); //printf("%d =? %d , %s\n", count, nCh, text.toStdString().c_str());
@ -2774,7 +2753,7 @@ void DigiSettingsPanel::UpdatePHASetting(){
enableSignalSlot = false; enableSignalSlot = false;
//printf("------ %s \n", __func__); printf("------ %s \n", __func__);
for( int ch = 0; ch < digi[ID]->GetNChannels(); ch ++){ for( int ch = 0; ch < digi[ID]->GetNChannels(); ch ++){
UpdateSpinBox(sbRecordLength[ID][ch], DPP::RecordLength_G, ch); UpdateSpinBox(sbRecordLength[ID][ch], DPP::RecordLength_G, ch);
@ -2826,9 +2805,9 @@ void DigiSettingsPanel::UpdatePHASetting(){
uint32_t vetoBit = digi[ID]->GetSettingFromMemory(DPP::VetoWidth, ch); uint32_t vetoBit = digi[ID]->GetSettingFromMemory(DPP::VetoWidth, ch);
UpdateComboBoxBit(cbVetoStep[ID][ch], vetoBit, DPP::Bit_VetoWidth::VetoStep); UpdateComboBoxBit(cbVetoStep[ID][ch], vetoBit, DPP::Bit_VetoWidth::VetoStep);
} }
enableSignalSlot = true; enableSignalSlot = true;
SyncAllChannelsTab_PHA(); SyncAllChannelsTab_PHA();
@ -2891,12 +2870,13 @@ void DigiSettingsPanel::SyncAllChannelsTab_PSD(){
SyncComboBox(cbVetoMode); SyncComboBox(cbVetoMode);
SyncComboBox(cbVetoStep); SyncComboBox(cbVetoStep);
} }
void DigiSettingsPanel::UpdatePSDSetting(){ void DigiSettingsPanel::UpdatePSDSetting(){
enableSignalSlot = false; enableSignalSlot = false;
//printf("------ %s \n", __func__); printf("------ %s \n", __func__);
for(int ch = 0; ch < digi[ID]->GetNChannels(); ch ++){ for(int ch = 0; ch < digi[ID]->GetNChannels(); ch ++){

View File

@ -21,7 +21,7 @@ public:
DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent = nullptr); DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent = nullptr);
~DigiSettingsPanel(); ~DigiSettingsPanel();
public slots: private slots:
void UpdatePanelFromMemory(); void UpdatePanelFromMemory();
void ReadSettingsFromBoard(); void ReadSettingsFromBoard();
@ -30,7 +30,6 @@ public slots:
signals: signals:
void SendLogMsg(const QString &msg); void SendLogMsg(const QString &msg);
void UpdateOtherPanels();
private: private:
@ -69,6 +68,7 @@ private:
void CheckRadioAndCheckedButtons(); void CheckRadioAndCheckedButtons();
Digitizer ** digi; Digitizer ** digi;
unsigned int nDigi; unsigned int nDigi;
unsigned short ID; unsigned short ID;

View File

@ -12,6 +12,10 @@
#include <QFileDialog> #include <QFileDialog>
#include <QScrollArea> #include <QScrollArea>
#include <TH1.h>
#include "CustomWidgets.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
setWindowTitle("FSU DAQ"); setWindowTitle("FSU DAQ");
@ -23,7 +27,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
scalar = nullptr; scalar = nullptr;
scope = nullptr; scope = nullptr;
digiSettings = nullptr; digiSettings = nullptr;
canvas = nullptr;
QWidget * mainLayoutWidget = new QWidget(this); QWidget * mainLayoutWidget = new QWidget(this);
setCentralWidget(mainLayoutWidget); setCentralWidget(mainLayoutWidget);
@ -40,92 +43,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
connect(bnOpenDigitizers, &QPushButton::clicked, this, &MainWindow::OpenDigitizers); connect(bnOpenDigitizers, &QPushButton::clicked, this, &MainWindow::OpenDigitizers);
bnCloseDigitizers = new QPushButton("Close Digitizers", this); bnCloseDigitizers = new QPushButton("Close Digitizers", this);
layout->addWidget(bnCloseDigitizers, 1, 0); layout->addWidget(bnCloseDigitizers, 0, 1);
connect(bnCloseDigitizers, &QPushButton::clicked, this, &MainWindow::CloseDigitizers); connect(bnCloseDigitizers, &QPushButton::clicked, this, &MainWindow::CloseDigitizers);
bnDigiSettings = new QPushButton("Digitizers Settings", this);
layout->addWidget(bnDigiSettings, 0, 1);
connect(bnDigiSettings, &QPushButton::clicked, this, &MainWindow::OpenDigiSettings);
bnOpenScope = new QPushButton("Open Scope", this); bnOpenScope = new QPushButton("Open Scope", this);
layout->addWidget(bnOpenScope, 1, 1); layout->addWidget(bnOpenScope, 1, 0);
connect(bnOpenScope, &QPushButton::clicked, this, &MainWindow::OpenScope); connect(bnOpenScope, &QPushButton::clicked, this, &MainWindow::OpenScope);
bnCanvas = new QPushButton("Online 1D Histograms", this); bnDigiSettings = new QPushButton("Digitizers Settings", this);
layout->addWidget(bnCanvas, 1, 2); layout->addWidget(bnDigiSettings, 1, 1);
connect(bnCanvas, &QPushButton::clicked, this, &MainWindow::OpenCanvas); connect(bnDigiSettings, &QPushButton::clicked, this, &MainWindow::OpenDigiSettings);
}
{//^====================== influx and Elog
QGroupBox * otherBox = new QGroupBox("Misc.", mainLayoutWidget);
layoutMain->addWidget(otherBox);
QGridLayout * layout = new QGridLayout(otherBox);
layout->setSpacing(2);
QLabel * lbInfluxIP = new QLabel("Influx IP : ", this);
lbInfluxIP->setAlignment(Qt::AlignRight | Qt::AlignCenter);
layout->addWidget(lbInfluxIP, 0, 0);
leInfluxIP = new QLineEdit(this);
leInfluxIP->setReadOnly(true);
layout->addWidget(leInfluxIP, 0, 1);
QLabel * lbDatabaseName = new QLabel("Database Name : ", this);
lbDatabaseName->setAlignment(Qt::AlignRight | Qt::AlignCenter);
layout->addWidget(lbDatabaseName, 0, 2);
leDatabaseName = new QLineEdit(this);
leDatabaseName->setReadOnly(true);
layout->addWidget(leDatabaseName, 0, 3);
QLabel * lbElogIP = new QLabel("Elog IP : ", this);
lbElogIP->setAlignment(Qt::AlignRight | Qt::AlignCenter);
layout->addWidget(lbElogIP, 1, 0);
leElogIP = new QLineEdit(this);
leElogIP->setReadOnly(true);
layout->addWidget(leElogIP, 1, 1);
bnLock = new QPushButton("Unlock", this);
bnLock->setChecked(true);
layout->addWidget(bnLock, 1, 3);
connect(bnLock, &QPushButton::clicked, this, [=](){
if( leInfluxIP->isReadOnly() ){
bnLock->setText("Lock and Set");
leInfluxIP->setReadOnly(false);
leDatabaseName->setReadOnly(false);
leElogIP->setReadOnly(false);
leInfluxIP->setStyleSheet("color : blue;");
leDatabaseName->setStyleSheet("color : blue;");
leElogIP->setStyleSheet("color : blue;");
}else{
bnLock->setText("Unlock");
leInfluxIP->setReadOnly(true);
leDatabaseName->setReadOnly(true);
leElogIP->setReadOnly(true);
leInfluxIP->setStyleSheet("");
leDatabaseName->setStyleSheet("");
leElogIP->setStyleSheet("");
influxIP = leInfluxIP->text();
dataBaseName = leDatabaseName->text();
elogIP = leElogIP->text();
SaveProgramSettings();
SetUpInflux();
}
});
} }
@ -161,7 +88,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
leRunID->setAlignment(Qt::AlignHCenter); leRunID->setAlignment(Qt::AlignHCenter);
chkSaveData = new QCheckBox("Save Data", this); chkSaveData = new QCheckBox("Save Data", this);
cbAutoRun = new RComboBox(this); cbAutoRun = new QComboBox(this);
cbAutoRun->addItem("Single Infinite", 0); cbAutoRun->addItem("Single Infinite", 0);
cbAutoRun->addItem("Single 30 mins", 30); cbAutoRun->addItem("Single 30 mins", 30);
cbAutoRun->addItem("Single 60 mins", 60); cbAutoRun->addItem("Single 60 mins", 60);
@ -218,7 +145,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
layoutMain->setStretchFactor(box3, 1); layoutMain->setStretchFactor(box3, 1);
QVBoxLayout * layout3 = new QVBoxLayout(box3); QVBoxLayout * layout3 = new QVBoxLayout(box3);
logInfo = new QPlainTextEdit(this); logInfo = new QPlainTextEdit(this);
logInfo->setReadOnly(true); logInfo->isReadOnly();
QFont font; QFont font;
font.setFamily("Courier New"); font.setFamily("Courier New");
logInfo->setFont(font); logInfo->setFont(font);
@ -238,8 +165,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
//=========== disable widget //=========== disable widget
WaitForDigitizersOpen(true); WaitForDigitizersOpen(true);
SetUpInflux();
} }
MainWindow::~MainWindow(){ MainWindow::~MainWindow(){
@ -251,8 +176,6 @@ MainWindow::~MainWindow(){
if( digiSettings ) delete digiSettings; if( digiSettings ) delete digiSettings;
if( canvas ) delete canvas;
if( scalar ) { if( scalar ) {
CleanUpScalar(); CleanUpScalar();
scalarThread->Stop(); scalarThread->Stop();
@ -261,8 +184,6 @@ MainWindow::~MainWindow(){
delete scalarThread; delete scalarThread;
} }
delete influx;
} }
//*************************************************************** //***************************************************************
@ -280,8 +201,6 @@ void MainWindow::OpenDataPath(){
leDataPath->clear(); leDataPath->clear();
} }
SaveProgramSettings();
} }
void MainWindow::LoadProgramSettings(){ void MainWindow::LoadProgramSettings(){
@ -301,19 +220,12 @@ void MainWindow::LoadProgramSettings(){
if( line.left(6) == "//----") break; if( line.left(6) == "//----") break;
if( count == 0 ) rawDataPath = line; if( count == 0 ) rawDataPath = line;
if( count == 1 ) influxIP = line;
if( count == 2 ) dataBaseName = line;
if( count == 3 ) elogIP = line;
count ++; count ++;
line = in.readLine(); line = in.readLine();
} }
//looking for the lastRun.sh for //looking for the lastRun.sh for
leDataPath->setText(rawDataPath); leDataPath->setText(rawDataPath);
leInfluxIP->setText(influxIP);
leDatabaseName->setText(dataBaseName);
leElogIP->setText(elogIP);
//check is rawDataPath exist, if not, create one //check is rawDataPath exist, if not, create one
QDir rawDataDir; QDir rawDataDir;
@ -340,10 +252,7 @@ void MainWindow::SaveProgramSettings(){
file.open(QIODevice::Text | QIODevice::WriteOnly); file.open(QIODevice::Text | QIODevice::WriteOnly);
file.write((rawDataPath+"\n").toStdString().c_str()); file.write((rawDataPath+"\n").toStdString().c_str());
file.write((influxIP+"\n").toStdString().c_str()); file.write("//------------end of file.");
file.write((dataBaseName+"\n").toStdString().c_str());
file.write((elogIP+"\n").toStdString().c_str());
file.write("//------------end of file.\n");
file.close(); file.close();
LogMsg("Saved program settings to <b>"+ programSettingsFilePath + "<b>."); LogMsg("Saved program settings to <b>"+ programSettingsFilePath + "<b>.");
@ -481,14 +390,6 @@ void MainWindow::OpenDigitizers(){
QCoreApplication::processEvents(); //to prevent Qt said application not responding. QCoreApplication::processEvents(); //to prevent Qt said application not responding.
} }
canvas = new Canvas(digi, nDigi);
histThread = new TimingThread(this);
histThread->SetWaitTimeinSec(0.5);
connect(histThread, &TimingThread::timeUp, this, [=](){
if( canvas == nullptr ) return;
canvas->UpdateCanvas();
});
LogMsg(QString("Done. Opened %1 digitizer(s).").arg(nDigi)); LogMsg(QString("Done. Opened %1 digitizer(s).").arg(nDigi));
WaitForDigitizersOpen(false); WaitForDigitizersOpen(false);
@ -521,13 +422,6 @@ void MainWindow::CloseDigitizers(){
for(unsigned int i = 0; i < nDigi; i ++){ for(unsigned int i = 0; i < nDigi; i ++){
digi[i]->CloseDigitizer(); digi[i]->CloseDigitizer();
delete digi[i]; delete digi[i];
if(readDataThread[i]->isRunning()){
readDataThread[i]->Stop();
readDataThread[i]->quit();
readDataThread[i]->wait();
}
delete readDataThread[i]; delete readDataThread[i];
} }
delete [] digi; delete [] digi;
@ -553,7 +447,6 @@ void MainWindow::WaitForDigitizersOpen(bool onOff){
bnStartACQ->setEnabled(!onOff); bnStartACQ->setEnabled(!onOff);
bnStopACQ->setEnabled(!onOff); bnStopACQ->setEnabled(!onOff);
chkSaveData->setEnabled(!onOff); chkSaveData->setEnabled(!onOff);
bnCanvas->setEnabled(!onOff);
} }
@ -585,7 +478,7 @@ void MainWindow::SetupScalar(){
scalarThread = new TimingThread(); scalarThread = new TimingThread();
connect(scalarThread, &TimingThread::timeUp, this, &MainWindow::UpdateScalar); connect(scalarThread, &TimingThread::timeUp, this, &MainWindow::UpdateScalar);
scalar->setGeometry(0, 0, 10 + nDigi * 200, 110 + MaxNChannels * 20); scalar->setGeometry(0, 0, 10 + nDigi * 200, 110 + MaxNChannels * 25);
if( lbLastUpdateTime == nullptr ){ if( lbLastUpdateTime == nullptr ){
lbLastUpdateTime = new QLabel("Last update : NA", scalar); lbLastUpdateTime = new QLabel("Last update : NA", scalar);
@ -622,7 +515,6 @@ void MainWindow::SetupScalar(){
rowID = 2; rowID = 2;
leTrigger[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()]; leTrigger[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()];
leAccept[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()]; leAccept[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()];
uint32_t chMask = digi[iDigi]->GetChannelMask();
for( int ch = 0; ch < MaxNChannels; ch++){ for( int ch = 0; ch < MaxNChannels; ch++){
if( ch == 0 ){ if( ch == 0 ){
@ -641,6 +533,7 @@ void MainWindow::SetupScalar(){
} }
rowID ++; rowID ++;
leTrigger[iDigi][ch] = new QLineEdit(scalar); leTrigger[iDigi][ch] = new QLineEdit(scalar);
leTrigger[iDigi][ch]->setReadOnly(true); leTrigger[iDigi][ch]->setReadOnly(true);
leTrigger[iDigi][ch]->setAlignment(Qt::AlignRight); leTrigger[iDigi][ch]->setAlignment(Qt::AlignRight);
@ -650,10 +543,6 @@ void MainWindow::SetupScalar(){
leAccept[iDigi][ch]->setReadOnly(true); leAccept[iDigi][ch]->setReadOnly(true);
leAccept[iDigi][ch]->setAlignment(Qt::AlignRight); leAccept[iDigi][ch]->setAlignment(Qt::AlignRight);
leAccept[iDigi][ch]->setStyleSheet("background-color: #F0F0F0;"); leAccept[iDigi][ch]->setStyleSheet("background-color: #F0F0F0;");
leTrigger[iDigi][ch]->setEnabled( (chMask >> ch) & 0x1 );
leAccept[iDigi][ch]->setEnabled( (chMask >> ch) & 0x1 );
scalarLayout->addWidget(leAccept[iDigi][ch], rowID, 2*iDigi+2); scalarLayout->addWidget(leAccept[iDigi][ch], rowID, 2*iDigi+2);
} }
} }
@ -695,31 +584,17 @@ void MainWindow::OpenScalar(){
void MainWindow::UpdateScalar(){ void MainWindow::UpdateScalar(){
if( digi == nullptr ) return; if( digi == nullptr ) return;
if( scalar == nullptr ) return; if( scalar == nullptr ) return;
//if( !scalar->isVisible() ) return; if( !scalar->isVisible() ) return;
lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss")); lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss"));
//printf("----------------------\n");
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){ for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){
digiMTX[iDigi].lock(); Data * data = digi[iDigi]->GetData();
for( int i = 0; i < digi[iDigi]->GetNChannels(); i++){ for( int i = 0; i < digi[iDigi]->GetNChannels(); i++){
if( digi[iDigi]->GetChannelOnOff(i) == true ) { leTrigger[iDigi][i]->setText(QString::number(data->TriggerRate[i]));
//printf(" %3d %2d | %7.2f %7.2f \n", digi[iDigi]->GetSerialNumber(), i, digi[iDigi]->GetData()->TriggerRate[i], digi[iDigi]->GetData()->NonPileUpRate[i]); leAccept[iDigi][i]->setText(QString::number(data->NonPileUpRate[i]));
leTrigger[iDigi][i]->setText(QString::number(digi[iDigi]->GetData()->TriggerRate[i], 'f', 2));
leAccept[iDigi][i]->setText(QString::number(digi[iDigi]->GetData()->NonPileUpRate[i], 'f', 2));
if( influx ){
influx->AddDataPoint("Rate,Bd="+std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(i).rightJustified(2, '0').toStdString() + " value=" + QString::number(digi[iDigi]->GetData()->TriggerRate[i], 'f', 2).toStdString());
}
}
} }
digiMTX[iDigi].unlock();
}
if( influx ){
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
} }
} }
@ -734,11 +609,7 @@ void MainWindow::StartACQ(){
if( chkSaveData->isChecked() ) commentResult = CommentDialog(true); if( chkSaveData->isChecked() ) commentResult = CommentDialog(true);
if( commentResult == false) return; if( commentResult == false) return;
if( chkSaveData->isChecked() ) { LogMsg("===================== Start a new Run-" + QString::number(runID));
LogMsg("<font style=\"color: orange;\">===================== <b>Start a new Run-" + QString::number(runID) + "</b></font>");
}else{
LogMsg("<font style=\"color: orange;\">===================== <b>Start a non-save Run</b></font>");
}
for( unsigned int i = 0; i < nDigi ; i++){ for( unsigned int i = 0; i < nDigi ; i++){
if( chkSaveData->isChecked() ) { if( chkSaveData->isChecked() ) {
@ -749,13 +620,10 @@ void MainWindow::StartACQ(){
} }
readDataThread[i]->SetSaveData(chkSaveData->isChecked()); readDataThread[i]->SetSaveData(chkSaveData->isChecked());
LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is starting ACQ." ); LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is starting ACQ." );
digi[i]->WriteRegister(DPP::SoftwareClear_W, 1);
digi[i]->GetData()->SetSaveWaveToMemory(false);
digi[i]->StartACQ(); digi[i]->StartACQ();
readDataThread[i]->start(); readDataThread[i]->start();
} }
if( chkSaveData->isChecked() ) SaveLastRunFile(); if( chkSaveData->isChecked() ) SaveLastRunFile();
scalarThread->start(); scalarThread->start();
if( !scalar->isVisible() ) { if( !scalar->isVisible() ) {
@ -765,8 +633,6 @@ void MainWindow::StartACQ(){
} }
lbScalarACQStatus->setText("<font style=\"color: green;\"><b>ACQ On</b></font>"); lbScalarACQStatus->setText("<font style=\"color: green;\"><b>ACQ On</b></font>");
if( canvas != nullptr ) histThread->start();
bnStartACQ->setEnabled(false); bnStartACQ->setEnabled(false);
bnStopACQ->setEnabled(true); bnStopACQ->setEnabled(true);
bnOpenScope->setEnabled(false); bnOpenScope->setEnabled(false);
@ -775,28 +641,21 @@ void MainWindow::StartACQ(){
void MainWindow::StopACQ(){ void MainWindow::StopACQ(){
if( digi == nullptr ) return; if( digi == nullptr ) return;
LogMsg("===================== Stop Run-" + QString::number(runID));
bool commentResult = true; bool commentResult = true;
if( chkSaveData->isChecked() ) commentResult = CommentDialog(true); if( chkSaveData->isChecked() ) commentResult = CommentDialog(true);
if( commentResult == false) return; if( commentResult == false) return;
if( chkSaveData->isChecked() ) {
LogMsg("===================== Stop Run-" + QString::number(runID));
}else{
LogMsg("===================== Stop a non-save Run");
}
for( unsigned int i = 0; i < nDigi; i++){ for( unsigned int i = 0; i < nDigi; i++){
LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is stoping ACQ." ); LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is stoping ACQ." );
digi[i]->StopACQ();
if( chkSaveData->isChecked() ) digi[i]->GetData()->CloseSaveFile();
if( readDataThread[i]->isRunning() ) { if( readDataThread[i]->isRunning() ) {
readDataThread[i]->Stop();
readDataThread[i]->quit(); readDataThread[i]->quit();
readDataThread[i]->wait(); readDataThread[i]->wait();
} }
digiMTX[i].lock();
digi[i]->StopACQ();
digiMTX[i].unlock();
if( chkSaveData->isChecked() ) digi[i]->GetData()->CloseSaveFile();
} }
if( scalarThread->isRunning()){ if( scalarThread->isRunning()){
@ -804,12 +663,6 @@ void MainWindow::StopACQ(){
scalarThread->quit(); scalarThread->quit();
scalarThread->wait(); scalarThread->wait();
} }
if( histThread->isRunning()){
histThread->Stop();
histThread->quit();
histThread->wait();
}
lbScalarACQStatus->setText("<font style=\"color: red;\"><b>ACQ Off</b></font>"); lbScalarACQStatus->setText("<font style=\"color: red;\"><b>ACQ Off</b></font>");
@ -818,7 +671,7 @@ void MainWindow::StopACQ(){
bnOpenScope->setEnabled(true); bnOpenScope->setEnabled(true);
} }
void MainWindow::AutoRun(){ //TODO void MainWindow::AutoRun(){
} }
@ -930,31 +783,15 @@ void MainWindow::OpenScope(){
bnStopACQ->setEnabled(false); bnStopACQ->setEnabled(false);
}); });
connect(scope, &Scope::TellACQOnOff, this, [=](bool onOff){ connect(scope, &Scope::TellACQOnOff, this, [=](bool onOff){
if( scope ) { if( scope == nullptr ) return;
if( onOff ) { if( onOff ) {
lbScalarACQStatus->setText("<font style=\"color: green;\"><b>ACQ On</b></font>"); lbScalarACQStatus->setText("<font style=\"color: green;\"><b>ACQ On</b></font>");
}else{ }else{
lbScalarACQStatus->setText("<font style=\"color: red;\"><b>ACQ Off</b></font>"); lbScalarACQStatus->setText("<font style=\"color: red;\"><b>ACQ Off</b></font>");
}
}
if( canvas ){
if( onOff ) {
histThread->start();
}else{
if( histThread->isRunning()){
histThread->Stop();
histThread->quit();
histThread->wait();
}
}
} }
}); });
connect(scope, &Scope::UpdateScaler, this, &MainWindow::UpdateScalar); connect(scope, &Scope::UpdateScaler, this, &MainWindow::UpdateScalar);
connect(scope, &Scope::UpdateOtherPanels, this, [=](){ UpdateAllPanels(1); });
scope->show(); scope->show();
}else{ }else{
scope->show(); scope->show();
@ -964,8 +801,6 @@ void MainWindow::OpenScope(){
bnStartACQ->setEnabled(false); bnStartACQ->setEnabled(false);
bnStopACQ->setEnabled(false); bnStopACQ->setEnabled(false);
chkSaveData->setChecked(false);
} }
//*************************************************************** //***************************************************************
@ -975,8 +810,6 @@ void MainWindow::OpenDigiSettings(){
if( digiSettings == nullptr ) { if( digiSettings == nullptr ) {
digiSettings = new DigiSettingsPanel(digi, nDigi, rawDataPath); digiSettings = new DigiSettingsPanel(digi, nDigi, rawDataPath);
//connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg); //connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg);
connect(digiSettings, &DigiSettingsPanel::UpdateOtherPanels, this, [=](){ UpdateAllPanels(2); });
digiSettings->show(); digiSettings->show();
}else{ }else{
digiSettings->show(); digiSettings->show();
@ -985,94 +818,6 @@ void MainWindow::OpenDigiSettings(){
} }
//***************************************************************
//***************************************************************
void MainWindow::OpenCanvas(){
if( canvas == nullptr ) {
canvas = new Canvas(digi, nDigi);
canvas->show();
}else{
canvas->show();
canvas->activateWindow();
}
}
//***************************************************************
//***************************************************************
void MainWindow::UpdateAllPanels(int panelID){
//panelID is the source panel that call
// scope = 1;
// digiSetting = 2;
if( panelID == 1 ){ // from scope
if( digiSettings && digiSettings->isVisible() ) digiSettings->UpdatePanelFromMemory();
}
if( panelID == 2 ){
if(scope && scope->isVisible() ) scope->UpdatePanelFromMomeory();
if(scalar) {
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){
uint32_t chMask = digi[iDigi]->GetChannelMask();
for( int i = 0; i < digi[iDigi]->GetNChannels(); i++){
leTrigger[iDigi][i]->setEnabled( (chMask >> i) & 0x1 );
leAccept[iDigi][i]->setEnabled( (chMask >> i) & 0x1 );
}
}
}
}
}
//***************************************************************
//***************************************************************
void MainWindow::SetUpInflux(){
if( influxIP == "" ) return;
if( influx ) {
delete influx;
influx = nullptr;
}
influx = new InfluxDB(influxIP.toStdString(), false);
if( influx->TestingConnection() ){
LogMsg("<font style=\"color : green;\"> InfluxDB URL (<b>"+ influxIP + "</b>) is Valid </font>");
//==== chck database exist
//LogMsg("List of database:");
std::vector<std::string> databaseList = influx->GetDatabaseList();
bool foundDatabase = false;
for( int i = 0; i < (int) databaseList.size(); i++){
if( databaseList[i] == dataBaseName.toStdString() ) foundDatabase = true;
//LogMsg(QString::number(i) + "|" + QString::fromStdString(databaseList[i]));
}
if( foundDatabase ){
LogMsg("<font style=\"color : green;\"> Database <b>" + dataBaseName + "</b> found.");
influx->AddDataPoint("ProgramStart value=1");
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
if( influx->IsWriteOK() ){
LogMsg("<font style=\"color : green;\">test write database OK.</font>");
}else{
LogMsg("<font style=\"color : red;\">test write database FAIL.</font>");
}
}else{
LogMsg("<font style=\"color : red;\"> Database <b>" + dataBaseName + "</b> NOT found.");
delete influx;
influx = nullptr;
}
}else{
LogMsg("<font style=\"color : red;\"> InfluxDB URL (<b>"+ influxIP + "</b>) is NOT Valid </font>");
delete influx;
influx = nullptr;
}
}
//*************************************************************** //***************************************************************
//*************************************************************** //***************************************************************
void MainWindow::LogMsg(QString msg){ void MainWindow::LogMsg(QString msg){
@ -1084,6 +829,6 @@ void MainWindow::LogMsg(QString msg){
} }
QScrollBar *v = logInfo->verticalScrollBar(); QScrollBar *v = logInfo->verticalScrollBar();
v->setValue(v->maximum()); v->setValue(v->maximum());
qDebug() << outputStr; //qDebug() << msg;
logInfo->repaint(); logInfo->repaint();
} }

View File

@ -13,11 +13,8 @@
#include "ClassDigitizer.h" #include "ClassDigitizer.h"
#include "CustomThreads.h" #include "CustomThreads.h"
#include "CustomWidgets.h"
#include "Scope.h" #include "Scope.h"
#include "DigiSettingsPanel.h" #include "DigiSettingsPanel.h"
#include "CanvasClass.h"
#include "influxdb.h"
//^#===================================================== MainWindow //^#===================================================== MainWindow
class MainWindow : public QMainWindow{ class MainWindow : public QMainWindow{
@ -29,7 +26,6 @@ public:
void closeEvent(QCloseEvent * event){ void closeEvent(QCloseEvent * event){
if( scope ) scope->close(); if( scope ) scope->close();
if( digiSettings ) digiSettings->close(); if( digiSettings ) digiSettings->close();
if( canvas ) canvas->close();
event->accept(); event->accept();
} }
@ -60,12 +56,6 @@ private slots:
void OpenDigiSettings(); void OpenDigiSettings();
void OpenCanvas();
void UpdateAllPanels(int panelID);
void SetUpInflux();
private: private:
Digitizer ** digi; Digitizer ** digi;
@ -76,9 +66,6 @@ private:
QString prefix; QString prefix;
unsigned int runID; unsigned int runID;
unsigned int elogID; unsigned int elogID;
QString influxIP;
QString dataBaseName;
QString elogIP;
QPushButton * bnOpenDigitizers; QPushButton * bnOpenDigitizers;
QPushButton * bnCloseDigitizers; QPushButton * bnCloseDigitizers;
@ -89,18 +76,6 @@ private:
QPushButton * bnStartACQ; QPushButton * bnStartACQ;
QPushButton * bnStopACQ; QPushButton * bnStopACQ;
QPushButton * bnCanvas;
//@----- influx
InfluxDB * influx;
QLineEdit * leInfluxIP;
QLineEdit * leDatabaseName;
QPushButton * bnLock;
//@----- Elog
QLineEdit * leElogIP;
//@----- log msg //@----- log msg
QPlainTextEdit * logInfo; QPlainTextEdit * logInfo;
void LogMsg(QString msg); void LogMsg(QString msg);
@ -113,7 +88,7 @@ private:
QLineEdit * leRunID; QLineEdit * leRunID;
QCheckBox * chkSaveData; QCheckBox * chkSaveData;
RComboBox * cbAutoRun; QComboBox * cbAutoRun;
QString startComment; QString startComment;
QString stopComment; QString stopComment;
@ -136,10 +111,6 @@ private:
//@----- DigiSettings //@----- DigiSettings
DigiSettingsPanel * digiSettings; DigiSettingsPanel * digiSettings;
//@----- Canvas
Canvas * canvas;
TimingThread * histThread;
}; };

View File

@ -8,11 +8,8 @@ INCLUDEPATH += .
QT += core widgets charts QT += core widgets charts
#QMAKE_CXXFLAGS += `root-config --cflags --glibs` QMAKE_CXXFLAGS += `root-config --cflags --glibs`
#LIBS += -lCAENDigitizer `root-config --cflags --glibs` LIBS += -lCAENDigitizer `root-config --cflags --glibs`
#QMAKE_CXXFLAGS += -g
LIBS += -lCAENDigitizer -lcurl
# You can make your code fail to compile if you use deprecated APIs. # You can make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line. # In order to do so, uncomment the following line.
@ -30,13 +27,9 @@ HEADERS += ClassData.h \
FSUDAQ.h \ FSUDAQ.h \
macro.h \ macro.h \
RegisterAddress.h \ RegisterAddress.h \
influxdb.h\ Scope.h
Scope.h \
CanvasClass.h
SOURCES += ClassDigitizer.cpp \ SOURCES += ClassDigitizer.cpp \
DigiSettingsPanel.cpp \ DigiSettingsPanel.cpp \
FSUDAQ.cpp \ FSUDAQ.cpp \
main.cpp \ main.cpp \
influxdb.cpp\ Scope.cpp
Scope.cpp \
CanvasClass.cpp

View File

@ -5,8 +5,7 @@
CC = g++ CC = g++
#COPTS = -fPIC -DLINUX -O2 -std=c++17 -lpthread COPTS = -fPIC -DLINUX -O2 -std=c++17 -lpthread
COPTS = -fPIC -DLINUX -g -std=c++17 -lpthread
CAENLIBS = -lCAENDigitizer CAENLIBS = -lCAENDigitizer

View File

@ -1,31 +0,0 @@
# Introduction
This is a DAQ for 1st gen CAEN digitizer for V1725, V17255S, V1230 with PHA and PSD firmware.
It has scope (updated every half-sec), allow full control of the digitizer (except LVDS), and allow saving waevform.
# Required / Development enviroment
Ubuntu 22.04
CAENVMELib_v3.3
CAENCOmm_v1.5.3
CAENDigitizer_v2.17.1
`sudo apt install qt6-base-dev libcurl4-openssl-dev libqt6charts6-dev`
# Compile
use `qmake6 -project ` to generate the *.pro
in the *.pro, add
` QT += core widgets charts`
` LIBS += -lCAENDigitizer -lcurl`
then run ` qmake6 *.pro` it will generate Makefile
then ` make`

View File

@ -116,20 +116,16 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) SetUpPHAPanel(); if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) SetUpPHAPanel();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) SetUpPSDPanel(); if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) SetUpPSDPanel();
ReadSettingsFromBoard(); //ReadSettingsFromBoard();
}); });
connect(cbScopeCh, &RComboBox::currentIndexChanged, this, [=](){
if( !enableSignalSlot ) return;
ReadSettingsFromBoard();
});
bnReadSettingsFromBoard = new QPushButton("Refresh Settings", this); bnReadSettingsFromBoard = new QPushButton("Refresh Settings", this);
layout->addWidget(bnReadSettingsFromBoard, rowID, 2); layout->addWidget(bnReadSettingsFromBoard, rowID, 2);
connect(bnReadSettingsFromBoard, &QPushButton::clicked, this, &Scope::ReadSettingsFromBoard); connect(bnReadSettingsFromBoard, &QPushButton::clicked, this, &Scope::ReadSettingsFromBoard);
QPushButton * bnClearMemory = new QPushButton("Clear Memory", this); QPushButton * bnClearMemory = new QPushButton("Clear Memory", this);
layout->addWidget(bnClearMemory, rowID, 3); layout->addWidget(bnClearMemory, rowID, 3);
connect(bnClearMemory, &QPushButton::clicked, this, [=](){ connect(bnClearMemory, &QPushButton::clicked, this, [=](){
@ -154,6 +150,7 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
//================ Plot view //================ Plot view
rowID ++; rowID ++;
plotView = new TraceView(plot, this); plotView = new TraceView(plot, this);
plotView->setRenderHints(QPainter::Antialiasing);
layout->addWidget(plotView, rowID, 0, 1, 6); layout->addWidget(plotView, rowID, 0, 1, 6);
@ -230,24 +227,16 @@ void Scope::StartScope(){
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi ++){ for( unsigned int iDigi = 0; iDigi < nDigi; iDigi ++){
traceOn[iDigi] = digi[iDigi]->IsRecordTrace(); //remember setting
digi[iDigi]->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, 1, -1);
digi[iDigi]->GetData()->SetSaveWaveToMemory(true); digi[iDigi]->GetData()->SetSaveWaveToMemory(true);
digi[iDigi]->StartACQ(); digi[iDigi]->StartACQ();
printf("----- readDataThread running ? %d.\n", readDataThread[iDigi]->isRunning());
if( readDataThread[iDigi]->isRunning() ){
readDataThread[iDigi]->quit();
readDataThread[iDigi]->wait();
}
readDataThread[iDigi]->SetScopeMode(true); readDataThread[iDigi]->SetScopeMode(true);
readDataThread[iDigi]->SetSaveData(false); readDataThread[iDigi]->SetSaveData(false);
readDataThread[iDigi]->start();
}
emit UpdateOtherPanels(); readDataThread[iDigi]->start();
}
updateTraceThread->start(); updateTraceThread->start();
@ -263,27 +252,20 @@ void Scope::StartScope(){
void Scope::StopScope(){ void Scope::StopScope(){
if( !digi ) return; if( !digi ) return;
// printf("------ Scope::%s \n", __func__);
updateTraceThread->Stop(); updateTraceThread->Stop();
updateTraceThread->quit(); updateTraceThread->quit();
updateTraceThread->exit(); updateTraceThread->exit();
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi ++){
if( readDataThread[iDigi]->isRunning() ){ for( unsigned int iDigi = 0; iDigi < nDigi; iDigi ++){
readDataThread[iDigi]->Stop();
readDataThread[iDigi]->quit();
readDataThread[iDigi]->wait();
}
digiMTX[iDigi].lock(); digiMTX[iDigi].lock();
digi[iDigi]->StopACQ(); digi[iDigi]->StopACQ();
digiMTX[iDigi].unlock(); digiMTX[iDigi].unlock();
digi[iDigi]->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, traceOn[iDigi], -1); readDataThread[iDigi]->quit();
readDataThread[iDigi]->wait();
} }
emit UpdateOtherPanels();
bnScopeStart->setEnabled(true); bnScopeStart->setEnabled(true);
bnScopeStop->setEnabled(false); bnScopeStop->setEnabled(false);
@ -291,28 +273,25 @@ void Scope::StopScope(){
TellACQOnOff(false); TellACQOnOff(false);
// printf("----- end of %s\n", __func__);
} }
void Scope::UpdateScope(){ void Scope::UpdateScope(){
//printf("---- %s \n", __func__);
if( !digi ) return; if( !digi ) return;
int ch = cbScopeCh->currentIndex(); int ch = cbScopeCh->currentIndex();
if( digi[ID]->GetChannelOnOff(ch) == false) return;
int ch2ns = digi[ID]->GetCh2ns(); int ch2ns = digi[ID]->GetCh2ns();
int factor = digi[ID]->IsDualTrace_PHA() ? 2 : 1; int factor = digi[ID]->IsDualTrace() ? 2 : 1;
digiMTX[ID].lock();
Data * data = digi[ID]->GetData(); Data * data = digi[ID]->GetData();
digiMTX[ID].lock();
//leTriggerRate->setText(QString::number(data->TriggerRate[ch]) + " [" + QString::number(data->NumEventsDecoded[ch]) + "]"); //leTriggerRate->setText(QString::number(data->TriggerRate[ch]) + " [" + QString::number(data->NumEventsDecoded[ch]) + "]");
leTriggerRate->setText(QString::number(data->TriggerRate[ch])); leTriggerRate->setText(QString::number(data->TriggerRate[ch]));
unsigned short index = data->EventIndex[ch]; unsigned short index = data->EventIndex[ch] - 1;
unsigned short traceLength = data->Waveform1[ch][index].size(); unsigned short traceLength = data->Waveform1[ch][index].size();
if( data->TriggerRate[ch] > 0 ){ if( data->TriggerRate[ch] > 0 ){
@ -386,7 +365,6 @@ void Scope::SetUpComboBox(RComboBox * &cb, QString str, int row, int col, const
if( digi[ID]->GetErrorCode() == CAEN_DGTZ_Success ){ if( digi[ID]->GetErrorCode() == CAEN_DGTZ_Success ){
SendLogMsg(msg + " | OK."); SendLogMsg(msg + " | OK.");
cb->setStyleSheet(""); cb->setStyleSheet("");
emit UpdateOtherPanels();
}else{ }else{
SendLogMsg(msg + " | Fail."); SendLogMsg(msg + " | Fail.");
cb->setStyleSheet("color:red;"); cb->setStyleSheet("color:red;");
@ -434,7 +412,7 @@ void Scope::SetUpSpinBox(RSpinBox * &sb, QString str, int row, int col, const Re
uint32_t value = sb->value() / ch2ns / abs(para.GetPartialStep()); uint32_t value = sb->value() / ch2ns / abs(para.GetPartialStep());
if( para == DPP::RecordLength_G){ if( para == DPP::RecordLength_G){
int factor = digi[ID]->IsDualTrace_PHA() ? 2 : 1; int factor = digi[ID]->IsDualTrace() ? 2 : 1;
value = value * factor; value = value * factor;
} }
@ -454,7 +432,6 @@ void Scope::SetUpSpinBox(RSpinBox * &sb, QString str, int row, int col, const Re
if( digi[ID]->GetErrorCode() == CAEN_DGTZ_Success ){ if( digi[ID]->GetErrorCode() == CAEN_DGTZ_Success ){
SendLogMsg(msg + " | OK."); SendLogMsg(msg + " | OK.");
sb->setStyleSheet(""); sb->setStyleSheet("");
emit UpdateOtherPanels();
}else{ }else{
SendLogMsg(msg + " | Fail."); SendLogMsg(msg + " | Fail.");
sb->setStyleSheet("color:red;"); sb->setStyleSheet("color:red;");
@ -475,6 +452,7 @@ void Scope::CleanUpSettingsGroupBox(){
} }
void Scope::SetUpPHAPanel(){ void Scope::SetUpPHAPanel(){
printf("--- %s \n", __func__); printf("--- %s \n", __func__);
@ -718,8 +696,6 @@ void Scope::UpdatePanelFromMomeory(){
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHAPanel(); if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHAPanel();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDPanel(); if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDPanel();
settingGroup->setEnabled(digi[ID]->GetChannelOnOff(ch));
} }
void Scope::UpdatePHAPanel(){ void Scope::UpdatePHAPanel(){

View File

@ -37,12 +37,11 @@ public:
event->accept(); event->accept();
} }
public slots: private slots:
void StartScope(); void StartScope();
void StopScope(); void StopScope();
void UpdateScope(); void UpdateScope();
void ReadSettingsFromBoard(); void ReadSettingsFromBoard();
void UpdatePanelFromMomeory();
signals: signals:
@ -50,7 +49,6 @@ signals:
void SendLogMsg(const QString &msg); void SendLogMsg(const QString &msg);
void TellACQOnOff(const bool onOff); void TellACQOnOff(const bool onOff);
void UpdateScaler(); void UpdateScaler();
void UpdateOtherPanels();
private: private:
@ -65,6 +63,7 @@ private:
void UpdateComobox(RComboBox * &cb, const Reg para); void UpdateComobox(RComboBox * &cb, const Reg para);
void UpdateSpinBox(RSpinBox * &sb, const Reg para); void UpdateSpinBox(RSpinBox * &sb, const Reg para);
void UpdatePanelFromMomeory();
void UpdatePHAPanel(); void UpdatePHAPanel();
void UpdatePSDPanel(); void UpdatePSDPanel();
@ -72,7 +71,6 @@ private:
unsigned short nDigi; unsigned short nDigi;
unsigned short ID; // the id of digi, index of cbScopeDigi unsigned short ID; // the id of digi, index of cbScopeDigi
int ch2ns; int ch2ns;
bool traceOn[MaxNDigitizer];
ReadDataThread ** readDataThread; ReadDataThread ** readDataThread;
TimingThread * updateTraceThread; TimingThread * updateTraceThread;

View File

@ -1,157 +0,0 @@
#include "influxdb.h"
InfluxDB::InfluxDB(std::string url, bool verbose){
curl = curl_easy_init();
if( verbose) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
SetURL(url);
respondCode = 0;
dataPoints = "";
}
InfluxDB::~InfluxDB(){
curl_easy_cleanup(curl);
}
void InfluxDB::SetURL(std::string url){
// check the last char of url is "/"
if( url.back() != '/') {
this->databaseIP = url + "/";
}else{
this->databaseIP = url;
}
}
bool InfluxDB::TestingConnection(){
CheckDatabases();
if( respond != CURLE_OK ) return false;
return true;
}
std::string InfluxDB::CheckDatabases(){
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str());
std::string postFields="q=Show databases";
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(postFields.length()));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
Execute();
//printf("|%s|\n", readBuffer.c_str());
if( respond != CURLE_OK) return "";
databaseList.clear();
size_t pos = readBuffer.find("values");
if( pos > 0 ){
std::string kaka = readBuffer.substr(pos+8);
pos = kaka.find("}");
kaka = kaka.substr(0, pos);
int len = kaka.length();
bool startFlag = false;
std::string lala;
char yaya = '"';
for( int i = 0; i < len; i++){
if( startFlag == false && kaka[i] == yaya ) {
startFlag = true;
lala = "";
continue;
}
if( startFlag && kaka[i] == yaya ){
startFlag = false;
databaseList.push_back(lala);
continue;
}
if( startFlag ) lala += kaka[i];
}
}
return readBuffer;
}
std::string InfluxDB::Query(std::string databaseName, std::string query){
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query?db=" + databaseName).c_str());
std::string postFields = "q=" + query;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(postFields.length()));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
Execute();
//printf("|%s|\n", readBuffer.c_str());
return readBuffer;
}
void InfluxDB::CreateDatabase(std::string databaseName){
curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
std::string postFields = "q=CREATE DATABASE " + databaseName;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(postFields.length()));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());
Execute();
}
void InfluxDB::AddDataPoint(std::string fullString){
dataPoints += fullString + "\n";
}
void InfluxDB::ClearDataPointsBuffer(){
dataPoints = "";
}
void InfluxDB::PrintDataPoints(){
printf("%s\n", dataPoints.c_str());
}
void InfluxDB::WriteData(std::string databaseName){
if( dataPoints.length() == 0 ) return;
//printf("|%s|\n", (databaseIP + "write?db=" + databaseName).c_str());
curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "write?db=" + databaseName).c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(dataPoints.length()));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataPoints.c_str());
Execute();
}
void InfluxDB::Execute(){
try{
respond = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode);
//printf("==== respond %d (OK = %d)\n", respond, CURLE_OK);
if( respond != CURLE_OK) printf("############# InfluxDB::Execute fail\n");
} catch (std::exception& e){ // in case of unexpected error
printf("%s\n", e.what());
respond = CURLE_SEND_ERROR;
}
}
size_t InfluxDB::WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp){
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}

View File

@ -1,58 +0,0 @@
#ifndef INFLUXDB_H
#define INFLUXDB_H
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
#include <curl/curl.h>
class InfluxDB{
private:
bool isURLValid;
CURL * curl;
CURLcode respond;
long respondCode;
std::string databaseIP;
std::string dataPoints;
std::vector<std::string> databaseList;
static size_t WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp);
void Execute();
public:
InfluxDB(std::string url, bool verbose = false);
~InfluxDB();
void SetURL(std::string url);
bool TestingConnection();
bool IsURLValid() const {return isURLValid;}
/// Query
std::string CheckDatabases(); /// this save the list of database into databaseList
std::string Query(std::string databaseName, std::string query);
/// the CheckDatabases() function must be called before
std::vector<std::string> GetDatabaseList() {return databaseList;}
void CreateDatabase(std::string databaseName);
/// for single or batch write,
/// 1, addDataPoint first, you can add as many as you like
/// 2, writeData.
void AddDataPoint(std::string fullString);
unsigned int GetDataLength() const {return dataPoints.length();}
void ClearDataPointsBuffer();
void PrintDataPoints();
void WriteData(std::string databaseName);
bool IsWriteOK() const {return (respond == CURLE_OK) ? true: false;}
};
#endif