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
97
99{
100#ifdef _BELLE2_EPICS
101 if (ca_current_context()) ca_context_destroy();
102#endif
103}
104
106{
107 m_eventMetaDataPtr.registerInDataStore();
108 //if (m_server) m_serv = new THttpServer("http:8082");
109
110#ifdef _BELLE2_EPICS
111 if (!ca_current_context()) SEVCHK(ca_context_create(ca_disable_preemptive_callback), "ca_context_create");
112 SEVCHK(ca_add_exception_event(exceptionCallback, NULL), "ca_add_exception_event");
113 for (auto& it : m_histlist) {
114 if (it.size() != 4 && it.size() != 5) {
115 B2WARNING("Histolist with wrong nr of parameters " << it.size());
116 continue;
117 }
118 auto n = (MYNODE*) callocMustSucceed(1, sizeof(MYNODE), "caMonitor");
119 pmynode.push_back(n);
120
121 {
122 TDirectory* oldDir = gDirectory;
123 TDirectory* d = oldDir;
124 TString myl = it.at(1).c_str();
125 TString tok;
126 Ssiz_t from = 0;
127 while (myl.Tokenize(tok, from, "/")) {
128 TString dummy;
129 Ssiz_t f;
130 f = from;
131 if (myl.Tokenize(dummy, f, "/")) { // check if its the last one
132 d = d->mkdir(tok, "", true);
133 d->cd();
134 } else {
135 break;
136 }
137 }
138
139 B2DEBUG(20, "Create Histo " << tok);
140
141 Int_t x;
142 Double_t xmin, xmax;
143 strncpy(n->name, it.at(0).c_str(), MAX_PV_NAME_LEN - 1);
144 istringstream is(it.at(3));
145 is >> x;
146 is >> xmin;
147 is >> xmax;
148 if (it.size() == 4) {
149 n->histo = (TH1*)new TH1F(tok, it.at(2).c_str(), x, xmin, xmax);
150 n->binx = x;
151 n->biny = 0;
152 n->binmax = x;
153 } else {
154 Int_t y;
155 Double_t ymin, ymax;
156 istringstream iss(it.at(4));
157 iss >> y;
158 iss >> ymin;
159 iss >> ymax;
160 n->histo = (TH1*)new TH2F(tok, it.at(2).c_str(), x, xmin, xmax, y, ymin, ymax);
161 n->binx = x;
162 n->biny = y;
163 n->binmax = x * y;
164 }
165
166 // cd back to root directory
167 oldDir->cd();
168 }
169
170 }
171
172 for (auto n : pmynode) {
173 SEVCHK(ca_create_channel(n->name, connectionCallback, n, 20, &n->mychid), "ca_create_channel");
174 SEVCHK(ca_replace_access_rights_event(n->mychid, accessRightsCallback), "ca_replace_access_rights_event");
175 if (m_callback) {
176 SEVCHK(ca_create_subscription(DBR_STRING, 1, n->mychid, DBE_VALUE, eventCallback, n, &n->myevid), "ca_create_subscription");
177 }
178 }
179
180#endif
181 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: initialized.");
182}
183
184
186{
187 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: beginRun called.");
188}
189
191{
192 m_count++;
193 m_eventMetaDataPtr.create();
194 m_eventMetaDataPtr->setExperiment(m_expno);
196 m_eventMetaDataPtr->setEvent(m_count);
197
198 TTimer t(m_interval, kFALSE);// in ms
199
200#ifdef _BELLE2_EPICS
201 SEVCHK(ca_pend_event(0.0001), "ca_pend_event");
202
203 for (auto n : pmynode) {
204 if (m_callback && !n->changed) continue;
205 n->changed = false;
206 if (ca_field_type(n->mychid) != DBF_LONG && ca_field_type(n->mychid) != DBF_FLOAT) continue;
207
208 // FIXME: dbr_size_n is a preprocessor macro, it would be nice replacing it with something better
209#pragma GCC diagnostic push
210#pragma GCC diagnostic ignored "-Wtype-limits"
211 auto bufferorg = new char[dbr_size_n(ca_field_type(n->mychid), ca_element_count(n->mychid))];
212#pragma GCC diagnostic pop
213
214 void* buffer = (void*) bufferorg;
215 int status;
216
217 status = ca_array_get(ca_field_type(n->mychid), ca_element_count(n->mychid), n->mychid, buffer);
218 SEVCHK(status, "ca_array_get()");
219 status = ca_pend_io(15.0);
220 if (status != ECA_NORMAL) {
221 B2WARNING("EPICS ca_array_get " << ca_name(n->mychid) << " didn't return a value.");
222 } else {
223 if (n->histo) {
224 // this should always be the case
225 unsigned int bins;
226 bins = ca_element_count(n->mychid) < n->binmax ? ca_element_count(n->mychid) : n->binmax;
227 TH1* histo = n->histo;
228 for (unsigned int j = ca_element_count(n->mychid); j < n->binmax; j++) histo->SetBinContent(j + 1, 0); // zero out undefined bins
229 switch (ca_field_type(n->mychid)) {
230 case DBF_CHAR: {
231 dbr_char_t* b = (dbr_char_t*)buffer;
232 for (unsigned int j = 0; j < bins; j++) {
233 histo->SetBinContent(j + 1, b[j]);
234 }
235 }; break;
236// case DBF_INT:
237 case DBF_SHORT: { // same as INT
238 dbr_short_t* b = (dbr_short_t*)buffer;
239 for (unsigned int j = 0; j < bins; j++) {
240 histo->SetBinContent(j + 1, b[j]);
241 }
242 }; break;
243 case DBF_LONG: {
244 dbr_long_t* b = (dbr_long_t*)buffer;
245 for (unsigned int j = 0; j < bins; j++) {
246 histo->SetBinContent(j + 1, b[j]);
247 }
248 }; break;
249 case DBF_FLOAT: {
250 dbr_float_t* b = (dbr_float_t*)buffer;
251 for (unsigned int j = 0; j < bins; j++) {
252 histo->SetBinContent(j + 1, b[j]);
253 }
254 }; break;
255 case DBF_DOUBLE: {
256 dbr_double_t* b = (dbr_double_t*)buffer;
257 for (unsigned int j = 0; j < bins; j++) {
258 histo->SetBinContent(j + 1, b[j]);
259 }
260 }; break;
261 default:
262 // type not supported
263 break;
264 }
265 }
266 }
267 delete[] bufferorg;
268 }
269#endif
270 do { // call at least once!
271 //if (m_serv) m_serv->ProcessRequests();
272 gSystem->Sleep(10); // 10 ms sleep
273 } while (!t.CheckTimer(gSystem->Now()));
274
275}
276
278{
279 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: endRun called");
280}
281
282
284{
285 B2DEBUG(20, "DQMHistAnalysisInputPVSrv: terminate called");
286}
287
288
289
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.
The base class for the histogram analysis module.
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
STL namespace.