artdaq_epics_plugin  v1_02_04
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  auto sts = ca_search(name.c_str(), &channel);
44  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:
63  explicit EpicsMetric(fhicl::ParameterSet pset)
64  : MetricPlugin(pset)
65  , prefix_(pset.get<std::string>("channel_name_prefix", "artdaq"))
66  , channels_() {}
67 
68  virtual ~EpicsMetric()
69  {
70  MetricPlugin::stopMetrics();
71  }
72 
77  std::string getLibName() const override { return "epics"; }
78 
82  void stopMetrics_() override
83  {
84  for (auto channel : channels_)
85  {
86  SEVCHK(ca_clear_channel(channel.second), NULL);
87  }
88  channels_.clear();
89  }
90 
94  void startMetrics_() override {}
95 
106  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
107  {
108  std::string caName = prefix_ + ":" + name;
109  std::string tmpValue = value + " " + unit;
110 
111  if (checkChannel_(caName))
112  {
113  //DBR_STRING, 40 characters
114  if (tmpValue.size() > 40) { tmpValue = tmpValue.erase(40); }
115  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
116  SEVCHK(ca_flush_io(), NULL);
117  }
118  }
119 
130  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
131  {
132  //DBR_LONG
133  std::string caName = prefix_ + ":" + name;
134  if (unit.size() > 0)
135  {
136  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
137  }
138 
139  if (checkChannel_(caName))
140  {
141  dbr_long_t val = static_cast<dbr_long_t>(value);
142  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
143  SEVCHK(ca_flush_io(), NULL);
144  }
145  }
146 
157  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
158  {
159  //DBR_DOUBLE
160  std::string caName = prefix_ + ":" + name;
161  if (unit.size() > 0)
162  {
163  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
164  }
165 
166  if (checkChannel_(caName))
167  {
168  dbr_double_t val = static_cast<dbr_double_t>(value);
169  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
170  SEVCHK(ca_flush_io(), NULL);
171  }
172  }
173 
184  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
185  {
186  //DBR_FLOAT
187  std::string caName = prefix_ + ":" + name;
188  if (unit.size() > 0)
189  {
190  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
191  }
192 
193  if (checkChannel_(caName))
194  {
195  dbr_float_t val = static_cast<dbr_float_t>(value);
196  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
197  SEVCHK(ca_flush_io(), NULL);
198  }
199  }
200 
211  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
212  {
213  //DBR_LONG, only unsigned type is only 16 bits, use widest integral field
214  std::string caName = prefix_ + ":" + name;
215  if (unit.size() > 0)
216  {
217  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
218  }
219 
220  if (checkChannel_(caName))
221  {
222  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
223  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
224  SEVCHK(ca_flush_io(), NULL);
225  }
226  }
227  };
228 } //End namespace artdaq
229 
230 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
231 
232 #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:82
void startMetrics_() override
No initialization is needed to start sending metrics.
Definition: epics_metric.cc:94
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:77
EpicsMetric(fhicl::ParameterSet pset)
Construct an instance of the EpicsMetric plugin.
Definition: epics_metric.cc:63
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit) override
Send a string metric data point to ChannelAccess.
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.