2023-04-11 11:13:23 -04:00
|
|
|
#ifndef DATA_H
|
|
|
|
#define DATA_H
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstring> ///memset
|
|
|
|
#include <iostream> ///cout
|
2023-10-05 14:30:04 -04:00
|
|
|
#include <sstream>
|
|
|
|
#include <iomanip> // for setw
|
2023-10-18 18:33:29 -04:00
|
|
|
#include <algorithm>
|
2023-04-11 11:13:23 -04:00
|
|
|
#include <bitset>
|
|
|
|
#include <vector>
|
2023-04-17 11:52:06 -04:00
|
|
|
#include <sys/stat.h>
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
#include "macro.h"
|
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
//#define MaxNData 10000 /// store 10k events per channels
|
|
|
|
#define DefaultDataSize 10000
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-09-08 17:21:05 -04:00
|
|
|
enum DPPType{
|
|
|
|
DPP_PHA_CODE = 0x8B,
|
2023-10-04 18:03:42 -04:00
|
|
|
DPP_PSD_CODE = 0x88,
|
|
|
|
DPP_QDC_CODE = 0x87
|
2023-09-08 17:21:05 -04:00
|
|
|
};
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
class Data{
|
|
|
|
|
|
|
|
public:
|
2023-04-19 13:41:43 -04:00
|
|
|
char *buffer; /// readout buffer
|
2023-04-17 11:52:06 -04:00
|
|
|
int DPPType;
|
2024-01-11 11:52:40 -05:00
|
|
|
std::string DPPTypeStr; /// only for saving fiel name
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned short boardSN;
|
2024-01-12 16:59:55 -05:00
|
|
|
int tick2ns; /// use in convert the timestamp to ns, and use in TriggerRate calculation
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
unsigned int nByte; /// number of byte from read buffer
|
2023-10-06 17:57:43 -04:00
|
|
|
uint32_t AllocatedSize;
|
|
|
|
|
|
|
|
float TriggerRate [MaxNChannels]; /// Hz
|
|
|
|
float NonPileUpRate [MaxNChannels]; /// Hz
|
|
|
|
unsigned long TotNumNonPileUpEvents[MaxNChannels]; /// also exclude overthrow
|
|
|
|
unsigned short NumEventsDecoded [MaxNChannels]; /// reset at every decode
|
|
|
|
unsigned short NumNonPileUpDecoded [MaxNChannels]; /// reset at every decode
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-12-11 18:55:12 -05:00
|
|
|
unsigned int aggTime; /// update every decode
|
|
|
|
|
2023-04-19 18:08:20 -04:00
|
|
|
/// store data for event building and deduce the trigger rate.
|
2023-05-25 18:50:42 -04:00
|
|
|
//it is a circular memory
|
2023-04-11 11:13:23 -04:00
|
|
|
bool IsNotRollOverFakeAgg;
|
2023-06-09 13:51:02 -04:00
|
|
|
|
2023-10-06 17:57:43 -04:00
|
|
|
int LoopIndex[MaxNChannels]; /// number of loop in the circular memory
|
|
|
|
int DataIndex[MaxNChannels];
|
2023-06-09 13:51:02 -04:00
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
uShort GetDataSize() const {return dataSize;}
|
|
|
|
ullong ** Timestamp; /// 47 bit
|
|
|
|
uShort ** fineTime; /// 10 bits, in unit of tick2ns / 1000 = ps
|
|
|
|
uShort ** Energy ; /// 15 bit
|
|
|
|
uShort ** Energy2 ; /// 15 bit, in PSD, Energy = Qshort, Energy2 = Qlong
|
|
|
|
bool ** PileUp ; /// pile up flag
|
|
|
|
|
|
|
|
std::vector<short> ** Waveform1 ; // used at least 14 MB
|
|
|
|
std::vector<short> ** Waveform2 ;
|
|
|
|
std::vector<bool> ** DigiWaveform1;
|
|
|
|
std::vector<bool> ** DigiWaveform2;
|
|
|
|
std::vector<bool> ** DigiWaveform3;
|
|
|
|
std::vector<bool> ** DigiWaveform4;
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
public:
|
2024-01-18 23:09:50 -05:00
|
|
|
Data(unsigned short numCh, uShort dataSize = DefaultDataSize);
|
2023-04-11 11:13:23 -04:00
|
|
|
~Data();
|
|
|
|
|
|
|
|
void Allocate80MBMemory();
|
|
|
|
void AllocateMemory(uint32_t size);
|
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
void AllocateDataSize(uShort dataSize);
|
|
|
|
void ClearDataPointer();
|
2023-04-11 11:13:23 -04:00
|
|
|
void ClearData();
|
|
|
|
void ClearTriggerRate();
|
|
|
|
void ClearBuffer();
|
2023-11-21 17:17:31 -05:00
|
|
|
|
|
|
|
unsigned short GetNChannel() const {return numInputCh;}
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
void CopyBuffer( const char * buffer, const unsigned int size);
|
2023-04-17 11:52:06 -04:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
void DecodeBuffer(bool fastDecode, int verbose = 0); /// fastDecode will not save waveform
|
2023-05-16 11:26:22 -04:00
|
|
|
void DecodeBuffer(char * &buffer, unsigned int size, bool fastDecode, int verbose = 0); // for outside data
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-12-12 15:35:47 -05:00
|
|
|
void DecodeDualBlock(char * &buffer, unsigned int size, int DPPType, int chMask, bool fastDecode, int verbose = 0); // for outside data
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-12-12 17:52:32 -05:00
|
|
|
void PrintStat(bool skipEmpty = true);
|
2023-06-29 18:59:36 -04:00
|
|
|
void PrintAllData(bool tableMode = true, unsigned int maxRowDisplay = 0) const;
|
2024-01-12 16:59:55 -05:00
|
|
|
void PrintChData(unsigned short ch, unsigned int maxRowDisplay = 0) const;
|
2023-04-17 11:52:06 -04:00
|
|
|
|
|
|
|
//^================= Saving data
|
2023-05-17 16:16:48 -04:00
|
|
|
bool OpenSaveFile(std::string fileNamePrefix); // return false when fail
|
|
|
|
std::string GetOutFileName() const {return outFileName;}
|
2023-04-17 11:52:06 -04:00
|
|
|
void SaveData();
|
|
|
|
void CloseSaveFile();
|
|
|
|
unsigned int GetFileSize() const {return outFileSize;}
|
|
|
|
uint64_t GetTotalFileSize() const {return FinishedOutFilesSize + outFileSize;}
|
2023-05-22 18:23:24 -04:00
|
|
|
void ZeroTotalFileSize() { FinishedOutFilesSize = 0; }
|
2023-12-12 15:35:47 -05:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
protected:
|
2023-10-06 17:57:43 -04:00
|
|
|
|
2023-10-09 17:46:32 -04:00
|
|
|
const unsigned short numInputCh;
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned int nw;
|
2023-04-14 16:12:52 -04:00
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
uShort dataSize;
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
///for temperary
|
2023-04-20 13:49:36 -04:00
|
|
|
std::vector<short> tempWaveform1;
|
|
|
|
std::vector<short> tempWaveform2;
|
2023-04-11 11:13:23 -04:00
|
|
|
std::vector<bool> tempDigiWaveform1;
|
|
|
|
std::vector<bool> tempDigiWaveform2;
|
2023-10-06 16:50:28 -04:00
|
|
|
std::vector<bool> tempDigiWaveform3;
|
|
|
|
std::vector<bool> tempDigiWaveform4;
|
2023-04-19 13:41:43 -04:00
|
|
|
|
|
|
|
FILE * outFile;
|
|
|
|
uint64_t FinishedOutFilesSize; // sum of files size.
|
|
|
|
unsigned int outFileIndex;
|
|
|
|
std::string outFilePrefix;
|
|
|
|
std::string outFileName;
|
|
|
|
unsigned int outFileSize; // should be max at 2 GB
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
short calIndexes[MaxNChannels][2]; /// the index for trigger rate calculation
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned int ReadBuffer(unsigned int nWord, int verbose = 0);
|
|
|
|
|
|
|
|
int DecodePHADualChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose);
|
|
|
|
int DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose);
|
2023-10-06 16:50:28 -04:00
|
|
|
int DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose);
|
2023-04-11 11:13:23 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
//==========================================
|
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
inline Data::Data(unsigned short numCh, uShort dataSize): numInputCh(numCh){
|
2023-06-20 11:57:39 -04:00
|
|
|
tick2ns = 2.0;
|
2023-04-11 11:13:23 -04:00
|
|
|
boardSN = 0;
|
2023-09-08 17:21:05 -04:00
|
|
|
DPPType = DPPType::DPP_PHA_CODE;
|
2023-04-17 11:52:06 -04:00
|
|
|
DPPTypeStr = "";
|
2023-04-11 11:13:23 -04:00
|
|
|
IsNotRollOverFakeAgg = false;
|
|
|
|
buffer = NULL;
|
2024-01-18 23:09:50 -05:00
|
|
|
|
|
|
|
AllocateDataSize(dataSize);
|
|
|
|
|
2023-10-04 13:13:38 -04:00
|
|
|
for ( int i = 0; i < MaxNChannels; i++) TotNumNonPileUpEvents[i] = 0;
|
2023-04-11 11:13:23 -04:00
|
|
|
ClearData();
|
|
|
|
ClearTriggerRate();
|
|
|
|
nw = 0;
|
2023-04-14 16:12:52 -04:00
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
outFileIndex = 0;
|
|
|
|
outFilePrefix = "";
|
|
|
|
outFileName = "";
|
|
|
|
outFile = nullptr;
|
|
|
|
outFileSize = 0; // should be max at 2 GB
|
|
|
|
FinishedOutFilesSize = 0; // sum of files size.
|
2024-01-18 23:09:50 -05:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline Data::~Data(){
|
|
|
|
if( buffer != NULL ) delete buffer;
|
2024-01-18 23:09:50 -05:00
|
|
|
|
|
|
|
ClearDataPointer();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::AllocateDataSize(uShort dataSize){
|
|
|
|
|
2024-01-19 03:06:36 -05:00
|
|
|
if( dataSize < 1) {
|
|
|
|
printf("dataSize cannot < 1, set dataSize = 1.\n");
|
|
|
|
dataSize = 1;
|
|
|
|
}
|
2024-01-19 13:21:59 -05:00
|
|
|
//printf("Data::%s, size: %u\n", __func__, dataSize);
|
2024-01-18 23:09:50 -05:00
|
|
|
|
|
|
|
this->dataSize = dataSize;
|
|
|
|
|
|
|
|
Timestamp = new ullong * [numInputCh];
|
|
|
|
fineTime = new uShort * [numInputCh];
|
|
|
|
Energy = new uShort * [numInputCh];
|
|
|
|
Energy2 = new uShort * [numInputCh];
|
|
|
|
PileUp = new bool * [numInputCh];
|
|
|
|
|
|
|
|
Waveform1 = new std::vector<short> * [numInputCh];
|
|
|
|
Waveform2 = new std::vector<short> * [numInputCh];
|
|
|
|
DigiWaveform1 = new std::vector<bool> * [numInputCh];
|
|
|
|
DigiWaveform2 = new std::vector<bool> * [numInputCh];
|
|
|
|
DigiWaveform3 = new std::vector<bool> * [numInputCh];
|
|
|
|
DigiWaveform4 = new std::vector<bool> * [numInputCh];
|
|
|
|
|
|
|
|
for(int ch = 0; ch < numInputCh; ch++){
|
|
|
|
Timestamp[ch] = new ullong[dataSize];
|
|
|
|
fineTime[ch] = new uShort[dataSize];
|
|
|
|
Energy[ch] = new uShort[dataSize];
|
|
|
|
Energy2[ch] = new uShort[dataSize];
|
|
|
|
PileUp[ch] = new bool[dataSize];
|
|
|
|
|
|
|
|
Waveform1[ch] = new std::vector<short> [dataSize];
|
|
|
|
Waveform2[ch] = new std::vector<short> [dataSize];
|
|
|
|
DigiWaveform1[ch] = new std::vector<bool> [dataSize];
|
|
|
|
DigiWaveform2[ch] = new std::vector<bool> [dataSize];
|
|
|
|
DigiWaveform3[ch] = new std::vector<bool> [dataSize];
|
|
|
|
DigiWaveform4[ch] = new std::vector<bool> [dataSize];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::ClearDataPointer(){
|
|
|
|
|
|
|
|
for(int ch = 0; ch < numInputCh; ch++){
|
|
|
|
delete [] Timestamp[ch] ;
|
|
|
|
delete [] fineTime[ch];
|
|
|
|
delete [] Energy[ch];
|
|
|
|
delete [] Energy2[ch];
|
|
|
|
delete [] PileUp[ch];
|
|
|
|
|
|
|
|
delete [] Waveform1[ch];
|
|
|
|
delete [] Waveform2[ch];
|
|
|
|
delete [] DigiWaveform1[ch];
|
|
|
|
delete [] DigiWaveform2[ch];
|
|
|
|
delete [] DigiWaveform3[ch];
|
|
|
|
delete [] DigiWaveform4[ch];
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] Timestamp;
|
|
|
|
delete [] fineTime;
|
|
|
|
delete [] Energy;
|
|
|
|
delete [] Energy2;
|
|
|
|
delete [] PileUp;
|
|
|
|
|
|
|
|
delete [] Waveform1;
|
|
|
|
delete [] Waveform2;
|
|
|
|
delete [] DigiWaveform1;
|
|
|
|
delete [] DigiWaveform2;
|
|
|
|
delete [] DigiWaveform3;
|
|
|
|
delete [] DigiWaveform4;
|
|
|
|
|
|
|
|
dataSize = 0;
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::AllocateMemory(uint32_t size){
|
|
|
|
ClearBuffer();
|
|
|
|
AllocatedSize = size;
|
|
|
|
buffer = (char *) malloc( AllocatedSize);
|
2023-11-17 17:41:10 -05:00
|
|
|
printf("Allocated %u byte ( %.2f MB) for buffer = %u words\n", AllocatedSize, AllocatedSize/1024./1024., AllocatedSize / 4);
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::Allocate80MBMemory(){
|
|
|
|
AllocateMemory( 80 * 1024 * 1024 ); /// 80 M Byte
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::ClearTriggerRate(){
|
|
|
|
for( int i = 0 ; i < MaxNChannels; i++) {
|
|
|
|
TriggerRate[i] = 0.0;
|
2023-04-19 16:21:14 -04:00
|
|
|
NonPileUpRate[i] = 0.0;
|
2023-04-11 11:13:23 -04:00
|
|
|
NumEventsDecoded[i] = 0;
|
2023-04-19 16:21:14 -04:00
|
|
|
NumNonPileUpDecoded[i] = 0;
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::ClearData(){
|
|
|
|
nByte = 0;
|
|
|
|
AllocatedSize = 0;
|
|
|
|
IsNotRollOverFakeAgg = false;
|
2023-05-16 11:26:22 -04:00
|
|
|
for( int ch = 0 ; ch < MaxNChannels; ch++){
|
2023-05-25 18:50:42 -04:00
|
|
|
LoopIndex[ch] = 0;
|
|
|
|
DataIndex[ch] = -1;
|
2024-01-19 03:06:36 -05:00
|
|
|
NumEventsDecoded[ch] = 0;
|
|
|
|
NumNonPileUpDecoded[ch] = 0;
|
|
|
|
|
|
|
|
TotNumNonPileUpEvents[ch] = 0 ;
|
|
|
|
|
|
|
|
calIndexes[ch][0] = -1;
|
|
|
|
calIndexes[ch][1] = -1;
|
|
|
|
|
|
|
|
if( ch >= numInputCh) break;
|
2024-01-18 23:09:50 -05:00
|
|
|
for( int j = 0; j < dataSize; j++){
|
2023-05-16 11:26:22 -04:00
|
|
|
Timestamp[ch][j] = 0;
|
|
|
|
fineTime[ch][j] = 0;
|
|
|
|
Energy[ch][j] = 0;
|
|
|
|
Energy2[ch][j] = 0;
|
|
|
|
Waveform1[ch][j].clear();
|
|
|
|
Waveform2[ch][j].clear();
|
|
|
|
DigiWaveform1[ch][j].clear();
|
|
|
|
DigiWaveform2[ch][j].clear();
|
2023-10-06 16:50:28 -04:00
|
|
|
DigiWaveform3[ch][j].clear();
|
|
|
|
DigiWaveform4[ch][j].clear();
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-04-20 14:39:59 -04:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
tempWaveform1.clear();
|
|
|
|
tempWaveform2.clear();
|
|
|
|
tempDigiWaveform1.clear();
|
|
|
|
tempDigiWaveform2.clear();
|
2023-10-06 16:50:28 -04:00
|
|
|
tempDigiWaveform3.clear();
|
|
|
|
tempDigiWaveform4.clear();
|
2024-01-19 03:06:36 -05:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::ClearBuffer(){
|
2023-06-14 15:20:15 -04:00
|
|
|
//printf("==== Data::%s \n", __func__);
|
2023-04-11 11:13:23 -04:00
|
|
|
delete buffer;
|
2023-04-19 18:08:20 -04:00
|
|
|
buffer = nullptr;
|
2023-04-11 11:13:23 -04:00
|
|
|
AllocatedSize = 0;
|
|
|
|
nByte = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::CopyBuffer(const char * buffer, const unsigned int size){
|
|
|
|
std::memcpy(this->buffer, buffer, size);
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
//^###############################################
|
|
|
|
//^############################################### Save fsu file
|
2023-05-17 16:16:48 -04:00
|
|
|
inline bool Data::OpenSaveFile(std::string fileNamePrefix){
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
outFilePrefix = fileNamePrefix;
|
2023-10-05 14:30:04 -04:00
|
|
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << outFilePrefix << "_"
|
|
|
|
<< std::setfill('0') << std::setw(3) << boardSN << "_"
|
|
|
|
<< DPPTypeStr << "_"
|
2024-01-11 11:52:40 -05:00
|
|
|
<< std::fixed << std::setprecision(0) << tick2ns << "_"
|
2023-10-05 14:30:04 -04:00
|
|
|
<< std::setfill('0') << std::setw(3) << outFileIndex << ".fsu";
|
|
|
|
std::string saveFileName = oss.str();
|
|
|
|
|
|
|
|
//char saveFileName[100];
|
|
|
|
//sprintf(saveFileName, "%s_%03d_%3s_%03u.fsu", outFilePrefix.c_str() , boardSN, DPPTypeStr.c_str(), outFileIndex);
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
outFileName = saveFileName;
|
2023-10-05 14:30:04 -04:00
|
|
|
outFile = fopen(saveFileName.c_str(), "wb"); // overwrite binary
|
2023-05-17 16:16:48 -04:00
|
|
|
|
|
|
|
if (outFile == NULL) {
|
|
|
|
printf("Failed to open the file. Probably Read-ONLY.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
fseek(outFile, 0L, SEEK_END);
|
|
|
|
outFileSize = ftell(outFile);
|
2023-05-17 16:16:48 -04:00
|
|
|
|
|
|
|
return true;
|
2023-04-17 11:52:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::SaveData(){
|
|
|
|
|
2023-05-23 14:52:23 -04:00
|
|
|
if( buffer == nullptr) {
|
|
|
|
printf("buffer is null.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-06-09 13:51:02 -04:00
|
|
|
if( outFile == nullptr ) return;
|
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
if( outFileSize > (unsigned int) MaxSaveFileSize){
|
|
|
|
FinishedOutFilesSize += ftell(outFile);
|
|
|
|
CloseSaveFile();
|
|
|
|
outFileIndex ++;
|
2023-10-05 14:30:04 -04:00
|
|
|
|
|
|
|
// char saveFileName[100];
|
|
|
|
// sprintf(saveFileName, "%s_%03d_%3s_%03u.fsu", outFilePrefix.c_str() , boardSN, DPPTypeStr.c_str(), outFileIndex);
|
|
|
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << outFilePrefix << "_"
|
|
|
|
<< std::setfill('0') << std::setw(3) << boardSN << "_"
|
|
|
|
<< DPPTypeStr << "_"
|
2024-01-11 11:52:40 -05:00
|
|
|
<< std::fixed << std::setprecision(0) << tick2ns << "_"
|
2023-10-05 14:30:04 -04:00
|
|
|
<< std::setfill('0') << std::setw(3) << outFileIndex << ".fsu";
|
|
|
|
std::string saveFileName = oss.str();
|
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
outFileName = saveFileName;
|
|
|
|
outFile = fopen(outFileName.c_str(), "wb"); //overwrite binary
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
2023-04-17 11:52:06 -04:00
|
|
|
fwrite(buffer, nByte, 1, outFile);
|
|
|
|
outFileSize = ftell(outFile);
|
|
|
|
|
|
|
|
}
|
|
|
|
inline void Data::CloseSaveFile(){
|
2023-08-24 13:27:16 -04:00
|
|
|
if( outFile != nullptr ){
|
2023-04-17 11:52:06 -04:00
|
|
|
fclose(outFile);
|
2023-08-24 13:27:16 -04:00
|
|
|
outFile = nullptr;
|
2023-04-17 11:52:06 -04:00
|
|
|
int result = chmod(outFileName.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
|
|
|
|
if( result != 0 ) printf("somewrong when set file (%s) to read only.", outFileName.c_str());
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
//^#######################################################
|
|
|
|
//^####################################################### Print
|
2023-12-12 17:52:32 -05:00
|
|
|
inline void Data::PrintStat(bool skipEmpty) {
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-08-22 14:38:37 -04:00
|
|
|
printf("============================= Print Stat. Digi-%d\n", boardSN);
|
2023-04-11 11:13:23 -04:00
|
|
|
if( !IsNotRollOverFakeAgg ) {
|
|
|
|
printf(" this is roll-over fake event or no events.\n");
|
|
|
|
return;
|
|
|
|
}
|
2023-08-28 15:02:56 -04:00
|
|
|
printf("%2s | %6s | %9s | %9s | %6s | %6s(%4s)\n", "ch", "# Evt.", "Rate [Hz]", "Accept", "Tot. Evt.", "index", "loop");
|
2023-04-20 14:39:59 -04:00
|
|
|
printf("---+--------+-----------+-----------+----------\n");
|
2023-10-09 17:46:32 -04:00
|
|
|
for(int ch = 0; ch < numInputCh; ch++){
|
2023-12-14 15:34:28 -05:00
|
|
|
//if( skipEmpty && TriggerRate[ch] == 0 ) continue;
|
|
|
|
if( skipEmpty && DataIndex[ch] < 0 ) continue;
|
2023-10-04 13:13:38 -04:00
|
|
|
printf("%2d | %6d | %9.2f | %9.2f | %6lu | %6d(%2d)\n", ch, NumEventsDecoded[ch], TriggerRate[ch], NonPileUpRate[ch], TotNumNonPileUpEvents[ch], DataIndex[ch], LoopIndex[ch]);
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-04-20 14:39:59 -04:00
|
|
|
printf("---+--------+-----------+-----------+----------\n");
|
2023-12-12 17:52:32 -05:00
|
|
|
|
|
|
|
ClearTriggerRate();
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
2023-06-29 18:59:36 -04:00
|
|
|
inline void Data::PrintAllData(bool tableMode, unsigned int maxRowDisplay) const{
|
2023-07-11 18:29:38 -04:00
|
|
|
printf("============================= Print Data Digi-%d\n", boardSN);
|
2023-06-09 13:51:02 -04:00
|
|
|
|
|
|
|
if( tableMode ){
|
|
|
|
int entry = 0;
|
|
|
|
|
|
|
|
int MaxEntry = 0;
|
|
|
|
printf("%4s|", "");
|
2023-10-09 17:46:32 -04:00
|
|
|
for( int ch = 0; ch < numInputCh; ch++){
|
2023-06-09 13:51:02 -04:00
|
|
|
if( LoopIndex[ch] > 0 ) {
|
2024-01-18 23:09:50 -05:00
|
|
|
MaxEntry = dataSize-1;
|
2023-06-09 13:51:02 -04:00
|
|
|
}else{
|
|
|
|
if( DataIndex[ch] > MaxEntry ) MaxEntry = DataIndex[ch];
|
|
|
|
}
|
|
|
|
if( DataIndex[ch] < 0 ) continue;
|
2024-01-18 23:09:50 -05:00
|
|
|
printf(" %5s-%02d,%2d,%-6d |", "ch", ch, LoopIndex[ch], DataIndex[ch]);
|
2023-06-09 13:51:02 -04:00
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
|
|
|
|
do{
|
|
|
|
printf("%4d|", entry );
|
2023-10-09 17:46:32 -04:00
|
|
|
for( int ch = 0; ch < numInputCh; ch++){
|
2023-06-09 13:51:02 -04:00
|
|
|
if( DataIndex[ch] < 0 ) continue;
|
2024-01-18 23:09:50 -05:00
|
|
|
printf(" %5d,%17lld |", Energy[ch][entry], Timestamp[ch][entry]);
|
2023-06-09 13:51:02 -04:00
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
entry ++;
|
2023-06-29 18:59:36 -04:00
|
|
|
|
|
|
|
if( maxRowDisplay > 0 && (unsigned int) entry >= maxRowDisplay ) break;
|
2023-06-09 13:51:02 -04:00
|
|
|
}while(entry <= MaxEntry);
|
|
|
|
|
|
|
|
}else{
|
2023-10-09 17:46:32 -04:00
|
|
|
for( int ch = 0; ch < numInputCh ; ch++){
|
2023-06-09 13:51:02 -04:00
|
|
|
if( DataIndex[ch] < 0 ) continue;
|
|
|
|
printf("------------ ch : %d, DataIndex : %d, loop : %d\n", ch, DataIndex[ch], LoopIndex[ch]);
|
2024-01-18 23:09:50 -05:00
|
|
|
for( int ev = 0; ev <= (LoopIndex[ch] > 0 ? dataSize : DataIndex[ch]) ; ev++){
|
|
|
|
if( DPPType == DPPType::DPP_PHA_CODE || DPPType == DPPType::DPP_QDC_CODE ) printf("%4d, %5u, %18llu, %5u \n", ev, Energy[ch][ev], Timestamp[ch][ev], fineTime[ch][ev]);
|
|
|
|
if( DPPType == DPPType::DPP_PSD_CODE ) printf("%4d, %5u, %5u, %18llu, %5u \n", ev, Energy[ch][ev], Energy2[ch][ev], Timestamp[ch][ev], fineTime[ch][ev]);
|
2023-06-29 18:59:36 -04:00
|
|
|
if( maxRowDisplay > 0 && (unsigned int) ev > maxRowDisplay ) break;
|
2023-06-09 13:51:02 -04:00
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-12 16:59:55 -05:00
|
|
|
inline void Data::PrintChData(unsigned short ch, unsigned int maxRowDisplay) const{
|
|
|
|
|
|
|
|
if( DataIndex[ch] < 0 ) printf("no data in ch-%d\n", ch);
|
|
|
|
printf("------------ ch : %d, DataIndex : %d, loop : %d\n", ch, DataIndex[ch], LoopIndex[ch]);
|
2024-01-19 03:06:36 -05:00
|
|
|
for( int ev = 0; ev < (LoopIndex[ch] > 0 ? dataSize : DataIndex[ch]) ; ev++){
|
2024-01-12 16:59:55 -05:00
|
|
|
if( DPPType == DPPType::DPP_PHA_CODE || DPPType == DPPType::DPP_QDC_CODE ) printf("%4d, %5u, %15llu, %5u \n", ev, Energy[ch][ev], Timestamp[ch][ev], fineTime[ch][ev]);
|
|
|
|
if( DPPType == DPPType::DPP_PSD_CODE ) printf("%4d, %5u, %5u, %15llu, %5u \n", ev, Energy[ch][ev], Energy2[ch][ev], Timestamp[ch][ev], fineTime[ch][ev]);
|
|
|
|
if( maxRowDisplay > 0 && (unsigned int) ev > maxRowDisplay ) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
//^#######################################################
|
|
|
|
//^####################################################### Decode
|
2023-04-11 11:13:23 -04:00
|
|
|
inline unsigned int Data::ReadBuffer(unsigned int nWord, int verbose){
|
|
|
|
if( buffer == NULL ) return 0;
|
|
|
|
|
|
|
|
unsigned int word = 0;
|
|
|
|
for( int i = 0 ; i < 4 ; i++) word += ((buffer[i + 4 * nWord] & 0xFF) << 8*i);
|
|
|
|
if( verbose >= 2) printf("%6d | 0x%08X | ", nWord, word);
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
inline void Data::DecodeBuffer(char * &buffer, unsigned int size, bool fastDecode, int verbose){
|
2023-04-11 11:13:23 -04:00
|
|
|
this->buffer = buffer;
|
|
|
|
this->nByte = size;
|
|
|
|
DecodeBuffer(fastDecode, verbose);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Data::DecodeBuffer(bool fastDecode, int verbose){
|
|
|
|
/// verbose : 0 = off, 1 = only energy + timestamp, 2 = show header, 3 = wave
|
|
|
|
|
|
|
|
if( buffer == NULL ) {
|
|
|
|
if( verbose >= 1 ) printf(" buffer is empty \n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-12 17:52:32 -05:00
|
|
|
//for( int ch = 0; ch < MaxNChannels; ch ++) {
|
|
|
|
// NumEventsDecoded[ch] = 0;
|
|
|
|
// NumNonPileUpDecoded[ch] = 0;
|
|
|
|
//}
|
2023-10-10 11:06:03 -04:00
|
|
|
|
2023-04-19 18:08:20 -04:00
|
|
|
if( nByte == 0 ) return;
|
2023-04-11 11:13:23 -04:00
|
|
|
nw = 0;
|
2023-10-18 18:33:29 -04:00
|
|
|
|
|
|
|
//printf("############################# agg\n");
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
do{
|
|
|
|
if( verbose >= 1 ) printf("Data::DecodeBuffer ######################################### Board Agg.\n");
|
|
|
|
unsigned int word = ReadBuffer(nw, verbose);
|
|
|
|
if( ( (word >> 28) & 0xF ) == 0xA ) { /// start of Board Agg
|
|
|
|
unsigned int nWord = word & 0x0FFFFFFF ;
|
|
|
|
if( verbose >= 1 ) printf("Number of words in this Agg : %u = %u Byte\n", nWord, nWord * 4);
|
|
|
|
|
|
|
|
nw = nw + 1; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int BoardID = ((word >> 27) & 0x1F);
|
|
|
|
unsigned short pattern = ((word >> 8 ) & 0x7FFF );
|
|
|
|
bool BoardFailFlag = ((word >> 26) & 0x1 );
|
|
|
|
unsigned int ChannelMask = ( word & 0xFF ) ;
|
|
|
|
if( verbose >= 1 ) printf("Board ID(type) : %d, FailFlag = %d, Patten = %u, ChannelMask = 0x%X\n",
|
|
|
|
BoardID, BoardFailFlag, pattern, ChannelMask);
|
|
|
|
|
|
|
|
if( BoardID > 0 ) {
|
|
|
|
switch(BoardID){
|
2023-09-08 17:21:05 -04:00
|
|
|
case 0x8 : DPPType = DPPType::DPP_PSD_CODE; break;
|
|
|
|
case 0xB : DPPType = DPPType::DPP_PHA_CODE; break;
|
2023-10-10 11:06:03 -04:00
|
|
|
case 0x7 : DPPType = DPPType::DPP_QDC_CODE; break;
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nw = nw + 1;
|
|
|
|
unsigned int bdAggCounter = ReadBuffer(nw, verbose);
|
|
|
|
if( verbose >= 1 ) printf("Board Agg Counter : %u \n", bdAggCounter & 0x7FFFFF);
|
|
|
|
|
|
|
|
nw = nw + 1;
|
2023-12-11 18:55:12 -05:00
|
|
|
aggTime = ReadBuffer(nw, verbose);
|
|
|
|
if( verbose >= 1 ) printf("Agg Time Tag : %u \n", aggTime);
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-10-11 18:28:19 -04:00
|
|
|
for( int chMask = 0; chMask < 8 ; chMask ++ ){ // the max numnber of Coupled/RegChannel is 8 for PHA, PSD, QDC
|
2023-04-11 11:13:23 -04:00
|
|
|
if( ((ChannelMask >> chMask) & 0x1 ) == 0 ) continue;
|
2023-10-10 11:06:03 -04:00
|
|
|
if( verbose >= 2 ) printf("==================== Dual/Group Channel Block, ch Mask : 0x%X, nw : %d\n", chMask *2, nw);
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-12-12 15:35:47 -05:00
|
|
|
nw = nw + 1;
|
|
|
|
|
2023-09-08 17:21:05 -04:00
|
|
|
if( DPPType == DPPType::DPP_PHA_CODE ) {
|
2023-04-11 11:13:23 -04:00
|
|
|
if ( DecodePHADualChannelBlock(chMask, fastDecode, verbose) < 0 ) break;
|
|
|
|
}
|
2023-09-08 17:21:05 -04:00
|
|
|
if( DPPType == DPPType::DPP_PSD_CODE ) {
|
2023-05-16 17:21:40 -04:00
|
|
|
if ( DecodePSDDualChannelBlock(chMask, fastDecode, verbose) < 0 ) break;
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-10-06 16:50:28 -04:00
|
|
|
if( DPPType == DPPType::DPP_QDC_CODE ) {
|
|
|
|
if ( DecodeQDCGroupedChannelBlock(chMask, fastDecode, verbose) < 0 ) break;
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if( verbose >= 1 ) printf("nw : %d, incorrect buffer header. \n", nw);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nw++;
|
|
|
|
///printf("nw : %d ,x 4 = %d, nByte : %d \n", nw, 4*nw, nByte);
|
|
|
|
}while(4*nw < nByte);
|
|
|
|
|
2023-10-12 16:27:56 -04:00
|
|
|
///^===================Calculate trigger rate and first and last Timestamp
|
2023-04-11 11:13:23 -04:00
|
|
|
for(int ch = 0; ch < MaxNChannels; ch++){
|
2023-10-10 11:06:03 -04:00
|
|
|
if( ch > numInputCh ) continue;
|
2023-12-11 19:02:54 -05:00
|
|
|
if( DataIndex[ch] < 0 ) continue;
|
2023-10-10 11:06:03 -04:00
|
|
|
|
2023-04-20 18:15:30 -04:00
|
|
|
if( NumEventsDecoded[ch] > 0 ) {
|
2023-08-17 12:38:15 -04:00
|
|
|
// printf("%s | ch %d | %d %d \n", __func__, ch, LoopIndex[ch], DataIndex[ch]);
|
2023-04-20 18:15:30 -04:00
|
|
|
IsNotRollOverFakeAgg = true;
|
|
|
|
}else{
|
2023-12-11 19:02:54 -05:00
|
|
|
// TriggerRate[ch] = 0;
|
|
|
|
// NonPileUpRate[ch] = 0;
|
2023-04-20 18:15:30 -04:00
|
|
|
continue;
|
|
|
|
}
|
2023-10-18 18:33:29 -04:00
|
|
|
|
|
|
|
//printf("Ch : %2d | Decoded Event : %d \n", ch, NumEventsDecoded[ch]);
|
2023-04-20 14:39:59 -04:00
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
if( NumEventsDecoded[ch] > 4 ){
|
|
|
|
|
2023-05-25 18:50:42 -04:00
|
|
|
int indexStart = DataIndex[ch] - NumEventsDecoded[ch] + 1;
|
2024-01-18 23:09:50 -05:00
|
|
|
if( indexStart < 0 ) indexStart += dataSize;
|
2023-05-16 11:26:22 -04:00
|
|
|
|
2023-05-25 18:50:42 -04:00
|
|
|
unsigned long long dTime = Timestamp[ch][DataIndex[ch]] - Timestamp[ch][indexStart];
|
2023-06-20 11:57:39 -04:00
|
|
|
double sec = dTime * tick2ns / 1e9;
|
2023-05-16 11:26:22 -04:00
|
|
|
|
2023-08-22 14:38:37 -04:00
|
|
|
TriggerRate[ch] = (NumEventsDecoded[ch]-1)/sec;
|
2023-11-15 19:22:50 -05:00
|
|
|
NonPileUpRate[ch] = (NumNonPileUpDecoded[ch]-1)/sec;
|
|
|
|
//printf("%d %d| %d %d | %llu, %.3e | %.2f, %.2f\n", indexStart, DataIndex[ch], NumEventsDecoded[ch], NumNonPileUpDecoded[ch], dTime, sec , TriggerRate[ch], NonPileUpRate[ch]);
|
2023-05-16 11:26:22 -04:00
|
|
|
|
|
|
|
}else{ // look in to the data in the memory, not just this agg.
|
2023-10-18 18:33:29 -04:00
|
|
|
|
|
|
|
const short nEvent = 10;
|
|
|
|
|
|
|
|
if( TotNumNonPileUpEvents[ch] >= nEvent ){
|
|
|
|
|
|
|
|
calIndexes[ch][1] = DataIndex[ch];
|
|
|
|
calIndexes[ch][0] = DataIndex[ch] - nEvent + 1;
|
2024-01-18 23:09:50 -05:00
|
|
|
if (calIndexes[ch][0] < 0 ) calIndexes[ch][0] += dataSize;
|
2023-10-18 18:33:29 -04:00
|
|
|
|
|
|
|
// std::vector<unsigned long long> tList ;
|
|
|
|
// for( int i = 0; i < nEvent ; i ++){
|
2024-01-18 23:09:50 -05:00
|
|
|
// int j = (calIndexes[ch][0] + i) % dataSize;
|
2023-10-18 18:33:29 -04:00
|
|
|
// tList.push_back( Timestamp[ch][j]);
|
|
|
|
// }
|
|
|
|
// if( DPPType == DPPType::DPP_QDC_CODE){
|
|
|
|
// //std::sort(tList.begin(), tList.end());
|
|
|
|
// unsigned long long t0 = tList.front(); // earlier
|
|
|
|
// unsigned long long t1 = tList.back(); // latest
|
|
|
|
|
|
|
|
// for( int i = 0; i < (int) tList.size(); i++){
|
|
|
|
// if( t0 < tList[i]) t0 = tList[i];
|
|
|
|
// if( t1 > tList[i]) t1 = tList[i];
|
|
|
|
// }
|
|
|
|
// tList.front() = t0;
|
|
|
|
// tList.back() = t1;
|
|
|
|
// }
|
|
|
|
//double sec = ( tList.back() - tList.front() ) * tick2ns / 1e9;
|
|
|
|
|
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
unsigned long long t0 = Timestamp[ch][(calIndexes[ch][0]) % dataSize]; // earlier
|
|
|
|
unsigned long long t1 = Timestamp[ch][(calIndexes[ch][1]) % dataSize];; // latest
|
2023-10-19 14:29:28 -04:00
|
|
|
|
2023-10-26 17:57:06 -04:00
|
|
|
if( t0 > t1 ) {
|
|
|
|
printf("digi-%d, ch-%d | data is not in time order\n", boardSN, ch);
|
|
|
|
unsigned long long tt = t1;
|
|
|
|
t1 = t0;
|
|
|
|
t0 = tt;
|
|
|
|
}
|
2023-10-19 14:29:28 -04:00
|
|
|
|
2023-10-18 18:33:29 -04:00
|
|
|
double sec = ( t1 - t0 ) * tick2ns / 1e9;
|
|
|
|
|
|
|
|
TriggerRate[ch] = nEvent / sec;
|
|
|
|
|
|
|
|
short pileUpCount = 0;
|
|
|
|
for( int i = 0 ; i < nEvent; i++ ) {
|
2024-01-18 23:09:50 -05:00
|
|
|
int j = (calIndexes[ch][0] + i) % dataSize;
|
2023-10-18 18:33:29 -04:00
|
|
|
if( PileUp[ch][j] ) pileUpCount ++;
|
|
|
|
}
|
|
|
|
NonPileUpRate[ch] = (nEvent - pileUpCount)/sec;
|
2023-05-16 11:26:22 -04:00
|
|
|
|
2023-12-12 17:52:32 -05:00
|
|
|
//printf("%2d | %10llu %10llu, %.0f = %f sec, rate = %f, nEvent %d pileUp %d \n", ch, t1, t0, tick2ns, sec, nEvent / sec, nEvent, pileUpCount);
|
2023-10-18 18:33:29 -04:00
|
|
|
}
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-04-20 14:39:59 -04:00
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
//*=================================================
|
2023-12-12 15:35:47 -05:00
|
|
|
inline void Data::DecodeDualBlock(char * &buffer, unsigned int size, int DPPType, int chMask, bool fastDecode, int verbose){
|
|
|
|
this->buffer = buffer;
|
|
|
|
this->nByte = size;
|
|
|
|
|
|
|
|
nw = 0;
|
|
|
|
|
|
|
|
if( DPPType == DPPType::DPP_PHA_CODE ) {
|
|
|
|
DecodePHADualChannelBlock(chMask, fastDecode, verbose) ;
|
|
|
|
}
|
|
|
|
if( DPPType == DPPType::DPP_PSD_CODE ) {
|
|
|
|
DecodePSDDualChannelBlock(chMask, fastDecode, verbose) ;
|
|
|
|
}
|
|
|
|
if( DPPType == DPPType::DPP_QDC_CODE ) {
|
|
|
|
DecodeQDCGroupedChannelBlock(chMask, fastDecode, verbose) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
inline int Data::DecodePHADualChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose){
|
|
|
|
|
2023-05-16 17:21:40 -04:00
|
|
|
//printf("======= %s\n", __func__);
|
|
|
|
|
2023-12-12 15:35:47 -05:00
|
|
|
//nw = nw + 1;
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned int word = ReadBuffer(nw, verbose);
|
|
|
|
|
|
|
|
bool hasFormatInfo = ((word >> 31) & 0x1);
|
|
|
|
unsigned int aggSize = ( word & 0x7FFFFFFF ) ;
|
|
|
|
if( verbose >= 2 ) printf("Dual Channel size : %d \n", aggSize);
|
|
|
|
unsigned int nSample = 0; /// wave form;
|
|
|
|
unsigned int nEvents = 0;
|
|
|
|
unsigned int extra2Option = 0;
|
2023-10-10 11:06:03 -04:00
|
|
|
bool hasWaveForm = false;
|
2023-04-11 11:13:23 -04:00
|
|
|
bool hasExtra2 = false;
|
|
|
|
bool hasDualTrace = 0 ;
|
|
|
|
if( hasFormatInfo ){
|
|
|
|
nw = nw + 1; word = ReadBuffer(nw, verbose);
|
|
|
|
|
|
|
|
nSample = ( word & 0xFFFF ) * 8;
|
|
|
|
extra2Option = ( (word >> 24 ) & 0x7 );
|
|
|
|
hasExtra2 = ( (word >> 28 ) & 0x1 );
|
|
|
|
if( !fastDecode || verbose >= 2){
|
|
|
|
unsigned int digitalProbe = ( (word >> 16 ) & 0xF );
|
|
|
|
unsigned int analogProbe2 = ( (word >> 20 ) & 0x3 );
|
|
|
|
unsigned int analogProbe1 = ( (word >> 22 ) & 0x3 );
|
2023-10-11 18:28:19 -04:00
|
|
|
hasWaveForm = ( (word >> 27 ) & 0x1 );
|
2023-04-11 11:13:23 -04:00
|
|
|
bool hasTimeStamp = ( (word >> 29 ) & 0x1 );
|
|
|
|
bool hasEnergy = ( (word >> 30 ) & 0x1 );
|
|
|
|
hasDualTrace = ( (word >> 31 ) & 0x1 );
|
|
|
|
|
|
|
|
if( verbose >= 2 ) {
|
|
|
|
printf("DualTrace : %d, Energy : %d, Time: %d, Wave : %d, Extra2: %d \n",
|
|
|
|
hasDualTrace, hasEnergy, hasTimeStamp, hasWaveForm, hasExtra2);
|
|
|
|
}
|
|
|
|
if( verbose >= 3){
|
|
|
|
if( hasExtra2 ){
|
|
|
|
printf("...... extra 2 : ");
|
|
|
|
switch (extra2Option){
|
|
|
|
case 0: printf("[0:15] trapwzoid baseline * 4 [16:31] Extended timestamp (16-bit)\n"); break;
|
|
|
|
case 1: printf("Reserved\n"); break;
|
|
|
|
case 2: printf("[0:9] Fine time stamp [10:15] Reserved [16:31] Extended timestamp (16-bit)\n"); break;
|
|
|
|
case 3: printf("Reserved\n"); break;
|
|
|
|
case 4: printf("[0:15] Total trigger counter [16:31] Lost trigger counter\n"); break;
|
|
|
|
case 5: printf("[0:15] Event after Zero crossing [16:31] Event before Zero crossing\n"); break;
|
|
|
|
case 6: printf("Reserved\n"); break;
|
|
|
|
case 7: printf("Reserved\n"); break;
|
|
|
|
}
|
|
|
|
}
|
2023-12-11 18:55:12 -05:00
|
|
|
if( hasWaveForm ){
|
|
|
|
printf("...... Analog Probe 1 : ");
|
|
|
|
switch (analogProbe1 ){
|
|
|
|
case 0 : printf("Input \n"); break;
|
|
|
|
case 1 : printf("RC-CR (1st derivative) \n"); break;
|
|
|
|
case 2 : printf("RC-CR2 (2st derivative) \n"); break;
|
|
|
|
case 3 : printf("trapazoid \n"); break;
|
|
|
|
}
|
|
|
|
printf("...... Analog Probe 2 : ");
|
|
|
|
switch (analogProbe2 ){
|
|
|
|
case 0 : printf("Input \n"); break;
|
|
|
|
case 1 : printf("Theshold \n"); break;
|
|
|
|
case 2 : printf("trapezoid - baseline \n"); break;
|
|
|
|
case 3 : printf("baseline \n"); break;
|
|
|
|
}
|
|
|
|
printf("...... Digital Probe : ");
|
|
|
|
switch (digitalProbe ){
|
|
|
|
case 0 : printf("Peaking \n"); break;
|
|
|
|
case 1 : printf("Armed (trigger) \n"); break;
|
|
|
|
case 2 : printf("Peak Run \n"); break;
|
|
|
|
case 3 : printf("Pile up \n"); break;
|
|
|
|
case 4 : printf("Peaking \n"); break;
|
|
|
|
case 5 : printf("Trigger Validation Window \n"); break;
|
|
|
|
case 6 : printf("Baseline for energy calculation \n"); break;
|
|
|
|
case 7 : printf("Trigger holdoff \n"); break;
|
|
|
|
case 8 : printf("Trigger Validation \n"); break;
|
|
|
|
case 9 : printf("ACQ Busy \n"); break;
|
|
|
|
case 10 : printf("Trigger window \n"); break;
|
|
|
|
case 11 : printf("Ext. Trigger \n"); break;
|
|
|
|
case 12 : printf("Busy = memory is full \n"); break;
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nEvents = (aggSize - 2) / (nSample/2 + 2 + hasExtra2 );
|
2023-04-20 13:49:36 -04:00
|
|
|
if( verbose >= 2 ) printf("----------------- nEvents : %d, fast decode : %d\n", nEvents, fastDecode);
|
2023-04-11 11:13:23 -04:00
|
|
|
}else{
|
|
|
|
if( verbose >= 2 ) printf("does not has format info. unable to read buffer.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
///========== decode an event
|
2023-04-11 11:50:52 -04:00
|
|
|
for( unsigned int ev = 0; ev < nEvents ; ev++){
|
2023-04-11 11:13:23 -04:00
|
|
|
if( verbose >= 2 ) printf("------ event : %d\n", ev);
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
bool channelTag = ((word >> 31) & 0x1);
|
|
|
|
unsigned int timeStamp0 = (word & 0x7FFFFFFF);
|
|
|
|
int channel = ChannelMask*2 + channelTag;
|
|
|
|
if( verbose >= 2 ) printf("ch : %d, timeStamp0 %u \n", channel, timeStamp0);
|
|
|
|
|
|
|
|
///===== read waveform
|
2023-05-26 18:06:37 -04:00
|
|
|
if( !fastDecode ) {
|
2023-04-11 11:13:23 -04:00
|
|
|
tempWaveform1.clear();
|
|
|
|
tempWaveform2.clear();
|
|
|
|
tempDigiWaveform1.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int triggerAtSample = 0 ;
|
|
|
|
if( fastDecode ){
|
|
|
|
nw += nSample/2;
|
|
|
|
}else{
|
2023-10-10 11:06:03 -04:00
|
|
|
if( hasWaveForm ){
|
|
|
|
for( unsigned int wi = 0; wi < nSample/2; wi++){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose-2);
|
|
|
|
///The CAEN manual is wrong, the bit [31:16] is anaprobe 1
|
|
|
|
bool isTrigger1 = (( word >> 31 ) & 0x1 );
|
|
|
|
bool dp1 = (( word >> 30 ) & 0x1 );
|
|
|
|
unsigned short wave1 = (( word >> 16) & 0x3FFF);
|
|
|
|
short trace1 = 0;
|
|
|
|
if( wave1 & 0x2000){
|
|
|
|
trace1 = static_cast<short>(~wave1 + 1 + 0x3FFF);
|
|
|
|
trace1 = - trace1;
|
2023-04-11 11:13:23 -04:00
|
|
|
}else{
|
2023-10-10 11:06:03 -04:00
|
|
|
trace1 = static_cast<short>(wave1);
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-10-10 11:06:03 -04:00
|
|
|
|
|
|
|
///The CAEN manual is wrong, the bit [31:16] is anaprobe 2
|
|
|
|
bool isTrigger0 = (( word >> 15 ) & 0x1 );
|
|
|
|
bool dp0 = (( word >> 14 ) & 0x1 );
|
|
|
|
unsigned short wave0 = ( word & 0x3FFF);
|
|
|
|
short trace0 = 0;
|
|
|
|
if( wave0 & 0x2000){
|
|
|
|
trace0 = static_cast<short>(~wave0 + 1 + 0x3FFF);
|
|
|
|
trace0 = - trace0;
|
|
|
|
}else{
|
|
|
|
trace0 = static_cast<short>(wave0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( hasDualTrace ){
|
|
|
|
tempWaveform1.push_back(trace1);
|
|
|
|
tempWaveform2.push_back(trace0);
|
|
|
|
tempDigiWaveform1.push_back(dp1);
|
|
|
|
tempDigiWaveform2.push_back(dp0);
|
|
|
|
}else{
|
|
|
|
tempWaveform1.push_back(trace1);
|
|
|
|
tempWaveform1.push_back(trace0);
|
|
|
|
tempDigiWaveform1.push_back(dp1);
|
|
|
|
tempDigiWaveform1.push_back(dp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( isTrigger0 == 1 ) triggerAtSample = 2*wi ;
|
|
|
|
if( isTrigger1 == 1 ) triggerAtSample = 2*wi + 1;
|
|
|
|
|
|
|
|
if( verbose >= 4 ){
|
|
|
|
if( !hasDualTrace ){
|
|
|
|
printf("%4d| %5d, %d, %d \n", 2*wi, trace0, dp0, isTrigger0);
|
|
|
|
printf("%4d| %5d, %d, %d \n", 2*wi+1, trace1, dp1, isTrigger1);
|
|
|
|
}else{
|
|
|
|
printf("%4d| %5d, %5d | %d, %d | %d %d\n", wi, trace0, trace1, dp0, dp1, isTrigger0, isTrigger1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
unsigned long long extTimeStamp = 0;
|
|
|
|
unsigned int extra2 = 0;
|
|
|
|
if( hasExtra2 ){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
extra2 = word;
|
|
|
|
if( extra2Option == 0 || extra2Option == 2 ) extTimeStamp = (extra2 >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long long timeStamp = (extTimeStamp << 31) ;
|
|
|
|
timeStamp = timeStamp + timeStamp0;
|
|
|
|
|
|
|
|
if( verbose >= 2 && hasExtra2 ) printf("extra2 : 0x%0X, TimeStamp : %llu\n", extra2, timeStamp);
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int extra = (( word >> 16) & 0x3FF);
|
|
|
|
unsigned int energy = (word & 0x7FFF);
|
|
|
|
bool rollOver = (extra & 0x002);
|
|
|
|
bool pileUp = (extra & 0x200);
|
|
|
|
bool pileUpOrRollOver = ((word >> 15) & 0x1);
|
|
|
|
|
|
|
|
if( verbose >= 3 ) {
|
2023-04-11 11:50:52 -04:00
|
|
|
printf("PileUp or RollOver : %d\n", pileUpOrRollOver);
|
2023-04-11 11:13:23 -04:00
|
|
|
printf("PileUp : %d , extra : 0x%03x, energy : %d \n", pileUp, extra, energy);
|
|
|
|
printf(" lost event : %d \n", ((extra >> 0) & 0x1) );
|
2023-05-16 11:26:22 -04:00
|
|
|
printf(" roll-over : %d (is fake event ?)\n", ((extra >> 1) & 0x1) );
|
2023-04-11 11:13:23 -04:00
|
|
|
printf(" fake-event : %d \n", ((extra >> 3) & 0x1) );
|
|
|
|
printf(" input sat. : %d \n", ((extra >> 4) & 0x1) );
|
|
|
|
printf(" lost trg : %d \n", ((extra >> 5) & 0x1) );
|
|
|
|
printf(" tot trg : %d \n", ((extra >> 6) & 0x1) );
|
|
|
|
printf(" coincident : %d \n", ((extra >> 7) & 0x1) );
|
|
|
|
printf(" not coin. : %d \n", ((extra >> 8) & 0x1) );
|
|
|
|
printf(" pile-up : %d \n", ((extra >> 9) & 0x1) );
|
|
|
|
printf(" trapezoid sat. : %d \n", ((extra >> 10) & 0x1) );
|
|
|
|
}
|
|
|
|
|
2023-04-19 16:21:14 -04:00
|
|
|
|
|
|
|
if( rollOver == 0 ) { // non-time roll over fake event
|
2023-05-25 18:50:42 -04:00
|
|
|
DataIndex[channel] ++;
|
2024-01-18 23:09:50 -05:00
|
|
|
if( DataIndex[channel] >= dataSize ) {
|
2023-05-25 18:50:42 -04:00
|
|
|
LoopIndex[channel] ++;
|
|
|
|
DataIndex[channel] = 0;
|
|
|
|
}
|
2023-05-16 12:04:18 -04:00
|
|
|
|
2023-05-25 18:50:42 -04:00
|
|
|
Energy[channel][DataIndex[channel]] = energy;
|
2024-01-11 11:52:40 -05:00
|
|
|
Timestamp[channel][DataIndex[channel]] = timeStamp * tick2ns;
|
2023-06-23 13:50:21 -04:00
|
|
|
if(extra2Option == 2 ) fineTime[channel][DataIndex[channel]] = (extra2 & 0x03FF );
|
2023-05-25 18:50:42 -04:00
|
|
|
PileUp[channel][DataIndex[channel]] = pileUp;
|
2023-04-11 11:13:23 -04:00
|
|
|
NumEventsDecoded[channel] ++;
|
2023-04-19 16:21:14 -04:00
|
|
|
|
|
|
|
if( !pileUp ) {
|
|
|
|
NumNonPileUpDecoded[channel] ++;
|
2023-10-04 13:13:38 -04:00
|
|
|
TotNumNonPileUpEvents[channel] ++;
|
2023-04-19 16:21:14 -04:00
|
|
|
}
|
2023-05-16 12:04:18 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
if( !fastDecode && hasWaveForm) {
|
2023-05-16 12:04:18 -04:00
|
|
|
if( hasDualTrace ){
|
2023-05-25 18:50:42 -04:00
|
|
|
Waveform1[channel][DataIndex[channel]] = tempWaveform1;
|
|
|
|
Waveform2[channel][DataIndex[channel]] = tempWaveform2;
|
2023-05-16 12:04:18 -04:00
|
|
|
}else{
|
2023-05-25 18:50:42 -04:00
|
|
|
Waveform1[channel][DataIndex[channel]] = tempWaveform1;
|
2023-05-16 12:04:18 -04:00
|
|
|
}
|
2023-05-25 18:50:42 -04:00
|
|
|
DigiWaveform1[channel][DataIndex[channel]] = tempDigiWaveform1;
|
2023-05-16 12:04:18 -04:00
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-04-19 16:21:14 -04:00
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
//if( DataIndex[channel] > dataSize ) ClearData(); // if any channel has more data then dataSize, clear all stored data
|
2023-05-16 12:04:18 -04:00
|
|
|
|
2024-01-12 16:59:55 -05:00
|
|
|
if( verbose >= 1 ) printf("evt %4d(%2d) | ch : %2d, PileUp : %d , energy : %5d, rollOver: %d, timestamp : %16llu (%10llu), triggerAt : %d, nSample : %d, %f sec\n",
|
|
|
|
DataIndex[channel], LoopIndex[channel], channel, pileUp, energy, rollOver, timeStamp * tick2ns, timeStamp, triggerAtSample, nSample , timeStamp * 4. / 1e9);
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///=========== Key information
|
|
|
|
/// ch, energy, timestamp
|
|
|
|
/// trace
|
|
|
|
|
|
|
|
return nw;
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:26:22 -04:00
|
|
|
//*=================================================
|
2023-04-11 11:13:23 -04:00
|
|
|
inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose){
|
|
|
|
|
2023-05-16 17:21:40 -04:00
|
|
|
//printf("======= %s\n", __func__);
|
|
|
|
|
2023-12-12 15:35:47 -05:00
|
|
|
//nw = nw + 1;
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned int word = ReadBuffer(nw, verbose);
|
|
|
|
|
|
|
|
if( (word >> 31) != 1 ) return 0;
|
|
|
|
|
|
|
|
unsigned int aggSize = ( word & 0x3FFFFF ) ;
|
|
|
|
if( verbose >= 2 ) printf(" size : %d \n", aggSize);
|
|
|
|
|
|
|
|
unsigned int nEvents = 0;
|
|
|
|
nw = nw + 1; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int nSample = ( word & 0xFFFF ) * 8;
|
|
|
|
unsigned int digitalProbe1 = ( (word >> 16 ) & 0x7 );
|
|
|
|
unsigned int digitalProbe2 = ( (word >> 19 ) & 0x7 );
|
|
|
|
unsigned int analogProbe = ( (word >> 22 ) & 0x3 );
|
|
|
|
unsigned int extraOption = ( (word >> 24 ) & 0x7 );
|
|
|
|
bool hasWaveForm = ( (word >> 27 ) & 0x1 );
|
|
|
|
bool hasExtra = ( (word >> 28 ) & 0x1 );
|
|
|
|
bool hasTimeStamp = ( (word >> 29 ) & 0x1 );
|
|
|
|
bool hasCharge = ( (word >> 30 ) & 0x1 );
|
|
|
|
bool hasDualTrace = ( (word >> 31 ) & 0x1 );
|
|
|
|
|
|
|
|
if( verbose >= 2 ) {
|
|
|
|
printf("dualTrace : %d, Charge : %d, Time: %d, Wave : %d, Extra: %d\n",
|
|
|
|
hasDualTrace, hasCharge, hasTimeStamp, hasWaveForm, hasExtra);
|
|
|
|
if( hasExtra ){
|
|
|
|
printf(".... extra : ");
|
|
|
|
switch(extraOption){
|
2023-12-11 18:55:12 -05:00
|
|
|
case 0: printf("[0:15] baseline * 4 [16:31] Extended timestamp (16-bit)\n"); break;
|
2023-04-11 11:13:23 -04:00
|
|
|
case 1: printf("[0:11] reserved [12] lost trigger counted [13] 1024 trigger counted [14] Over-range\n");
|
|
|
|
printf("[15] trigger lost [16:31] Extended timestamp (16-bit)\n"); break;
|
|
|
|
case 2: printf("[0:9] Fine time stamp [10:15] flag [10:15] Reserved [16:31] Extended timestamp (16-bit)\n"); break;
|
|
|
|
case 3: printf("Reserved\n"); break;
|
|
|
|
case 4: printf("[0:15] Total trigger counter [16:31] Lost trigger counter\n"); break;
|
|
|
|
case 5: printf("[0:15] Event after Zero crossing [16:31] Event before Zero crossing\n"); break;
|
|
|
|
case 6: printf("Reserved\n"); break;
|
|
|
|
case 7: printf("debug, must be 0x12345678\n"); break;
|
|
|
|
}
|
|
|
|
}
|
2023-12-11 18:55:12 -05:00
|
|
|
if( hasWaveForm ){
|
|
|
|
printf(".... digital Probe 1 : ");
|
|
|
|
switch(digitalProbe1){
|
|
|
|
case 0 : printf("Long gate \n"); break;
|
|
|
|
case 1 : printf("Over threshold \n"); break;
|
|
|
|
case 2 : printf("Shaped TRG \n"); break;
|
|
|
|
case 3 : printf("TRG Val. Acceptance \n"); break;
|
|
|
|
case 4 : printf("Pile-Up \n"); break;
|
|
|
|
case 5 : printf("Coincidence \n"); break;
|
|
|
|
case 6 : printf("Reserved \n"); break;
|
|
|
|
case 7 : printf("Trigger \n"); break;
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-12-11 18:55:12 -05:00
|
|
|
printf(".... digital Probe 2 : ");
|
|
|
|
switch(digitalProbe2){
|
|
|
|
case 0 : printf("Short gate \n"); break;
|
|
|
|
case 1 : printf("Over threshold \n"); break;
|
|
|
|
case 2 : printf("TRG Validation \n"); break;
|
|
|
|
case 3 : printf("TRG HoldOff \n"); break;
|
|
|
|
case 4 : printf("Pile-Up \n"); break;
|
|
|
|
case 5 : printf("Coincidence \n"); break;
|
|
|
|
case 6 : printf("Reserved \n"); break;
|
|
|
|
case 7 : printf("Trigger \n"); break;
|
|
|
|
}
|
|
|
|
printf(".... analog Probe (dual trace : %d): ", hasDualTrace);
|
|
|
|
if( hasDualTrace ) {
|
|
|
|
switch(analogProbe){
|
|
|
|
case 0 : printf("Input and baseline \n"); break;
|
|
|
|
case 1 : printf("CFD and baseline \n"); break;
|
|
|
|
case 2 : printf("Input and CFD \n"); break;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
switch(analogProbe){
|
|
|
|
case 0 : printf("Input \n"); break;
|
|
|
|
case 1 : printf("CFD \n"); break;
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
2023-12-11 18:55:12 -05:00
|
|
|
|
|
|
|
if( !hasExtra && !hasWaveForm) printf("\n");
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
nEvents = (aggSize -2) / (nSample/2 + 2 + hasExtra );
|
2023-04-20 13:49:36 -04:00
|
|
|
if( verbose >= 2 ) printf("----------------- nEvents : %d, fast decode : %d\n", nEvents, fastDecode);
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
///========= Decode an event
|
2023-04-11 11:50:52 -04:00
|
|
|
for( unsigned int ev = 0; ev < nEvents ; ev++){
|
2023-04-11 11:13:23 -04:00
|
|
|
if( verbose >= 2 ) printf("--------------------------- event : %d\n", ev);
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
bool channelTag = ((word >> 31) & 0x1);
|
|
|
|
unsigned int timeStamp0 = (word & 0x7FFFFFFF);
|
|
|
|
int channel = ChannelMask*2 + channelTag;
|
|
|
|
if( verbose >= 2 ) printf("ch : %d, timeStamp %u \n", channel, timeStamp0);
|
|
|
|
|
|
|
|
///===== read waveform
|
2023-05-26 18:06:37 -04:00
|
|
|
if( !fastDecode ) {
|
2023-04-11 11:13:23 -04:00
|
|
|
tempWaveform1.clear();
|
|
|
|
tempWaveform2.clear();
|
|
|
|
tempDigiWaveform1.clear();
|
|
|
|
tempDigiWaveform2.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fastDecode ){
|
|
|
|
nw += nSample/2;
|
|
|
|
}else{
|
2023-10-10 11:06:03 -04:00
|
|
|
if( hasWaveForm ){
|
|
|
|
for( unsigned int wi = 0; wi < nSample/2; wi++){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose-4);
|
|
|
|
bool dp2b = (( word >> 31 ) & 0x1 );
|
|
|
|
bool dp1b = (( word >> 30 ) & 0x1 );
|
|
|
|
unsigned short waveb = (( word >> 16) & 0x3FFF);
|
|
|
|
|
|
|
|
bool dp2a = (( word >> 15 ) & 0x1 );
|
|
|
|
bool dp1a = (( word >> 14 ) & 0x1 );
|
|
|
|
unsigned short wavea = ( word & 0x3FFF);
|
|
|
|
|
|
|
|
if( hasDualTrace ){
|
|
|
|
tempWaveform1.push_back(wavea);
|
|
|
|
tempWaveform2.push_back(waveb);
|
|
|
|
}else{
|
|
|
|
tempWaveform1.push_back(wavea);
|
|
|
|
tempWaveform1.push_back(waveb);
|
|
|
|
}
|
|
|
|
tempDigiWaveform1.push_back(dp1a);
|
|
|
|
tempDigiWaveform1.push_back(dp1b);
|
|
|
|
tempDigiWaveform2.push_back(dp2a);
|
|
|
|
tempDigiWaveform2.push_back(dp2b);
|
|
|
|
|
|
|
|
if( verbose >= 3 ){
|
|
|
|
printf("%4d| %5d, %d, %d \n", 2*wi, wavea, dp1a, dp2a);
|
|
|
|
printf("%4d| %5d, %d, %d \n", 2*wi+1, waveb, dp1b, dp2b);
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-06 16:50:28 -04:00
|
|
|
|
|
|
|
unsigned int extra = 0;
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned long long extTimeStamp = 0;
|
2023-10-06 16:50:28 -04:00
|
|
|
|
|
|
|
if( hasExtra ){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
2023-12-11 18:55:12 -05:00
|
|
|
if( verbose > 2 ) printf("extra \n");
|
2023-10-06 16:50:28 -04:00
|
|
|
extra = word;
|
|
|
|
extTimeStamp = 0;
|
|
|
|
if( extraOption == 0 || extraOption == 2 ) extTimeStamp = (extra >> 16);
|
|
|
|
}
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
unsigned long long timeStamp = (extTimeStamp << 31) ;
|
|
|
|
timeStamp = timeStamp + timeStamp0;
|
|
|
|
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int Qlong = (( word >> 16) & 0xFFFF);
|
2023-10-04 13:13:38 -04:00
|
|
|
bool pileup = ((word >> 15) & 0x1);
|
2023-04-11 11:13:23 -04:00
|
|
|
unsigned int Qshort = (word & 0x7FFF);
|
2023-05-16 17:21:40 -04:00
|
|
|
bool isEnergyCorrect = ((word >> 15) & 0x1); // the PUR, either pileup or saturated
|
2023-04-11 11:13:23 -04:00
|
|
|
|
2023-05-16 17:21:40 -04:00
|
|
|
if( isEnergyCorrect == 0 ) {
|
2023-05-25 18:50:42 -04:00
|
|
|
DataIndex[channel] ++;
|
2024-01-18 23:09:50 -05:00
|
|
|
if( DataIndex[channel] >= dataSize ) {
|
2023-05-25 18:50:42 -04:00
|
|
|
LoopIndex[channel] ++;
|
|
|
|
DataIndex[channel] = 0;
|
|
|
|
}
|
2023-05-16 12:04:18 -04:00
|
|
|
|
2023-10-06 16:50:28 -04:00
|
|
|
Energy2[channel][DataIndex[channel]] = Qshort;
|
|
|
|
Energy[channel][DataIndex[channel]] = Qlong;
|
2024-01-11 11:52:40 -05:00
|
|
|
Timestamp[channel][DataIndex[channel]] = timeStamp * tick2ns;
|
2023-10-06 16:50:28 -04:00
|
|
|
if( extraOption == 2 ) fineTime[channel][DataIndex[channel]] = extra & 0x3FF;
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
NumEventsDecoded[channel] ++;
|
2023-10-04 13:13:38 -04:00
|
|
|
if( !pileup){
|
|
|
|
NumNonPileUpDecoded[channel] ++;
|
|
|
|
TotNumNonPileUpEvents[channel] ++;
|
|
|
|
}
|
2023-05-16 12:04:18 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
if( !fastDecode && hasWaveForm) {
|
2023-05-16 12:04:18 -04:00
|
|
|
if( hasDualTrace ){
|
2023-05-25 18:50:42 -04:00
|
|
|
Waveform1[channel][DataIndex[channel]] = tempWaveform1;
|
|
|
|
Waveform2[channel][DataIndex[channel]] = tempWaveform2;
|
2023-05-16 12:04:18 -04:00
|
|
|
}else{
|
2023-05-25 18:50:42 -04:00
|
|
|
Waveform1[channel][DataIndex[channel]] = tempWaveform1;
|
2023-05-16 12:04:18 -04:00
|
|
|
}
|
2023-05-25 18:50:42 -04:00
|
|
|
DigiWaveform1[channel][DataIndex[channel]] = tempDigiWaveform1;
|
|
|
|
DigiWaveform2[channel][DataIndex[channel]] = tempDigiWaveform2;
|
2023-05-16 17:21:40 -04:00
|
|
|
|
2023-05-16 12:04:18 -04:00
|
|
|
}
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
}
|
2023-04-19 16:21:14 -04:00
|
|
|
|
2024-01-18 23:09:50 -05:00
|
|
|
//if( DataIndex[channel] >= dataSize ) ClearData();
|
2023-04-19 16:21:14 -04:00
|
|
|
|
2023-12-11 18:55:12 -05:00
|
|
|
//if( verbose >= 2 ) printf("extra : 0x%08x, Qshort : %d, Qlong : %d \n", extra, Qshort, Qlong);
|
|
|
|
if( verbose == 1 ) printf("ch : %2d, Qshort : %6d, Qlong : %6d, timestamp : %llu\n",
|
2024-01-12 16:59:55 -05:00
|
|
|
channel, Qshort, Qlong, timeStamp * tick2ns);
|
2023-12-11 18:55:12 -05:00
|
|
|
if( verbose >= 2 ) printf("Qshort : %6d, Qlong : %6d, timestamp : %llu\n",
|
2024-01-12 16:59:55 -05:00
|
|
|
Qshort, Qlong, timeStamp * tick2ns);
|
2023-12-11 18:55:12 -05:00
|
|
|
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///=========== Key information
|
|
|
|
/// ch, Qshort, Qlong , timestamp
|
|
|
|
/// trace
|
|
|
|
|
|
|
|
return nw;
|
|
|
|
}
|
|
|
|
|
2023-10-06 16:50:28 -04:00
|
|
|
//*=================================================
|
|
|
|
inline int Data::DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose){
|
|
|
|
|
2023-12-12 15:35:47 -05:00
|
|
|
//nw = nw + 1;
|
2023-10-06 16:50:28 -04:00
|
|
|
unsigned int word = ReadBuffer(nw, verbose);
|
|
|
|
|
|
|
|
if( (word >> 31) != 1 ) return 0;
|
|
|
|
|
|
|
|
unsigned int aggSize = ( word & 0x3FFFFF ) ;
|
2023-10-10 11:06:03 -04:00
|
|
|
if( verbose >= 2 ) printf(" Group agg. size : %d words\n", aggSize);
|
2023-10-06 16:50:28 -04:00
|
|
|
|
|
|
|
unsigned int nEvents = 0;
|
|
|
|
nw = nw + 1; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int nSample = ( word & 0xFFFF ) * 8;
|
|
|
|
unsigned int analogProbe = ( (word >> 22 ) & 0x3 );
|
|
|
|
bool hasWaveForm = ( (word >> 27 ) & 0x1 );
|
|
|
|
bool hasExtra = ( (word >> 28 ) & 0x1 );
|
|
|
|
bool hasTimeStamp = ( (word >> 29 ) & 0x1 );
|
|
|
|
bool hasEnergy = ( (word >> 30 ) & 0x1 );
|
2023-10-10 11:06:03 -04:00
|
|
|
if( (word >> 31 ) != 0 ) return 0;
|
2023-10-06 16:50:28 -04:00
|
|
|
|
|
|
|
if( verbose >= 2 ) {
|
|
|
|
printf("Charge : %d, Time: %d, Wave : %d, Extra: %d\n", hasEnergy, hasTimeStamp, hasWaveForm, hasExtra);
|
2023-12-11 18:55:12 -05:00
|
|
|
if( hasWaveForm ){
|
|
|
|
printf(".... analog Probe (%d): ", analogProbe);
|
2023-10-06 16:50:28 -04:00
|
|
|
switch(analogProbe){
|
|
|
|
case 0 : printf("Input\n"); break;
|
|
|
|
case 1 : printf("Smoothed Input\n"); break;
|
|
|
|
case 2 : printf("Baseline\n"); break;
|
|
|
|
}
|
2023-12-11 18:55:12 -05:00
|
|
|
}
|
2023-10-06 16:50:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
nEvents = (aggSize -2) / (nSample/2 + 2 + hasExtra );
|
|
|
|
if( verbose >= 2 ) printf("----------------- nEvents : %d, fast decode : %d\n", nEvents, fastDecode);
|
|
|
|
|
|
|
|
///========= Decode an event
|
|
|
|
for( unsigned int ev = 0; ev < nEvents ; ev++){
|
|
|
|
if( verbose >= 2 ) printf("--------------------------- event : %d\n", ev);
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
unsigned int timeStamp0 = (word & 0xFFFFFFFF);
|
|
|
|
if( verbose >= 2 ) printf("timeStamp %u \n", timeStamp0);
|
|
|
|
|
|
|
|
///===== read waveform
|
2023-10-10 11:06:03 -04:00
|
|
|
if( !fastDecode && hasWaveForm ) {
|
2023-10-06 16:50:28 -04:00
|
|
|
tempWaveform1.clear();
|
|
|
|
tempDigiWaveform1.clear();
|
|
|
|
tempDigiWaveform2.clear();
|
|
|
|
tempDigiWaveform3.clear();
|
|
|
|
tempDigiWaveform4.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fastDecode ){
|
|
|
|
nw += nSample/2;
|
|
|
|
}else{
|
2023-10-10 11:06:03 -04:00
|
|
|
if( hasWaveForm ){
|
|
|
|
for( unsigned int wi = 0; wi < nSample/2; wi++){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose-4);
|
2023-10-06 16:50:28 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
tempWaveform1.push_back(( word & 0xFFF));
|
|
|
|
tempWaveform1.push_back((( word >> 16) & 0xFFF));
|
2023-10-06 16:50:28 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
tempDigiWaveform1.push_back((( word >> 12 ) & 0x1 )); //Gate
|
|
|
|
tempDigiWaveform1.push_back((( word >> 28 ) & 0x1 ));
|
2023-10-06 16:50:28 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
tempDigiWaveform2.push_back((( word >> 13 ) & 0x1 )); //Trigger
|
|
|
|
tempDigiWaveform2.push_back((( word >> 29 ) & 0x1 ));
|
2023-10-06 16:50:28 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
tempDigiWaveform3.push_back((( word >> 14 ) & 0x1 )); //Triger Hold Off
|
|
|
|
tempDigiWaveform3.push_back((( word >> 30 ) & 0x1 ));
|
|
|
|
|
|
|
|
tempDigiWaveform4.push_back((( word >> 15 ) & 0x1 )); //Over-Threshold
|
|
|
|
tempDigiWaveform4.push_back((( word >> 31 ) & 0x1 ));
|
2023-10-06 16:50:28 -04:00
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
if( verbose >= 3 ){
|
|
|
|
printf("%4d| %5d, %d, %d, %d, %d \n", 2*wi, (word & 0xFFF) , (( word >> 12 ) & 0x1 ), (( word >> 13 ) & 0x1 ), (( word >> 14 ) & 0x1 ), (( word >> 15 ) & 0x1 ));
|
2023-10-13 18:02:19 -04:00
|
|
|
printf("%-22s", "");
|
2023-10-10 11:06:03 -04:00
|
|
|
printf("%4d| %5d, %d, %d, %d, %d \n", 2*wi+1, (( word >> 16) & 0xFFF), (( word >> 28 ) & 0x1 ), (( word >> 29 ) & 0x1 ), (( word >> 30 ) & 0x1 ), (( word >> 31 ) & 0x1 ));
|
|
|
|
}
|
2023-10-06 16:50:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long long extTimeStamp = 0;
|
|
|
|
unsigned int baseline = 0;
|
|
|
|
unsigned long extra = 0;
|
|
|
|
if( hasExtra ){
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
|
|
|
extra = word;
|
2023-10-18 18:33:29 -04:00
|
|
|
extTimeStamp = (word & 0xFFF);
|
|
|
|
baseline = (word >> 16) / 16;
|
2023-10-10 11:06:03 -04:00
|
|
|
if( verbose >= 2 ) printf("extra : 0x%lx, baseline : %d\n", extra, baseline);
|
2023-10-06 16:50:28 -04:00
|
|
|
}
|
|
|
|
|
2023-10-18 18:33:29 -04:00
|
|
|
unsigned long long timeStamp = (extTimeStamp << 32) ;
|
2023-10-06 16:50:28 -04:00
|
|
|
timeStamp = timeStamp + timeStamp0;
|
|
|
|
|
|
|
|
nw = nw +1 ; word = ReadBuffer(nw, verbose);
|
2023-10-10 11:06:03 -04:00
|
|
|
unsigned int energy = ( word & 0xFFFF);
|
2023-10-06 16:50:28 -04:00
|
|
|
bool pileup = ((word >> 27) & 0x1);
|
|
|
|
bool OverRange = ((word >> 26)& 0x1);
|
|
|
|
unsigned short subCh = ((word >> 28)& 0xF);
|
|
|
|
|
|
|
|
unsigned short channel = ChannelMask*8 + subCh;
|
|
|
|
|
|
|
|
DataIndex[channel] ++;
|
2024-01-18 23:09:50 -05:00
|
|
|
if( DataIndex[channel] >= dataSize ) {
|
2023-10-06 16:50:28 -04:00
|
|
|
LoopIndex[channel] ++;
|
|
|
|
DataIndex[channel] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Energy[channel][DataIndex[channel]] = energy;
|
2024-01-11 11:52:40 -05:00
|
|
|
Timestamp[channel][DataIndex[channel]] = timeStamp * tick2ns;
|
2023-10-06 16:50:28 -04:00
|
|
|
|
|
|
|
NumEventsDecoded[channel] ++;
|
|
|
|
if( !pileup && !OverRange){
|
|
|
|
NumNonPileUpDecoded[channel] ++;
|
|
|
|
TotNumNonPileUpEvents[channel] ++;
|
|
|
|
}
|
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
if( !fastDecode && hasWaveForm) {
|
2023-10-06 16:50:28 -04:00
|
|
|
Waveform1[channel][DataIndex[channel]] = tempWaveform1;
|
|
|
|
DigiWaveform1[channel][DataIndex[channel]] = tempDigiWaveform1;
|
|
|
|
DigiWaveform2[channel][DataIndex[channel]] = tempDigiWaveform2;
|
|
|
|
DigiWaveform3[channel][DataIndex[channel]] = tempDigiWaveform3;
|
|
|
|
DigiWaveform4[channel][DataIndex[channel]] = tempDigiWaveform4;
|
|
|
|
}
|
|
|
|
|
2024-01-12 16:59:55 -05:00
|
|
|
if( verbose == 1 ) printf("ch : %2d, energy : %d, timestamp : %llu\n", channel, energy, timeStamp * tick2ns);
|
|
|
|
if( verbose > 1 ) printf("ch : %2d, energy : %d, timestamp : %llu, pileUp : %d, OverRange : %d\n", channel, energy, timeStamp * tick2ns, pileup, OverRange);
|
2023-10-10 11:06:03 -04:00
|
|
|
|
|
|
|
if( verbose == 1) printf("Decoded : %d, total : %ld \n", NumEventsDecoded[channel], TotNumNonPileUpEvents[channel]);
|
2023-10-06 16:50:28 -04:00
|
|
|
}
|
|
|
|
|
2023-10-10 11:06:03 -04:00
|
|
|
|
2023-10-06 16:50:28 -04:00
|
|
|
return nw;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-11 11:13:23 -04:00
|
|
|
#endif
|