artdaq_epics_plugin  v1_02_12
epics_metric.cc
1 // epics_metric.cc: Epics Metric Plugin
2 // Author: Eric Flumerfelt
3 // Last Modified: 09/25/2015
4 //
5 // An implementation of the MetricPlugin interface for Epics/ChannelAccess
6 
7 #ifndef __EPICS_METRIC__
8 #define __EPICS_METRIC__ 1
9 
10 #include <unordered_map>
11 #include "artdaq-utilities/Plugins/MetricMacros.hh"
12 #include "messagefacility/MessageLogger/MessageLogger.h"
13 #undef STATIC_ASSERT
14 
15 #ifdef __clang__
16 #pragma clang diagnostic push
17 #pragma clang diagnostic ignored "-Wunused-parameter"
18 #endif
19 #include <cadef.h>
20 #ifdef __clang__
21 #pragma clang diagnostic pop
22 #endif
23 
24 #include "TRACE/tracemf.h"
25 #define TRACE_NAME "EPICSMetric"
26 
30 namespace artdaq {
34 class EpicsMetric : public MetricPlugin
35 {
36 private:
37  std::string prefix_;
38  std::unordered_map<std::string, chid> channels_;
39 
40  bool checkChannel_(std::string name)
41  {
42  if (!channels_.count(name))
43  {
44  chid channel;
45  ca_search(name.c_str(), &channel);
46  auto sts = ca_pend_io(5.0);
47  if (sts != ECA_NORMAL)
48  {
49  SEVCHK(ca_clear_channel(channel), NULL);
50  TLOG(TLVL_WARNING) << "Channel \"" << name << "\" not found!";
51  channels_[name] = nullptr;
52  return false;
53  }
54  channels_[name] = channel;
55  return true;
56  }
57  return channels_[name] != nullptr;
58  }
59 
60  std::string parseChannelName_(std::string prefix_, std::string name)
61  {
62  std::string caName = name;
63  if (name.find(".")) caName = name.replace(name.find("."), 1, "_");
64  //if (!prefix_.compare("")) caName = prefix_ + "_" + caName;
65  caName = prefix_ + "_" + caName;
66  TLOG(TLVL_DEBUG) << "Channel name is: \"" << caName << "\"";
67  return caName;
68  }
69 
70 public:
76  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
77  : MetricPlugin(pset, app_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")), channels_() {}
78 
79  virtual ~EpicsMetric() { MetricPlugin::stopMetrics(); }
80 
85  std::string getLibName() const override { return "epics"; }
86 
90  void stopMetrics_() override
91  {
92  for (auto channel : channels_)
93  {
94  SEVCHK(ca_clear_channel(channel.second), NULL);
95  }
96  channels_.clear();
97  }
98 
102  void startMetrics_() override {}
103 
114  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
115  {
116  //std::string caName = prefix_ + ":" + name;
117  std::string caName = parseChannelName_(prefix_, name);
118 
119  std::string tmpValue = value + " " + unit;
120 
121  if (checkChannel_(caName))
122  {
123  // DBR_STRING, 40 characters
124  if (tmpValue.size() > 40)
125  {
126  tmpValue = tmpValue.erase(40);
127  }
128  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
129  SEVCHK(ca_flush_io(), NULL);
130  }
131  }
132 
143  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
144  {
145  // DBR_LONG
146  //std::string caName = prefix_ + ":" + name;
147  std::string caName = parseChannelName_(prefix_, name);
148 
149  if (unit.size() > 0)
150  {
151  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
152  }
153 
154  if (checkChannel_(caName))
155  {
156  dbr_long_t val = static_cast<dbr_long_t>(value);
157  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
158  SEVCHK(ca_flush_io(), NULL);
159  }
160  }
161 
172  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
173  {
174  // DBR_DOUBLE
175  //std::string caName = prefix_ + ":" + name;
176  std::string caName = parseChannelName_(prefix_, name);
177 
178  if (unit.size() > 0)
179  {
180  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
181  }
182 
183  if (checkChannel_(caName))
184  {
185  dbr_double_t val = static_cast<dbr_double_t>(value);
186  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
187  SEVCHK(ca_flush_io(), NULL);
188  }
189  }
190 
201  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
202  {
203  // DBR_FLOAT
204  //std::string caName = prefix_ + ":" + name;
205  std::string caName = parseChannelName_(prefix_, name);
206 
207  if (unit.size() > 0)
208  {
209  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
210  }
211 
212  if (checkChannel_(caName))
213  {
214  dbr_float_t val = static_cast<dbr_float_t>(value);
215  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
216  SEVCHK(ca_flush_io(), NULL);
217  }
218  }
219 
230  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
231  {
232  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
233  //std::string caName = prefix_ + ":" + name;
234  std::string caName = parseChannelName_(prefix_, name);
235 
236  if (unit.size() > 0)
237  {
238  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
239  }
240 
241  if (checkChannel_(caName))
242  {
243  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
244  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
245  SEVCHK(ca_flush_io(), NULL);
246  }
247  }
248 };
249 } // End namespace artdaq
250 
251 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
252 
253 #endif // End ifndef __EPICS_METRIC__
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Send a float metric data point to ChannelAccess.
void sendMetric_(const std::string &name, const unsigned long int &value, const std::string &unit) override
Send an unsigned integer metric data point to ChannelAccess.
An instance of the MetricPlugin class that sends metric data using the Channel Access protocol from E...
Definition: epics_metric.cc:34
void stopMetrics_() override
Clears the registered ChannelAccess channels.
Definition: epics_metric.cc:90
void startMetrics_() override
No initialization is needed to start sending metrics.
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:85
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit) override
Send a string metric data point to ChannelAccess.
EpicsMetric(fhicl::ParameterSet const &pset, std::string const &app_name)
Construct an instance of the EpicsMetric plugin.
Definition: epics_metric.cc:76
void sendMetric_(const std::string &name, const double &value, const std::string &unit) override
Send a double metric data point to ChannelAccess.
void sendMetric_(const std::string &name, const int &value, const std::string &unit) override
Send an integer metric data point to ChannelAccess.