From 27120a5c9a0f56d0d700376a43211593f8a11f93 Mon Sep 17 00:00:00 2001 From: "Ryan@WorkStation" Date: Wed, 18 Jan 2023 18:10:31 -0500 Subject: [PATCH] use CAEN_FElib_Stop for stop ReadData, added influxDB --- .vscode/settings.json | 12 +++- ClassDigitizer2Gen.cpp | 22 ++++--- ClassDigitizer2Gen.h | 3 + Makefile | 8 ++- influxdb.cpp | 138 +++++++++++++++++++++++++++++++++++++++++ influxdb.h | 52 ++++++++++++++++ script.C | 1 + test.cpp | 126 ++++++++++++++++++++++++++----------- 8 files changed, 315 insertions(+), 47 deletions(-) create mode 100644 influxdb.cpp create mode 100644 influxdb.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c4450a..c6418fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -45,6 +45,16 @@ "streambuf": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "script.C": "cpp" + "script.C": "cpp", + "ctime": "cpp", + "chrono": "cpp", + "condition_variable": "cpp", + "ratio": "cpp", + "iostream": "cpp", + "istream": "cpp", + "mutex": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "thread": "cpp" } } \ No newline at end of file diff --git a/ClassDigitizer2Gen.cpp b/ClassDigitizer2Gen.cpp index 0f60c27..bc8241f 100644 --- a/ClassDigitizer2Gen.cpp +++ b/ClassDigitizer2Gen.cpp @@ -38,6 +38,8 @@ void Digitizer2Gen::Initialization(){ evt = NULL; + acqON = false; + } //########################################### Handles functions @@ -179,12 +181,15 @@ void Digitizer2Gen::StartACQ(){ SendCommand("/cmd/armacquisition"); // this will also clear data SendCommand("/cmd/swstartacquisition"); + acqON = true; } void Digitizer2Gen::StopACQ(){ - SendCommand("/cmd/disarmacquisition"); + SendCommand("/cmd/SwStopAcquisition"); + //SendCommand("/cmd/disarmacquisition"); + acqON = false; } void Digitizer2Gen::SetPHADataFormat(unsigned short dataFormat){ @@ -314,9 +319,9 @@ void Digitizer2Gen::SetPHADataFormat(unsigned short dataFormat){ ret = CAEN_FELib_GetHandle(handle, "/endpoint/dpppha/stats", &stat_handle); ret |= CAEN_FELib_SetReadDataFormat(stat_handle, " [ \ - { \"name\": \"REAL_TIME\", \"type\": \"U64\", \"dim\": 1 }, \ - { \"name\": \"DEAD_TIME\", \"type\": \"U64\", \"dim\": 1 }, \ - { \"name\": \"LIVE_TIME\", \"type\": \"U64\", \"dim\": 1 }, \ + { \"name\": \"REAL_TIME_NS\", \"type\": \"U64\", \"dim\": 1 }, \ + { \"name\": \"DEAD_TIME_NS\", \"type\": \"U64\", \"dim\": 1 }, \ + { \"name\": \"LIVE_TIME_NS\", \"type\": \"U64\", \"dim\": 1 }, \ { \"name\": \"TRIGGER_CNT\", \"type\": \"U32\", \"dim\": 1 }, \ { \"name\": \"SAVED_EVENT_CNT\", \"type\": \"U32\", \"dim\": 1 } \ ]" @@ -345,10 +350,11 @@ int Digitizer2Gen::ReadStat(){ } void Digitizer2Gen::PrintStat(){ - printf("ch | Real Time | Dead Time | Live Time | Trigger | Saved \n"); + printf("ch | Real Time[ns] | Dead Time[ns] | Live Time[ns] | Trigger | Saved | Rate[Hz] \n"); for( int i = 0; i < MaxNumberOfChannel; i++){ - printf("%02d | %9lu | %9lu | %9lu | %7u | %7u \n", - i, realTime[i], deadTime[i], liveTime[i], triggerCount[i], savedEventCount[i]); + if( triggerCount[i] == 0 ) continue; + printf("%02d | %13lu | %13lu | %13lu | %7u | %7u | %.3f\n", + i, realTime[i], deadTime[i], liveTime[i], triggerCount[i], savedEventCount[i], triggerCount[i]*1e9*1.0/realTime[i]); } } @@ -530,7 +536,7 @@ void Digitizer2Gen::ProgramPHA(bool testPulse){ WriteValue("/par/SyncOutMode", "Disabled"); WriteValue("/par/RunDelay", "0"); // ns, that is for sync time with multi board WriteValue("/par/IOlevel", "NIM"); - WriteValue("/par/EnStatEvents", "1"); + WriteValue("/par/EnStatEvents", "true"); // Channel setting //WriteValue("/ch/0..63/par/EventTriggerSource", "GlobalTriggerSource"); diff --git a/ClassDigitizer2Gen.h b/ClassDigitizer2Gen.h index 01234b9..82f32e2 100644 --- a/ClassDigitizer2Gen.h +++ b/ClassDigitizer2Gen.h @@ -54,6 +54,8 @@ class Digitizer2Gen { char outFileName[100]; FILE * outFile; unsigned int outFileSize; + + bool acqON; public: Digitizer2Gen(); @@ -74,6 +76,7 @@ class Digitizer2Gen { void StartACQ(); void StopACQ(); + bool IsAcqOn() {return acqON;} void SetPHADataFormat(unsigned short dataFormat); // 0 = all data, // 1 = analog trace-0 only + flags diff --git a/Makefile b/Makefile index 396a67b..af00a0a 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,16 @@ CC = g++ COPTS = -fPIC -DLINUX -O2 -std=c++17 -lpthread CAENLIBS = -lCAEN_FELib -all: test test_indep ClassDigitizer2Gen.o +all: test test_indep ClassDigitizer2Gen.o influxdb.o test_indep : test_indep.cpp $(CC) $(COPTS) -o test_indep test_indep.cpp $(CAENLIBS) -test : test.cpp ClassDigitizer2Gen.o - $(CC) $(COPTS) -o test test.cpp ClassDigitizer2Gen.o $(CAENLIBS) +test : test.cpp ClassDigitizer2Gen.o influxdb.o + $(CC) $(COPTS) ClassDigitizer2Gen.o influxdb.o -o test test.cpp $(CAENLIBS) -lcurl ClassDigitizer2Gen.o : ClassDigitizer2Gen.cpp ClassDigitizer2Gen.h Event.h $(CC) $(COPTS) -c ClassDigitizer2Gen.cpp $(CAENLIBS) +influxdb.o : influxdb.cpp influxdb.h + $(CC) $(COPTS) -c influxdb.cpp -lcurl diff --git a/influxdb.cpp b/influxdb.cpp new file mode 100644 index 0000000..2c71345 --- /dev/null +++ b/influxdb.cpp @@ -0,0 +1,138 @@ +#include "influxdb.h" + + +InfluxDB::InfluxDB(std::string url, bool verbose){ + + curl = curl_easy_init(); + if( verbose) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + this->databaseIP = url; + respondCode = 0; + dataPoints = ""; +} + +InfluxDB::~InfluxDB(){ + + curl_easy_cleanup(curl); +} + +void InfluxDB::SetURL(std::string url){ + this->databaseIP = url; +} + +std::string InfluxDB::ShowDatabases(){ + 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(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()); + + 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(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(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){ + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "write?db=" + databaseName).c_str()); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(dataPoints.length())); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataPoints.c_str()); + Execute(); +} + + +void InfluxDB::Execute(){ + respond = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode); + //printf("==== respond code %ld \n", respondCode); + if( respond != CURLE_OK) printf("############# fail\n"); +} + +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; +} diff --git a/influxdb.h b/influxdb.h new file mode 100644 index 0000000..310e642 --- /dev/null +++ b/influxdb.h @@ -0,0 +1,52 @@ +#ifndef INFLUXDB_H +#define INFLUXDB_H + +#include +#include +#include +#include +#include + +class InfluxDB{ + private: + + CURL * curl; + CURLcode respond; + long respondCode; + + std::string databaseIP; + std::string dataPoints; + + std::vector databaseList; + + static size_t WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp); + + void Execute(); + + public: + /// url = https://fsunuc.physics.fsu.edu/InfluxDB/ + InfluxDB(std::string url, bool verbose = false); + ~InfluxDB(); + + void SetURL(std::string url); + + /// Query + std::string ShowDatabases(); /// this save the list of database into databaseList + std::string Query(std::string databaseName, std::string query); + + /// the ShowDatabases() function must be called before + std::vector 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); + void ClearDataPointsBuffer(); + void PrintDataPoints(); + void WriteData(std::string databaseName); + +}; + +#endif diff --git a/script.C b/script.C index 40e8e92..3933ed7 100644 --- a/script.C +++ b/script.C @@ -10,6 +10,7 @@ void script(){ reader->ScanNumBlock(); + /* for( int i = 0; i < reader->GetTotalNumBlock() ; i++){ printf("########################## nBlock : %u, %u/%u\n", reader->GetNumBlock(), reader->GetFilePos(), diff --git a/test.cpp b/test.cpp index 5906e6a..4b5bb05 100644 --- a/test.cpp +++ b/test.cpp @@ -3,8 +3,81 @@ #include #include #include // time in nano-sec +#include + +#include +#include #include "ClassDigitizer2Gen.h" +#include "influxdb.h" + + +#define maxRead 400 + +std::mutex digiMTX; +Digitizer2Gen * digi = new Digitizer2Gen(); +InfluxDB * influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/", false); + +unsigned int readCount = 0; + +timespec ta, tb; +static void ReadDataLoop(){ + clock_gettime(CLOCK_REALTIME, &ta); + //while(digi->IsAcqOn() && readCount < maxRead){ + while(true){ + digiMTX.lock(); + int ret = digi->ReadData(); + digiMTX.unlock(); + + if( ret == CAEN_FELib_Success){ + digi->SaveDataToFile(); + }else if(ret == CAEN_FELib_Stop){ + digi->ErrorMsg("No more data"); + break; + }else{ + digi->ErrorMsg("ReadData()"); + //digiMTX.unlock(); + //break; + } + if( readCount % 100 == 0 ) { + clock_gettime(CLOCK_REALTIME, &tb); + printf("%4d, duration : %.0f\n", readCount, tb.tv_nsec-ta.tv_nsec + tb.tv_sec*1e+9 - ta.tv_sec*1e+9); + ta = tb; + } + readCount++; + } + +} + +char cmdStr[100]; + +static void StatLoop(){ + //while(digi->IsAcqOn() && readCount < maxRead){ + while(digi->IsAcqOn()){ + digiMTX.lock(); + + digi->ReadStat(); + for(int i = 0; i < 64; i++){ + sprintf(cmdStr, "/ch/%d/par/SelfTrgRate", i); + std::string haha = digi->ReadValue( cmdStr, false); + influx->AddDataPoint("Rate,Ch=" + std::to_string(i) + " value=" + haha); + } + //digi->ReadValue("/ch/4/par/ChRealtimeMonitor", true); + //digi->ReadValue("/ch/4/par/ChDeadtimeMonitor", true); + //digi->ReadValue("/ch/4/par/ChTriggerCnt", true); + //digi->ReadValue("/ch/4/par/ChSavedEventCnt", true); + //digi->ReadValue("/ch/4/par/ChWaveCnt", true); + digiMTX.unlock(); + + + influx->WriteData("testing"); + influx->ClearDataPointsBuffer(); + digi->PrintStat(); + usleep(500*1000); // every 500 msec + } + +} + int main(int argc, char* argv[]){ @@ -16,7 +89,6 @@ int main(int argc, char* argv[]){ const char * url = "dig2://192.168.0.100/"; - Digitizer2Gen * digi = new Digitizer2Gen(); digi->OpenDigitizer(url); digi->ProgramPHA(false); @@ -57,51 +129,35 @@ int main(int argc, char* argv[]){ digi->OpenOutFile("haha"); + digi->StartACQ(); timespec t0, t1; clock_gettime(CLOCK_REALTIME, &t0); - - for( int i = 0; i < 30; i++){ - //usleep(100000); + std::thread th1 (ReadDataLoop); + std::thread th2 (StatLoop); - int ret = digi->ReadData(); + char c; + printf("Press q for stop."); + do{ + c = getchar(); + }while( c != 'q'); - //digi->ReadValue("/ch/4/par/SelfTrgRate", true); - - //if( i% 2 == 0 ) printf("0x%X \n", atoi(digi->ReadValue("/par/AcquisitionStatus").c_str()) & 0x3F ); - - - if( ret == CAEN_FELib_Success){ - - digi->SaveDataToFile(); - - //if( digi->evt->channel == 63 ) { - //if( i % 63 == 0 ) { - clock_gettime(CLOCK_REALTIME, &t1); - printf("%5d | t1-t0 : %10ld\n", i, t1.tv_nsec-t0.tv_nsec); - t0 = t1; - // //digi->ReadStat(); - // //digi->PrintStat(); - //} - }else{ - printf("something wrong when ReadData() | ret = %d \n", ret); - digi->ErrorMsg("ReadData()"); - } - - } - + digiMTX.lock(); digi->StopACQ(); - - digi->ReadStat(); - digi->PrintStat(); - - - digi->CloseOutFile(); + digiMTX.unlock(); + th1.join(); + th2.join(); + + clock_gettime(CLOCK_REALTIME, &t1); + printf("t1-t0 : %.0f\n", t1.tv_nsec-t0.tv_nsec + t1.tv_sec*1e+9 - t0.tv_sec*1e+9); + + digi->CloseOutFile(); digi->CloseDigitizer(); delete digi; + delete influx; }