add influxdb
This commit is contained in:
parent
1ae7309eb2
commit
bb74e0d308
|
@ -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;
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
76
FSUDAQ.cpp
76
FSUDAQ.cpp
|
@ -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++){
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
4
FSUDAQ.h
4
FSUDAQ.h
|
@ -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);
|
||||
|
|
|
@ -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
31
README.md
Normal 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`
|
|
@ -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
157
influxdb.cpp
Normal 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
58
influxdb.h
Normal 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
|
Loading…
Reference in New Issue
Block a user