artdaq_epics_plugin  v1_02_14
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 #elif __GNUC__ > 9
20 #pragma GCC diagnostic push
21 #pragma GCC diagnostic ignored "-Wdeprecated-copy"
22 #endif
23 #include <cadef.h>
24 #ifdef __clang__
25 #pragma clang diagnostic pop
26 #elif __GNUC__ > 9
27 #pragma GCC diagnostic pop
28 #endif
29 
30 #include "TRACE/tracemf.h"
31 #define TRACE_NAME "EPICSMetric"
32 
36 namespace artdaq {
40 class EpicsMetric : public MetricPlugin
41 {
42 private:
43  std::string prefix_;
44  std::unordered_map<std::string, chid> channels_;
45 
46  bool checkChannel_(const std::string& name)
47  {
48  if (channels_.count(name) == 0u)
49  {
50  chid channel;
51  ca_search(name.c_str(), &channel);
52  auto sts = ca_pend_io(5.0);
53  if (sts != ECA_NORMAL)
54  {
55  SEVCHK(ca_clear_channel(channel), NULL);
56  TLOG(TLVL_WARNING) << "Channel \"" << name << "\" not found!";
57  channels_[name] = nullptr;
58  return false;
59  }
60  channels_[name] = channel;
61  return true;
62  }
63  return channels_[name] != nullptr;
64  }
65 
66  std::string parseChannelName_(std::string prefix_, std::string name)
67  {
68  std::string caName = std::move(name);
69  const std::string& caPrefix_ = std::move(prefix_);
70 
71  while (caName.find(' ') != std::string::npos)
72  {
73  caName = caName.replace(caName.find(' '), 1, "_");
74  }
75  while (caName.find('.') != std::string::npos)
76  {
77  caName = caName.replace(caName.find('.'), 1, ":");
78  }
79  while (caName.find('/') != std::string::npos)
80  {
81  caName = caName.replace(caName.find('/'), 1, "_");
82  }
83  while (caName.find("_%") != std::string::npos)
84  {
85  caName = caName.replace(caName.find("_%"), 2, "");
86  }
87  caName = caPrefix_ + ":" + caName;
88 
89  TLOG(TLVL_DEBUG) << "Channel name is: \"" << caName << "\"";
90  return caName;
91  }
92 
93  EpicsMetric(EpicsMetric const&) = delete;
94  EpicsMetric(EpicsMetric&&) = delete;
95  EpicsMetric& operator=(EpicsMetric const&) = delete;
96  EpicsMetric& operator=(EpicsMetric&&) = delete;
97 
98 public:
104  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
105  : MetricPlugin(pset, app_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")) {}
106 
107  ~EpicsMetric() override { MetricPlugin::stopMetrics(); }
108 
113  std::string getLibName() const override { return "epics"; }
114 
118  void stopMetrics_() override
119  {
120  for (const auto& channel : channels_)
121  {
122  if (channel.second != 0)
123  {
124  SEVCHK(ca_clear_channel(channel.second), NULL);
125  }
126  }
127  channels_.clear();
128  }
129 
133  void startMetrics_() override {}
134 
145  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
146  {
147  //std::string caName = prefix_ + ":" + name;
148  std::string caName = parseChannelName_(prefix_, name);
149 
150  std::string tmpValue = value + " " + unit;
151 
152  if (checkChannel_(caName))
153  {
154  // DBR_STRING, 40 characters
155  if (tmpValue.size() > 40)
156  {
157  tmpValue = tmpValue.erase(40);
158  }
159  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
160  SEVCHK(ca_flush_io(), NULL);
161  }
162  }
163 
174  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
175  {
176  // DBR_LONG
177  //std::string caName = prefix_ + ":" + name;
178  std::string caName = parseChannelName_(prefix_, name);
179 
180  if (!unit.empty())
181  {
182  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
183  }
184 
185  if (checkChannel_(caName))
186  {
187  auto val = static_cast<dbr_long_t>(value);
188  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
189  SEVCHK(ca_flush_io(), NULL);
190  }
191  }
192 
203  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
204  {
205  // DBR_DOUBLE
206  //std::string caName = prefix_ + ":" + name;
207  std::string caName = parseChannelName_(prefix_, name);
208 
209  if (!unit.empty())
210  {
211  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
212  }
213 
214  if (checkChannel_(caName))
215  {
216  auto val = static_cast<dbr_double_t>(value);
217  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
218  SEVCHK(ca_flush_io(), NULL);
219  }
220  }
221 
232  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
233  {
234  // DBR_FLOAT
235  //std::string caName = prefix_ + ":" + name;
236  std::string caName = parseChannelName_(prefix_, name);
237 
238  if (!unit.empty())
239  {
240  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
241  }
242 
243  if (checkChannel_(caName))
244  {
245  auto val = static_cast<dbr_float_t>(value);
246  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
247  SEVCHK(ca_flush_io(), NULL);
248  }
249  }
250 
261  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit) override
262  {
263  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
264  //std::string caName = prefix_ + ":" + name;
265  std::string caName = parseChannelName_(prefix_, name);
266 
267  if (!unit.empty())
268  {
269  TLOG(TLVL_DEBUG) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
270  }
271 
272  if (checkChannel_(caName))
273  {
274  auto val = static_cast<dbr_ulong_t>(value);
275  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
276  SEVCHK(ca_flush_io(), NULL);
277  }
278  }
279 };
280 } // End namespace artdaq
281 
282 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
283 
284 #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:40
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.
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.