Belle II Software development
DQMHistAnalysisInputPVSrv.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8//+
9// File : DQMHistAnalysisInputPVSrv.cc
10// Description : DQM input module, convert epics PVs to histograms for analysis
11//-
12
13
14#include <framework/core/ModuleParam.templateDetails.h>
15#include <dqm/analysis/modules/DQMHistAnalysisInputPVSrv.h>
16#include <TSystem.h>
17#include <TDirectory.h>
18#include <TH1F.h>
19#include <TH2F.h>
20
21using namespace std;
22using namespace Belle2;
23
24//-----------------------------------------------------------------
25// Register the Module
26//-----------------------------------------------------------------
27REG_MODULE(DQMHistAnalysisInputPVSrv);
28
29//-----------------------------------------------------------------
30// Implementation
31//-----------------------------------------------------------------
32
33#ifdef _BELLE2_EPICS
34static void printChidInfo(chid ichid, const char* message)
35{
36 B2DEBUG(20, message);
37 B2DEBUG(20, "pv: " << ca_name(ichid) << " type(" << ca_field_type(ichid) << ") nelements(" << ca_element_count(
38 ichid) << ") host(" << ca_host_name(ichid)
39 << ") read(" << ca_read_access(ichid) << ") write(" << ca_write_access(ichid) << ") state(" << ca_state(ichid) << ")");
40}
41
42static void exceptionCallback(struct exception_handler_args args)
43{
44 chid ichid = args.chid;
45 long stat = args.stat; /* Channel access status code*/
46 const char* channel;
47 const char* noname = "unknown";
48
49 channel = (ichid ? ca_name(ichid) : noname);
50
51
52 if (ichid) printChidInfo(ichid, "exceptionCallback");
53 printf("exceptionCallback stat %s channel %s\n", ca_message(stat), channel);
54}
55
56static void connectionCallback(struct connection_handler_args args)
57{
58 chid ichid = args.chid;
59
60 printChidInfo(ichid, "connectionCallback");
61}
62
63static void accessRightsCallback(struct access_rights_handler_args args)
64{
65 chid ichid = args.chid;
66
67 printChidInfo(ichid, "accessRightsCallback");
68}
69static void eventCallback(struct event_handler_args eha)
70{
71 chid ichid = eha.chid;
72 MYNODE* n = (MYNODE*)eha.usr;
73
74 if (eha.status != ECA_NORMAL) {
75 printChidInfo(ichid, "eventCallback");
76 } else {
77// char *pdata = (char *)eha.dbr;
78// printf("Event Callback: %s = %s (%d,%d)\n",ca_name(eha.chid),pdata,(int)eha.type,(int)eha.count);
79// printf("Event Callback: %s (%ld,%s,%ld)\n",ca_name(n->mychid),ca_field_type(n->mychid),dbr_type_to_text(ca_field_type(n->mychid)),ca_element_count(n->mychid));
80 n->changed = true;
81 }
82}
83
84#endif
85
88{
89 //Parameter definition
90 addParam("RefreshInterval", m_interval, "Refresh interval of histograms in ms", 2000);
91 addParam("HistoList", m_histlist, "pvname, histname, histtitle, (bins,min,max[,bins,min,max])");
92 addParam("Callback", m_callback, "Using EPICS callback for changes", true);
93 addParam("Server", m_server, "Start http server on port 8082", false);
94 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: Constructor done.");
95}
96
98{
99 m_eventMetaDataPtr.registerInDataStore();
100 //if (m_server) m_serv = new THttpServer("http:8082");
101
102#ifdef _BELLE2_EPICS
103 SEVCHK(ca_add_exception_event(exceptionCallback, NULL), "ca_add_exception_event");
104 for (auto& it : m_histlist) {
105 if (it.size() != 4 && it.size() != 5) {
106 B2WARNING("Histolist with wrong nr of parameters " << it.size());
107 continue;
108 }
109 auto n = (MYNODE*) callocMustSucceed(1, sizeof(MYNODE), "caMonitor");
110 pmynode.push_back(n);
111
112 {
113 TDirectory* oldDir = gDirectory;
114 TDirectory* d = oldDir;
115 TString myl = it.at(1).c_str();
116 TString tok;
117 Ssiz_t from = 0;
118 while (myl.Tokenize(tok, from, "/")) {
119 TString dummy;
120 Ssiz_t f;
121 f = from;
122 if (myl.Tokenize(dummy, f, "/")) { // check if its the last one
123 d = d->mkdir(tok, "", true);
124 d->cd();
125 } else {
126 break;
127 }
128 }
129
130 B2DEBUG(20, "Create Histo " << tok);
131
132 Int_t x;
133 Double_t xmin, xmax;
134 strncpy(n->name, it.at(0).c_str(), MAX_PV_NAME_LEN - 1);
135 istringstream is(it.at(3));
136 is >> x;
137 is >> xmin;
138 is >> xmax;
139 if (it.size() == 4) {
140 n->histo = (TH1*)new TH1F(tok, it.at(2).c_str(), x, xmin, xmax);
141 n->binx = x;
142 n->biny = 0;
143 n->binmax = x;
144 } else {
145 Int_t y;
146 Double_t ymin, ymax;
147 istringstream iss(it.at(4));
148 iss >> y;
149 iss >> ymin;
150 iss >> ymax;
151 n->histo = (TH1*)new TH2F(tok, it.at(2).c_str(), x, xmin, xmax, y, ymin, ymax);
152 n->binx = x;
153 n->biny = y;
154 n->binmax = x * y;
155 }
156
157 // cd back to root directory
158 oldDir->cd();
159 }
160
161 }
162
163 for (auto n : pmynode) {
164 SEVCHK(ca_create_channel(n->name, connectionCallback, n, 20, &n->mychid), "ca_create_channel");
165 SEVCHK(ca_replace_access_rights_event(n->mychid, accessRightsCallback), "ca_replace_access_rights_event");
166 if (m_callback) {
167 SEVCHK(ca_create_subscription(DBR_STRING, 1, n->mychid, DBE_VALUE, eventCallback, n, &n->myevid), "ca_create_subscription");
168 }
169 }
170
171#endif
172 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: initialized.");
173}
174
175
177{
178 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: beginRun called.");
179}
180
182{
183 m_count++;
184 m_eventMetaDataPtr.create();
185 m_eventMetaDataPtr->setExperiment(m_expno);
187 m_eventMetaDataPtr->setEvent(m_count);
188
189 TTimer t(m_interval, kFALSE);// in ms
190
191#ifdef _BELLE2_EPICS
192 SEVCHK(ca_pend_event(0.0001), "ca_pend_event");
193
194 for (auto n : pmynode) {
195 if (m_callback && !n->changed) continue;
196 n->changed = false;
197 if (ca_field_type(n->mychid) != DBF_LONG && ca_field_type(n->mychid) != DBF_FLOAT) continue;
198
199 // FIXME: dbr_size_n is a preprocessor macro, it would be nice replacing it with something better
200#pragma GCC diagnostic push
201#pragma GCC diagnostic ignored "-Wtype-limits"
202 auto bufferorg = new char[dbr_size_n(ca_field_type(n->mychid), ca_element_count(n->mychid))];
203#pragma GCC diagnostic pop
204
205 void* buffer = (void*) bufferorg;
206 int status;
207
208 status = ca_array_get(ca_field_type(n->mychid), ca_element_count(n->mychid), n->mychid, buffer);
209 SEVCHK(status, "ca_array_get()");
210 status = ca_pend_io(15.0);
211 if (status != ECA_NORMAL) {
212 B2WARNING("EPICS ca_array_get " << ca_name(n->mychid) << " didn't return a value.");
213 } else {
214 if (n->histo) {
215 // this should always be the case
216 unsigned int bins;
217 bins = ca_element_count(n->mychid) < n->binmax ? ca_element_count(n->mychid) : n->binmax;
218 TH1* histo = n->histo;
219 for (unsigned int j = ca_element_count(n->mychid); j < n->binmax; j++) histo->SetBinContent(j + 1, 0); // zero out undefined bins
220 switch (ca_field_type(n->mychid)) {
221 case DBF_CHAR: {
222 dbr_char_t* b = (dbr_char_t*)buffer;
223 for (unsigned int j = 0; j < bins; j++) {
224 histo->SetBinContent(j + 1, b[j]);
225 }
226 }; break;
227// case DBF_INT:
228 case DBF_SHORT: { // same as INT
229 dbr_short_t* b = (dbr_short_t*)buffer;
230 for (unsigned int j = 0; j < bins; j++) {
231 histo->SetBinContent(j + 1, b[j]);
232 }
233 }; break;
234 case DBF_LONG: {
235 dbr_long_t* b = (dbr_long_t*)buffer;
236 for (unsigned int j = 0; j < bins; j++) {
237 histo->SetBinContent(j + 1, b[j]);
238 }
239 }; break;
240 case DBF_FLOAT: {
241 dbr_float_t* b = (dbr_float_t*)buffer;
242 for (unsigned int j = 0; j < bins; j++) {
243 histo->SetBinContent(j + 1, b[j]);
244 }
245 }; break;
246 case DBF_DOUBLE: {
247 dbr_double_t* b = (dbr_double_t*)buffer;
248 for (unsigned int j = 0; j < bins; j++) {
249 histo->SetBinContent(j + 1, b[j]);
250 }
251 }; break;
252 default:
253 // type not supported
254 break;
255 }
256 }
257 }
258 delete[] bufferorg;
259 }
260#endif
261 do { // call at least once!
262 //if (m_serv) m_serv->ProcessRequests();
263 gSystem->Sleep(10); // 10 ms sleep
264 } while (!t.CheckTimer(gSystem->Now()));
265
266}
267
269{
270 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: endRun called");
271}
272
273
275{
276 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: terminate called");
277}
278
279
280
void initialize() override final
Definition of the histograms.
void terminate() override final
This method is called at the end of the event processing.
void event() override final
This method is called for each event.
void endRun() override final
This method is called if the current run ends.
bool m_server
Whether to start http server on port 8082.
std::vector< std::vector< std::string > > m_histlist
Parameter list for histograms.
void beginRun() override final
Called when entering a new run.
StoreObjPtr< EventMetaData > m_eventMetaDataPtr
The metadata for each event.
bool m_callback
Whether to use EPICS callback for changes.
DQMHistAnalysisModule()
Constructor / Destructor.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
Abstract base class for different kinds of events.
STL namespace.