artdaq_epics_plugin  v1_02_13
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 <utility>
12 #include "artdaq-utilities/Plugins/MetricMacros.hh"
13 #include "messagefacility/MessageLogger/MessageLogger.h"
14 #undef STATIC_ASSERT
15 
16 #ifdef __clang__
17 #pragma clang diagnostic push
18 #pragma clang diagnostic ignored "-Wunused-parameter"
19 #endif
20 #include <cadef.h>
21 #ifdef __clang__
22 #pragma clang diagnostic pop
23 #endif
24 
25 #include "TRACE/tracemf.h"
26 #define TRACE_NAME "EPICSMetric"
27 
31 namespace artdaq {
35 class EpicsMetric : public MetricPlugin
36 {
37 private:
38  std::string prefix_;
39  std::unordered_map<std::string, chid> channels_;
40 
41  bool checkChannel_(const std::string& name)
42  {
43  if (channels_.count(name) == 0u)
44  {
45  chid channel;
46  ca_search(name.c_str(), &channel);
47  auto sts = ca_pend_io(5.0);
48  if (sts != ECA_NORMAL)
49  {
50  SEVCHK(ca_clear_channel(channel), NULL);
51  TLOG(TLVL_WARNING) << "Channel \"" << name << "\" not found!";
52  channels_[name] = nullptr;
53  return false;
54  }
55  channels_[name] = channel;
56  return true;
57  }
58  return channels_[name] != nullptr;
59  }
60 
61  std::string parseChannelName_(std::string prefix_, std::string name)
62  {
63  std::string caName = std::move(name);
64  const std::string& caPrefix_ = std::move(prefix_);
65 
66  while (caName.find(' ') != std::string::npos)
67  {
68  caName = caName.replace(caName.find(' '), 1, "_");
69  }
70  while (caName.find('.') != std::string::npos)
71  {
72  caName = caName.replace(caName.find('.'), 1, ":");
73  }
74  while (caName.find('/') != std::string::npos)
75  {
76  caName = caName.replace(caName.find('/'), 1, "_");
77  }
78  while (caName.find("_%") != std::string::npos)
79  {
80  caName = caName.replace(caName.find("_%"), 2, "");
81  }
82  caName = caPrefix_ + ":" + caName;
83 
84  TLOG(TLVL_DEBUG) << "Channel name is: \"" << caName << "\"";
85  return caName;
86  }
87 
88  EpicsMetric(EpicsMetric const&) = delete;
89  EpicsMetric(EpicsMetric&&) = delete;
90  EpicsMetric& operator=(EpicsMetric const&) = delete;
91  EpicsMetric& operator=(EpicsMetric&&) = delete;
92 
93 public:
99  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
100  : MetricPlugin(pset, app_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")) {}
101 
102  ~EpicsMetric() override { MetricPlugin::stopMetrics(); }
103 
108  std::string getLibName() const override { return "epics"; }
109 
113  void stopMetrics_() override
114  {
115  for (const auto& channel : channels_)
116  {
117  if (channel.second != 0)
118  {
119  SEVCHK(ca_clear_channel(channel.second), NULL);
120  }
121  }
122  channels_.clear();
123  }
124 
128  void startMetrics_() override {}
129 
140  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
141  {
142  //std::string caName = prefix_ + ":" + name;
143  std::string caName = parseChannelName_(prefix_, name);
144 
145  std::string tmpValue = value + " " + unit;
146 
147  if (checkChannel_(caName))
148  {
149  // DBR_STRING, 40 characters
150  if (tmpValue.size() > 40)
151  {
152  tmpValue = tmpValue.erase(40);
153  }
154  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
155  SEVCHK(ca_flush_io(), NULL);
156  }
157  }
158 
169  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
170  {
171  // DBR_LONG
172  //std::string caName = prefix_ + ":" + name;
173  std::string caName = parseChannelName_(prefix_, name);
174 
175  if (!unit.empty())
176  {
177  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
178  }
179 
180  if (checkChannel_(caName))
181  {
182  auto val = static_cast<dbr_long_t>(value);
183  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
184  SEVCHK(ca_flush_io(), NULL);
185  }
186  }
187 
198  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
199  {
200  // DBR_DOUBLE
201  //std::string caName = prefix_ + ":" + name;
202  std::string caName = parseChannelName_(prefix_, name);
203 
204  if (!unit.empty())
205  {
206  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
207  }
208 
209  if (checkChannel_(caName))
210  {
211  auto val = static_cast<dbr_double_t>(value);
212  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
213  SEVCHK(ca_flush_io(), NULL);
214  }
215  }
216 
227  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
228  {
229  // DBR_FLOAT
230  //std::string caName = prefix_ + ":" + name;
231  std::string caName = parseChannelName_(prefix_, name);
232 
233  if (!unit.empty())
234  {
235  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
236  }
237 
238  if (checkChannel_(caName))
239  {
240  auto val = static_cast<dbr_float_t>(value);
241  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
242  SEVCHK(ca_flush_io(), NULL);
243  }
244  }
245 
256  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit) override
257  {
258  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
259  //std::string caName = prefix_ + ":" + name;
260  std::string caName = parseChannelName_(prefix_, name);
261 
262  if (!unit.empty())
263  {
264  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
265  }
266 
267  if (checkChannel_(caName))
268  {
269  auto val = static_cast<dbr_ulong_t>(value);
270  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
271  SEVCHK(ca_flush_io(), NULL);
272  }
273  }
274 };
275 } // End namespace artdaq
276 
277 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
278 
279 #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.
An instance of the MetricPlugin class that sends metric data using the Channel Access protocol from E...
Definition: epics_metric.cc:35
void stopMetrics_() override
Clears the registered ChannelAccess channels.
void startMetrics_() override
No initialization is needed to start sending metrics.
std::string getLibName() const override
Gets the unique library name of this plugin.
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit) override
Send an unsigned integer metric data point to ChannelAccess.
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:99
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.