artdaq_epics_plugin  v1_02_08a
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 
27 namespace artdaq {
31 class EpicsMetric : public MetricPlugin {
32  private:
33  std::string prefix_;
34  std::unordered_map<std::string, chid> channels_;
35 
36  bool checkChannel_(std::string name) {
37  if (!channels_.count(name)) {
38  chid channel;
39  ca_search(name.c_str(), &channel);
40  auto sts = ca_pend_io(5.0);
41  if (sts != ECA_NORMAL) {
42  SEVCHK(ca_clear_channel(channel), NULL);
43  mf::LogWarning("EPICS Plugin") << "Channel " << name << " not found!";
44  channels_[name] = nullptr;
45  return false;
46  }
47  channels_[name] = channel;
48  return true;
49  }
50  return channels_[name] != nullptr;
51  }
52 
53  public:
59  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
60  : MetricPlugin(pset, app_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")), channels_() {}
61 
62  virtual ~EpicsMetric() { MetricPlugin::stopMetrics(); }
63 
68  std::string getLibName() const override { return "epics"; }
69 
73  void stopMetrics_() override {
74  for (auto channel : channels_) {
75  SEVCHK(ca_clear_channel(channel.second), NULL);
76  }
77  channels_.clear();
78  }
79 
83  void startMetrics_() override {}
84 
95  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override {
96  std::string caName = prefix_ + ":" + name;
97  std::string tmpValue = value + " " + unit;
98 
99  if (checkChannel_(caName)) {
100  // DBR_STRING, 40 characters
101  if (tmpValue.size() > 40) {
102  tmpValue = tmpValue.erase(40);
103  }
104  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
105  SEVCHK(ca_flush_io(), NULL);
106  }
107  }
108 
119  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override {
120  // DBR_LONG
121  std::string caName = prefix_ + ":" + name;
122  if (unit.size() > 0) {
123  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
124  }
125 
126  if (checkChannel_(caName)) {
127  dbr_long_t val = static_cast<dbr_long_t>(value);
128  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
129  SEVCHK(ca_flush_io(), NULL);
130  }
131  }
132 
143  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override {
144  // DBR_DOUBLE
145  std::string caName = prefix_ + ":" + name;
146  if (unit.size() > 0) {
147  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
148  }
149 
150  if (checkChannel_(caName)) {
151  dbr_double_t val = static_cast<dbr_double_t>(value);
152  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
153  SEVCHK(ca_flush_io(), NULL);
154  }
155  }
156 
167  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override {
168  // DBR_FLOAT
169  std::string caName = prefix_ + ":" + name;
170  if (unit.size() > 0) {
171  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
172  }
173 
174  if (checkChannel_(caName)) {
175  dbr_float_t val = static_cast<dbr_float_t>(value);
176  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
177  SEVCHK(ca_flush_io(), NULL);
178  }
179  }
180 
191  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override {
192  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
193  std::string caName = prefix_ + ":" + name;
194  if (unit.size() > 0) {
195  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
196  }
197 
198  if (checkChannel_(caName)) {
199  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
200  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
201  SEVCHK(ca_flush_io(), NULL);
202  }
203  }
204 };
205 } // End namespace artdaq
206 
207 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
208 
209 #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:31
void stopMetrics_() override
Clears the registered ChannelAccess channels.
Definition: epics_metric.cc:73
void startMetrics_() override
No initialization is needed to start sending metrics.
Definition: epics_metric.cc:83
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:68
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit) override
Send a string metric data point to ChannelAccess.
Definition: epics_metric.cc:95
EpicsMetric(fhicl::ParameterSet const &pset, std::string const &app_name)
Construct an instance of the EpicsMetric plugin.
Definition: epics_metric.cc:59
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.