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