add influxdb

This commit is contained in:
splitPoleDAQ 2023-05-24 16:04:32 -04:00
parent 1ae7309eb2
commit bb74e0d308
10 changed files with 341 additions and 12 deletions

View File

@ -188,7 +188,7 @@ inline void Data::ClearData(){
}
inline void Data::ClearBuffer(){
printf("==== %s \n", __func__);
printf("==== Data::%s \n", __func__);
delete buffer;
buffer = nullptr;
AllocatedSize = 0;

View File

@ -103,8 +103,8 @@ class Digitizer{
CAEN_DGTZ_BoardInfo_t GetBoardInfo() const {return BoardInfo;}
std::string GetModelName() const {return BoardInfo.ModelName;}
int GetSerialNumber() const {return BoardInfo.SerialNumber;}
int GetChannelMask() const {return channelMask;}
bool GetChannelOnOff(unsigned ch) const {return (channelMask & ( 1 << ch) );}
int GetChannelMask() { channelMask = GetSettingFromMemory(DPP::ChannelEnableMask); return channelMask;}
bool GetChannelOnOff(unsigned ch) { channelMask = GetSettingFromMemory(DPP::ChannelEnableMask); return (channelMask & ( 1 << ch) );}
float GetCh2ns() const {return ch2ns;}
int GetNChannels() const {return NChannel;}
int GetHandle() const {return handle;}

View File

@ -1221,6 +1221,8 @@ void DigiSettingsPanel::SetUpChannelMask(){
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHASetting();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDSetting();
emit UpdateOtherPanels();
});
}

View File

@ -12,6 +12,10 @@
#include <QFileDialog>
#include <QScrollArea>
//TODO make the address in config file
const std::string influxIP = "https://fsunuc.physics.fsu.edu/influx/";
const std::string dataBaseName = "testing";
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
setWindowTitle("FSU DAQ");
@ -166,6 +170,43 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
//=========== disable widget
WaitForDigitizersOpen(true);
{//^====================== database
influx = new InfluxDB(influxIP, false);
if( influx->TestingConnection() ){
LogMsg("<font style=\"color : green;\"> InfluxDB URL (<b>"+ QString::fromStdString(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 ) foundDatabase = true;
//LogMsg(QString::number(i) + "|" + QString::fromStdString(databaseList[i]));
}
if( foundDatabase ){
LogMsg("<font style=\"color : green;\"> Database <b>" + QString::fromStdString(dataBaseName) + "</b> found.");
influx->AddDataPoint("ProgramStart value=1");
influx->WriteData(dataBaseName);
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>" + QString::fromStdString(dataBaseName) + "</b> NOT found.");
delete influx;
influx = nullptr;
}
}else{
LogMsg("<font style=\"color : red;\"> InfluxDB URL (<b>"+ QString::fromStdString(influxIP) + "</b>) is NOT Valid </font>");
delete influx;
influx = nullptr;
}
}
}
MainWindow::~MainWindow(){
@ -187,6 +228,8 @@ MainWindow::~MainWindow(){
delete scalarThread;
}
delete influx;
}
//***************************************************************
@ -497,7 +540,7 @@ void MainWindow::SetupScalar(){
scalarThread = new TimingThread();
connect(scalarThread, &TimingThread::timeUp, this, &MainWindow::UpdateScalar);
scalar->setGeometry(0, 0, 10 + nDigi * 200, 110 + MaxNChannels * 25);
scalar->setGeometry(0, 0, 10 + nDigi * 200, 110 + MaxNChannels * 20);
if( lbLastUpdateTime == nullptr ){
lbLastUpdateTime = new QLabel("Last update : NA", scalar);
@ -534,6 +577,7 @@ void MainWindow::SetupScalar(){
rowID = 2;
leTrigger[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++){
if( ch == 0 ){
@ -552,7 +596,6 @@ void MainWindow::SetupScalar(){
}
rowID ++;
leTrigger[iDigi][ch] = new QLineEdit(scalar);
leTrigger[iDigi][ch]->setReadOnly(true);
leTrigger[iDigi][ch]->setAlignment(Qt::AlignRight);
@ -562,6 +605,10 @@ void MainWindow::SetupScalar(){
leAccept[iDigi][ch]->setReadOnly(true);
leAccept[iDigi][ch]->setAlignment(Qt::AlignRight);
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);
}
}
@ -603,7 +650,7 @@ void MainWindow::OpenScalar(){
void MainWindow::UpdateScalar(){
if( digi == 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"));
@ -611,13 +658,26 @@ void MainWindow::UpdateScalar(){
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){
digiMTX[iDigi].lock();
for( int i = 0; i < digi[iDigi]->GetNChannels(); i++){
//printf(" %3d %2d | %7.2f %7.2f \n", digi[iDigi]->GetSerialNumber(), i, digi[iDigi]->GetData()->TriggerRate[i], digi[iDigi]->GetData()->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( digi[iDigi]->GetChannelOnOff(i) == true ) {
//printf(" %3d %2d | %7.2f %7.2f \n", digi[iDigi]->GetSerialNumber(), i, digi[iDigi]->GetData()->TriggerRate[i], digi[iDigi]->GetData()->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);
influx->ClearDataPointsBuffer();
}
}
//***************************************************************
@ -909,6 +969,16 @@ void MainWindow::UpdateAllPanels(int panelID){
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 );
}
}
}
}
}

View File

@ -17,6 +17,7 @@
#include "Scope.h"
#include "DigiSettingsPanel.h"
#include "CanvasClass.h"
#include "influxdb.h"
//^#===================================================== MainWindow
class MainWindow : public QMainWindow{
@ -85,6 +86,9 @@ private:
QPushButton * bnCanvas;
//@----- influx
InfluxDB * influx;
//@----- log msg
QPlainTextEdit * logInfo;
void LogMsg(QString msg);

View File

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

31
README.md Normal file
View File

@ -0,0 +1,31 @@
# 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

@ -13,8 +13,6 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
this->nDigi = nDigi;
this->readDataThread = readDataThread;
for( unsigned int i = 0; i < nDigi; i++){ traceOn[i] = digi[i]->IsRecordTrace();}
setWindowTitle("Scope");
setGeometry(0, 0, 1000, 800);
setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint );
@ -232,6 +230,8 @@ void Scope::StartScope(){
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);
@ -300,6 +300,9 @@ void Scope::UpdateScope(){
if( !digi ) return;
int ch = cbScopeCh->currentIndex();
if( digi[ID]->GetChannelOnOff(ch) == false) return;
int ch2ns = digi[ID]->GetCh2ns();
int factor = digi[ID]->IsDualTrace_PHA() ? 2 : 1;
@ -715,6 +718,8 @@ void Scope::UpdatePanelFromMomeory(){
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) UpdatePHAPanel();
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) UpdatePSDPanel();
settingGroup->setEnabled(digi[ID]->GetChannelOnOff(ch));
}
void Scope::UpdatePHAPanel(){

157
influxdb.cpp Normal file
View File

@ -0,0 +1,157 @@
#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;
}

58
influxdb.h Normal file
View File

@ -0,0 +1,58 @@
#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