artdaq_epics_plugin  v1_02_08
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 "artdaq-utilities/Plugins/MetricMacros.hh"
11 #include "messagefacility/MessageLogger/MessageLogger.h"
12 #include <unordered_map>
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 
27 namespace artdaq
28 {
32  class EpicsMetric : public MetricPlugin
33  {
34  private:
35  std::string prefix_;
36  std::unordered_map<std::string, chid> channels_;
37 
38  bool checkChannel_(std::string name)
39  {
40  if (!channels_.count(name))
41  {
42  chid channel;
43  ca_search(name.c_str(), &channel);
44  auto sts = ca_pend_io(5.0);
45  if (sts != ECA_NORMAL)
46  {
47  SEVCHK(ca_clear_channel(channel), NULL);
48  mf::LogWarning("EPICS Plugin") << "Channel " << name << " not found!";
49  channels_[name] = nullptr;
50  return false;
51  }
52  channels_[name] = channel;
53  return true;
54  }
55  return channels_[name] != nullptr;
56  }
57 
58  public:
64  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
65  : MetricPlugin(pset, app_name)
66  , prefix_(pset.get<std::string>("channel_name_prefix", "artdaq"))
67  , channels_() {}
68 
69  virtual ~EpicsMetric()
70  {
71  MetricPlugin::stopMetrics();
72  }
73 
78  std::string getLibName() const override { return "epics"; }
79 
83  void stopMetrics_() override
84  {
85  for (auto channel : channels_)
86  {
87  SEVCHK(ca_clear_channel(channel.second), NULL);
88  }
89  channels_.clear();
90  }
91 
95  void startMetrics_() override {}
96 
107  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
108  {
109  std::string caName = prefix_ + ":" + name;
110  std::string tmpValue = value + " " + unit;
111 
112  if (checkChannel_(caName))
113  {
114  //DBR_STRING, 40 characters
115  if (tmpValue.size() > 40) { tmpValue = tmpValue.erase(40); }
116  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
117  SEVCHK(ca_flush_io(), NULL);
118  }
119  }
120 
131  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
132  {
133  //DBR_LONG
134  std::string caName = prefix_ + ":" + name;
135  if (unit.size() > 0)
136  {
137  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
138  }
139 
140  if (checkChannel_(caName))
141  {
142  dbr_long_t val = static_cast<dbr_long_t>(value);
143  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
144  SEVCHK(ca_flush_io(), NULL);
145  }
146  }
147 
158  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
159  {
160  //DBR_DOUBLE
161  std::string caName = prefix_ + ":" + name;
162  if (unit.size() > 0)
163  {
164  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
165  }
166 
167  if (checkChannel_(caName))
168  {
169  dbr_double_t val = static_cast<dbr_double_t>(value);
170  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
171  SEVCHK(ca_flush_io(), NULL);
172  }
173  }
174 
185  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
186  {
187  //DBR_FLOAT
188  std::string caName = prefix_ + ":" + name;
189  if (unit.size() > 0)
190  {
191  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
192  }
193 
194  if (checkChannel_(caName))
195  {
196  dbr_float_t val = static_cast<dbr_float_t>(value);
197  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
198  SEVCHK(ca_flush_io(), NULL);
199  }
200  }
201 
212  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
213  {
214  //DBR_LONG, only unsigned type is only 16 bits, use widest integral field
215  std::string caName = prefix_ + ":" + name;
216  if (unit.size() > 0)
217  {
218  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
219  }
220 
221  if (checkChannel_(caName))
222  {
223  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
224  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
225  SEVCHK(ca_flush_io(), NULL);
226  }
227  }
228  };
229 } //End namespace artdaq
230 
231 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
232 
233 #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:32
void stopMetrics_() override
Clears the registered ChannelAccess channels.
Definition: epics_metric.cc:83
void startMetrics_() override
No initialization is needed to start sending metrics.
Definition: epics_metric.cc:95
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:78
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:64
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.