[[MAJOR]] for 1 PHA digitizer is done and working fine

This commit is contained in:
carina@hades 2022-11-03 16:31:33 -04:00
parent 27c8b502d3
commit 56f665a20f
11 changed files with 161 additions and 113 deletions

View File

@ -46,6 +46,8 @@ TGraph * gDigiTrace2 = NULL ;
Pixel_t red, blue, green; Pixel_t red, blue, green;
InfluxDB * influx = NULL;
unsigned short nDigi = 0; unsigned short nDigi = 0;
Digitizer ** digi = NULL; Digitizer ** digi = NULL;
@ -276,6 +278,8 @@ MainWindow::MainWindow(const TGWindow *p,UInt_t w,UInt_t h) {
gStyle->SetOptStat("neiou"); gStyle->SetOptStat("neiou");
DrawDummyGraph(); DrawDummyGraph();
influx = new InfluxDB(ProgramSetting::databaseIP, false);
fMain->Move(300, 200); fMain->Move(300, 200);
@ -299,6 +303,8 @@ void MainWindow::GoodBye(){
delete gDigiTrace1; delete gDigiTrace1;
delete gDigiTrace2; delete gDigiTrace2;
delete influx;
printf("----- bye bye ---- \n"); printf("----- bye bye ---- \n");
gApplication->Terminate(0); gApplication->Terminate(0);
@ -309,38 +315,38 @@ MainWindow::~MainWindow() {
printf("----- %s \n", __func__); printf("----- %s \n", __func__);
delete fMenuBar; //delete fMenuBar;
delete fMenuFile; //delete fMenuFile;
delete fMenuDigitizers; //delete fMenuDigitizers;
delete fMenuUtility; //delete fMenuUtility;
delete fEcanvas; //delete fEcanvas;
//
delete boardIDEntry; //delete boardIDEntry;
delete chIDEntry; //delete chIDEntry;
//
delete teLog; //delete teLog;
//
delete bOpenDigitizers; //delete bOpenDigitizers;
delete bStartRun; //delete bStartRun;
delete bStopRun; //delete bStopRun;
delete cbMode; //delete cbMode;
//
delete dataPrefix; //delete dataPrefix;
delete runIDEntry; //delete runIDEntry;
delete cbDataRun; //delete cbDataRun;
//
delete bPlotSingleTrace; //delete bPlotSingleTrace;
delete bFitTrace; //delete bFitTrace;
//
delete boardSetting; //delete boardSetting;
delete channelSettingPHA; //delete channelSettingPHA;
delete channelSettingPSD; //delete channelSettingPSD;
delete registerSetting; //delete registerSetting;
delete triggerSummary; //delete triggerSummary;
delete programSetting; //delete programSetting;
delete startStopDialog; //delete startStopDialog;
//
delete runThread; //delete runThread;
fMain->Cleanup(); fMain->Cleanup();
delete fMain; delete fMain;
@ -538,6 +544,25 @@ void MainWindow::ChangeBoard(){
void MainWindow::UpdateExpName(){ void MainWindow::UpdateExpName(){
dataPrefix->SetText(ProgramSetting::ExpName.c_str()); dataPrefix->SetText(ProgramSetting::ExpName.c_str());
runIDEntry->SetNumber(lastRunID + 1); runIDEntry->SetNumber(lastRunID + 1);
influx->SetURL(ProgramSetting::databaseIP);
///Check database exist
influx->ShowDatabases();
std::vector<std::string> list = influx->GetDatabaseList();
bool dataBaseExist = false;
for( int i = 0; i < (int) list.size(); i++){
if( list[i] == ProgramSetting::databaseName ) {
dataBaseExist = true;
break;
}
}
if( !dataBaseExist ) influx->CreateDatabase(ProgramSetting::databaseName);
influx->ClearDataPointsBuffer();
influx->AddDataPoint("SavingData,ExpName=" + ProgramSetting::ExpName + " value=0");
influx->WriteData(ProgramSetting::databaseName);
} }
void MainWindow::MakeElogEntry(bool start){ void MainWindow::MakeElogEntry(bool start){
@ -585,6 +610,12 @@ void MainWindow::StartRun(){
ProgramSetting::SaveProgramSetting(); ProgramSetting::SaveProgramSetting();
cbMode->SetEnabled(false); cbMode->SetEnabled(false);
MakeElogEntry(true); MakeElogEntry(true);
influx->ClearDataPointsBuffer();
influx->AddDataPoint("SavingData,ExpName=" + ProgramSetting::ExpName + " value=1");
influx->AddDataPoint("RunID value=" + std::to_string(lastRunID));
influx->PrintDataPoints();
influx->WriteData(ProgramSetting::databaseName);
bool threadFlag = false; bool threadFlag = false;
for( int i = 0 ; i < nDigi; i++) { for( int i = 0 ; i < nDigi; i++) {
@ -634,6 +665,10 @@ void MainWindow::StopRun(){
LogMsg(Form("Stop Data Run")); LogMsg(Form("Stop Data Run"));
influx->ClearDataPointsBuffer();
influx->AddDataPoint("SavingData,ExpName=" + ProgramSetting::ExpName + " value=0");
influx->WriteData(ProgramSetting::databaseName);
int runID = runIDEntry->GetNumber(); int runID = runIDEntry->GetNumber();
runIDEntry->SetNumber(runID +1); runIDEntry->SetNumber(runID +1);
MakeElogEntry(false); MakeElogEntry(false);
@ -666,14 +701,6 @@ void MainWindow::OpenChannelSetting(Int_t boardID){
} }
} }
//TODO, should merge into LogMsg.
void MainWindow::UpdateChannelSetting(){
if( digi == NULL ) return;
if( channelSettingPHA != NULL ) channelSettingPHA->ChangeCh();
if( channelSettingPSD != NULL ) channelSettingPSD->ChangeCh();
}
void MainWindow::LogMsg(char * msg){ void MainWindow::LogMsg(char * msg){
time_t now = time(0); time_t now = time(0);
@ -778,7 +805,7 @@ void MainWindow::PlotSingleTrace(){
fEcanvas->GetCanvas()->cd(); fEcanvas->GetCanvas()->cd();
gAnaTrace1->Draw("same L"); gAnaTrace1->Draw("same L");
gAnaTrace2->Draw("same L"); if( isDualTrace) gAnaTrace2->Draw("same L");
gDigiTrace1->Draw("same L"); gDigiTrace1->Draw("same L");
fEcanvas->GetCanvas()->Update(); fEcanvas->GetCanvas()->Update();
break; break;
@ -902,14 +929,19 @@ void * MainWindow::Run(void * ptr){
CurrentTime = get_time(); CurrentTime = get_time();
if( CurrentTime - PreviousTime > 1e6 ){ if( CurrentTime - PreviousTime > 1e6 ){
if( printFileSizeCount > 0 ){ //if( printFileSizeCount > 0 ){
nLine = teLog->ReturnLineCount(); // nLine = teLog->ReturnLineCount();
teLog->GetText()->DelLine(nLine-1); // teLog->GetText()->DelLine(nLine-1);
} //}
std::string msg = Form("File Size : %.2f MB", data->GetPresentFileSize() / 1024./1024. ); //std::string msg = Form("File Size : %.2f MB", data->GetPresentFileSize() / 1024./1024. );
teLog->AddLineFast(msg.c_str()); //teLog->AddLineFast(msg.c_str());
teLog->Update(); //teLog->Update();
teLog->ShowBottom(); //teLog->ShowBottom();
influx->ClearDataPointsBuffer();
influx->AddDataPoint("FileSize value=" + std::to_string(data->GetPresentFileSize()));
influx->WriteData(ProgramSetting::databaseName);
PreviousTime = CurrentTime; PreviousTime = CurrentTime;
printFileSizeCount ++; printFileSizeCount ++;
@ -947,7 +979,7 @@ void * MainWindow::Run(void * ptr){
/// since the gDummy fixed the draw range, it does not really matter to remove extra points /// since the gDummy fixed the draw range, it does not really matter to remove extra points
gAnaTrace1->Draw("same L"); gAnaTrace1->Draw("same L");
gAnaTrace2->Draw("same L"); if( isDualTrace) gAnaTrace2->Draw("same L");
} }
} }

View File

@ -16,7 +16,7 @@
#include "macro.h" #include "macro.h"
#include "ClassDigitizer.h" #include "ClassDigitizer.h"
#include "influxdb.h"
#include "programSetting.h" #include "programSetting.h"
#include "boardSetting.h" #include "boardSetting.h"
#include "channelSettingPHA.h" #include "channelSettingPHA.h"
@ -67,7 +67,7 @@ private:
StartStopDialog * startStopDialog; StartStopDialog * startStopDialog;
TThread * runThread; TThread * runThread;
public: public:
MainWindow(const TGWindow *p, UInt_t w, UInt_t h); MainWindow(const TGWindow *p, UInt_t w, UInt_t h);
virtual ~MainWindow(); virtual ~MainWindow();
@ -91,7 +91,6 @@ public:
void ChangePlot(); void ChangePlot();
void OpenChannelSetting(Int_t); void OpenChannelSetting(Int_t);
void UpdateChannelSetting();
void LogMsg(char * ); void LogMsg(char * );
void GoodBye(); void GoodBye();
static void DrawDummyGraph(); static void DrawDummyGraph();

View File

@ -809,11 +809,10 @@ void BoardSetting::LogMsg(TString msg){
} }
void BoardSetting::DisableEdit(){ // When ACQ is running, disable all control void BoardSetting::DisableEdit(){ // When ACQ is running, disable all control
} }
void BoardSetting::EnableEdit(){ // When ACQ is running, disable all control void BoardSetting::EnableEdit(){ // When ACQ is running, disable all control
} }
void BoardSetting::ReadStatus(){ void BoardSetting::ReadStatus(){

View File

@ -2,24 +2,14 @@
source ~/FSUDAQ/FSUDAQ.sh source ~/FSUDAQ/FSUDAQ.sh
echo "======================================= making elog Entry" echo "======================================= making elog Entry"
echo ${DataPath}
echo ${ExpName}
echo ${ElogIP}
elogIDFile=${DataPath}"/elogID.txt" elogIDFile=${DataPath}"/elogID.txt"
source ${elogIDFile} source ${elogIDFile}
echo ${ElogID}
isStart=$1 isStart=$1
Comment=$2 Comment=$2
elogFileName=${DataPath}"/elogText.txt" elogFileName=${DataPath}"/elogText.txt"
echo ${isStart}
echo ${Comment}
#Get file size #Get file size
RUN=${lastRunID} RUN=${lastRunID}
runLen=${#lastRunID} runLen=${#lastRunID}
@ -38,16 +28,11 @@ if [ ${isStart} == "1" ]; then
echo "Start Run Comment : "${Comment}" <br />">> ${elogFileName} echo "Start Run Comment : "${Comment}" <br />">> ${elogFileName}
echo "-------------------------------------------------------------------------- <br />" >> ${elogFileName} echo "-------------------------------------------------------------------------- <br />" >> ${elogFileName}
#push to elog #push to elog
IDStr=$(elog -h ${ElogIP} -l ${ExpName} -u GeneralFox fsuphysics888 -a Author="GeneralFox" -a Category="Run" -a RunNo=${lastRunID} -a Subject="Run Log" -n 2 -m ${elogFileName}) IDStr=$(elog -h ${ElogIP} -l ${ExpName} -u GeneralFox fsuphysics888 -a Author="GeneralFox" -a Category="Run" -a RunNo=${lastRunID} -a Subject="Run Log" -n 2 -m ${elogFileName})
echo "==========="${IDStr}
IDStr=$(echo ${IDStr} | tail -1 | awk '{print $4}') IDStr=$(echo ${IDStr} | tail -1 | awk '{print $4}')
echo ".............."${IDStr}
if [ ${IDStr:0:3} == "ID=" ] && [[ ${IDStr:3} =~ ${re} ]]; then if [ ${IDStr:0:3} == "ID=" ] && [[ ${IDStr:3} =~ ${re} ]]; then
elogIDStr="Elog"${IDStr} elogIDStr="Elog"${IDStr}
echo "Elog is succefully pushed at ${elogIDStr}" echo "Elog is succefully pushed at ${elogIDStr}"
@ -62,10 +47,6 @@ else
echo "====== getting elog entry" echo "====== getting elog entry"
elog -h ${ElogIP} -l elog/${ExpName} -u GeneralFox fsuphysics888 -w ${ElogID} > ${elogFileName2} elog -h ${ElogIP} -l elog/${ExpName} -u GeneralFox fsuphysics888 -w ${ElogID} > ${elogFileName2}
echo "======================="
#cat ${elogFileName2}
echo "remove header"
cutLineNum=$(grep -n "==============" ${elogFileName2} | cut -d: -f1) cutLineNum=$(grep -n "==============" ${elogFileName2} | cut -d: -f1)
#check encoding #check encoding
encoding=$(grep "Encoding" ${elogFileName2} | awk '{print $2}') encoding=$(grep "Encoding" ${elogFileName2} | awk '{print $2}')
@ -75,11 +56,8 @@ else
#remove all header #remove all header
sed -i "1,${cutLineNum}d" ${elogFileName2} sed -i "1,${cutLineNum}d" ${elogFileName2}
echo "Run Stop at $(date) <br />" >> ${elogFileName2} echo "Run Stop at $(date) <br />" >> ${elogFileName2}
echo "End Run Comment : "${Comment}" <br />" >> ${elogFileName2}
#Comment
echo "End Run Comment : "${Comment}" <br />" >> ${elogFileName2}
totalFileSize=$(du -hc ${DataPath}"/data/"${ExpName}_run${RUN}* | tail -1| awk {'print $1'}) totalFileSize=$(du -hc ${DataPath}"/data/"${ExpName}_run${RUN}* | tail -1| awk {'print $1'})
echo "File Size : "${totalFileSize}" <br />">> ${elogFileName2} echo "File Size : "${totalFileSize}" <br />">> ${elogFileName2}
echo "************************************************************************** <br />" >> ${elogFileName2} echo "************************************************************************** <br />" >> ${elogFileName2}

View File

@ -15,6 +15,9 @@ InfluxDB::~InfluxDB(){
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
} }
void InfluxDB::SetURL(std::string url){
this->databaseIP = url;
}
std::string InfluxDB::ShowDatabases(){ std::string InfluxDB::ShowDatabases(){
curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POST, 1);
@ -33,6 +36,39 @@ std::string InfluxDB::ShowDatabases(){
printf("|%s|\n", readBuffer.c_str()); 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; return readBuffer;
} }
@ -72,7 +108,7 @@ void InfluxDB::AddDataPoint(std::string fullString){
dataPoints += fullString + "\n"; dataPoints += fullString + "\n";
} }
void InfluxDB::ClearDataPoints(){ void InfluxDB::ClearDataPointsBuffer(){
dataPoints = ""; dataPoints = "";
} }
@ -92,7 +128,7 @@ void InfluxDB::WriteData(std::string databaseName){
void InfluxDB::Execute(){ void InfluxDB::Execute(){
respond = curl_easy_perform(curl); respond = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode);
printf("==== respond code %ld \n", respondCode); //printf("==== respond code %ld \n", respondCode);
if( respond != CURLE_OK) printf("############# fail\n"); if( respond != CURLE_OK) printf("############# fail\n");
} }

View File

@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <vector>
#include <string> #include <string>
#include <curl/curl.h> #include <curl/curl.h>
@ -16,6 +17,8 @@ class InfluxDB{
std::string databaseIP; std::string databaseIP;
std::string dataPoints; std::string dataPoints;
std::vector<std::string> databaseList;
static size_t WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp); static size_t WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp);
void Execute(); void Execute();
@ -24,18 +27,23 @@ class InfluxDB{
/// url = https://fsunuc.physics.fsu.edu/InfluxDB/ /// url = https://fsunuc.physics.fsu.edu/InfluxDB/
InfluxDB(std::string url, bool verbose = false); InfluxDB(std::string url, bool verbose = false);
~InfluxDB(); ~InfluxDB();
void SetURL(std::string url);
/// Query /// Query
std::string ShowDatabases(); std::string ShowDatabases(); /// this save the list of database into databaseList
std::string Query(std::string databaseName, std::string query); std::string Query(std::string databaseName, std::string query);
/// the ShowDatabases() function must be called before
std::vector<std::string> GetDatabaseList() {return databaseList;}
void CreateDatabase(std::string databaseName); void CreateDatabase(std::string databaseName);
/// for single or batch write, /// for single or batch write,
/// 1, addDataPoint first, you can add as many as you like /// 1, addDataPoint first, you can add as many as you like
/// 2, writeData. /// 2, writeData.
void AddDataPoint(std::string fullString); void AddDataPoint(std::string fullString);
void ClearDataPoints(); void ClearDataPointsBuffer();
void PrintDataPoints(); void PrintDataPoints();
void WriteData(std::string databaseName); void WriteData(std::string databaseName);

View File

@ -63,6 +63,7 @@ void StartStopDialog::DoClose(){
} }
void StartStopDialog::DoOK(){ void StartStopDialog::DoOK(){
Comment = "";
Comment = txtComment->GetText(); Comment = txtComment->GetText();
isOK = true; isOK = true;
TTimer::SingleShot(500, "StartStopDialog", this, "CloseWindow()"); TTimer::SingleShot(500, "StartStopDialog", this, "CloseWindow()");

View File

@ -15,6 +15,7 @@
#include <sys/time.h> /** struct timeval, select() */ #include <sys/time.h> /** struct timeval, select() */
#include <termios.h> /** tcgetattr(), tcsetattr() */ #include <termios.h> /** tcgetattr(), tcsetattr() */
#include <vector>
static struct termios g_old_kbd_mode; static struct termios g_old_kbd_mode;
@ -76,14 +77,20 @@ int main(int argc, char* argv[]){
InfluxDB influx("https://fsunuc.physics.fsu.edu/influx/", false); InfluxDB influx("https://fsunuc.physics.fsu.edu/influx/", false);
//influx.ShowDatabases(); influx.ShowDatabases();
std::vector<std::string> qaqa = influx.GetDatabaseList();
for( int i = 0; i < (int) qaqa.size(); i++) printf("%s\n", qaqa[i].c_str());
//influx.Query("testing", "Show measurements"); //influx.Query("testing", "Show measurements");
influx.AddDataPoint("Rate,Bd=0,Ch=0 value=10"); //influx.AddDataPoint("Rate,Bd=0,Ch=0 value=10");
influx.AddDataPoint("Rate,Bd=0,Ch=7 value=20"); //influx.AddDataPoint("Rate,Bd=0,Ch=7 value=20");
influx.AddDataPoint("Rate,Bd=0,Ch=15 value=30"); //influx.AddDataPoint("Rate,Bd=0,Ch=15 value=30");
influx.WriteData("testing"); //
//influx.PrintDataPoints();
//
//influx.WriteData("testing");
/**////##################### Demo for loading and change setting without open a digitizer /**////##################### Demo for loading and change setting without open a digitizer
/** /**

View File

@ -15,8 +15,7 @@
extern unsigned short nDigi; extern unsigned short nDigi;
extern Digitizer ** digi; extern Digitizer ** digi;
extern InfluxDB * influx;
//extern bool ProgramSetting::EnableDatabase;
bool TriggerSummary::updateFlag = true; bool TriggerSummary::updateFlag = true;
TGTextEntry * TriggerSummary::txtTrigger[MaxNBoards][MaxNChannels] = {NULL}; TGTextEntry * TriggerSummary::txtTrigger[MaxNBoards][MaxNChannels] = {NULL};
@ -27,6 +26,7 @@ TGNumberEntry * TriggerSummary::numUpdateTime = NULL;
unsigned short TriggerSummary::value[MaxNBoards][MaxNChannels] = {0}; unsigned short TriggerSummary::value[MaxNBoards][MaxNChannels] = {0};
bool TriggerSummary::onOff[MaxNBoards][MaxNChannels] = {true}; bool TriggerSummary::onOff[MaxNBoards][MaxNChannels] = {true};
TriggerSummary::TriggerSummary(const TGWindow *p, const TGWindow *main){ TriggerSummary::TriggerSummary(const TGWindow *p, const TGWindow *main){
fMain = new TGTransientFrame(p,main); fMain = new TGTransientFrame(p,main);
@ -153,38 +153,24 @@ TriggerSummary::~TriggerSummary(){
void * TriggerSummary::UpdateTriggerRate(void * ptr){ void * TriggerSummary::UpdateTriggerRate(void * ptr){
std::string tempDBPath = ProgramSetting::DataSavingPath + "/tempDB.txt";
std::string cmd = "curl -XPOST " + ProgramSetting::databaseIP + "/write?db=" + ProgramSetting::databaseName + " --data-binary @" + tempDBPath;
std::ofstream myfile;
unsigned int t1 = get_time();
unsigned int t2 = 0;
while( updateFlag){ while( updateFlag){
if( ProgramSetting::EnableDatabase) influx->ClearDataPointsBuffer();
for( int bd = 0; bd < nDigi; bd++){ for( int bd = 0; bd < nDigi; bd++){
uint32_t chMask = digi[bd]->GetChannelMask();
for( int ch = 0; ch < digi[bd]->GetNChannel(); ch++){ for( int ch = 0; ch < digi[bd]->GetNChannel(); ch++){
if( (chMask & ( 1 << ch) ) == 0 ) continue;
txtTrigger[bd][ch]->SetText(Form("%.2f", digi[bd]->GetData()->TriggerRate[ch])); txtTrigger[bd][ch]->SetText(Form("%.2f", digi[bd]->GetData()->TriggerRate[ch]));
value[bd][ch] = digi[bd]->GetSettingFromMemory(Register::DPP::PHA::TriggerThreshold, ch); value[bd][ch] = digi[bd]->GetSettingFromMemory(Register::DPP::PHA::TriggerThreshold, ch);
txtThresholdValue[bd][ch]->SetText(Form("%d", value[bd][ch]), false); txtThresholdValue[bd][ch]->SetText(Form("%d", value[bd][ch]), false);
influx->AddDataPoint(Form("Rate,Bd=%d,Ch=%d value=%.2f", bd, ch, digi[bd]->GetData()->TriggerRate[ch]));
} }
} }
t2 = get_time(); influx->WriteData(ProgramSetting::databaseName);
if( ProgramSetting::EnableDatabase && (t2 - t1) > 5*1e6){
myfile.open(tempDBPath);
for( int bd = 0; bd < nDigi; bd++){
for( int ch = 0; ch < digi[bd]->GetNChannel(); ch++){
myfile << "Rate,Bd=" << bd << ",Ch=" << ch << " value=" << digi[bd]->GetData()->TriggerRate[ch] << "\n";
}
}
myfile.close();
int temp = system(cmd.c_str());
t1 = t2;
}
usleep(numUpdateTime->GetNumber() * 1000); usleep(numUpdateTime->GetNumber() * 1000);
} }

View File

@ -10,6 +10,7 @@
#include <TGLabel.h> #include <TGLabel.h>
#include "ClassDigitizer.h" #include "ClassDigitizer.h"
#include "macro.h" #include "macro.h"
#include "influxdb.h"
class TGWindow; class TGWindow;
class TGMainFrame; class TGMainFrame;

View File

@ -11,7 +11,8 @@ For other information, please see https://fsunuc.physics.fsu.edu/wiki/index.php/
3. CAENDigitizer 2.12+ 3. CAENDigitizer 2.12+
4. CAEN A3818 Driver 1.61+ (for optical link) 4. CAEN A3818 Driver 1.61+ (for optical link)
5. CERN ROOT 6 5. CERN ROOT 6
6. InfluxDB 1.8 (recommanded for trigger rate, optional for database) 6. libcurl4-nss-dev (for the libcurl, used in InfluxDB class)
7. InfluxDB 1.8 (recommanded for trigger rate, optional for database)
7. Elog (optional for auto make elog entry) 7. Elog (optional for auto make elog entry)
## Folder Structure ## Folder Structure