artdaq_epics_plugin  v1_02_09
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 {
33 private:
34  std::string prefix_;
35  std::unordered_map<std::string, chid> channels_;
36 
37  bool checkChannel_(std::string name)
38  {
39  if (!channels_.count(name))
40  {
41  chid channel;
42  ca_search(name.c_str(), &channel);
43  auto sts = ca_pend_io(5.0);
44  if (sts != ECA_NORMAL)
45  {
46  SEVCHK(ca_clear_channel(channel), NULL);
47  mf::LogWarning("EPICS Plugin") << "Channel " << name << " not found!";
48  channels_[name] = nullptr;
49  return false;
50  }
51  channels_[name] = channel;
52  return true;
53  }
54  return channels_[name] != nullptr;
55  }
56 
57 public:
63  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
64  : MetricPlugin(pset, app_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")), channels_() {}
65 
66  virtual ~EpicsMetric() { MetricPlugin::stopMetrics(); }
67 
72  std::string getLibName() const override { return "epics"; }
73 
77  void stopMetrics_() override
78  {
79  for (auto channel : channels_)
80  {
81  SEVCHK(ca_clear_channel(channel.second), NULL);
82  }
83  channels_.clear();
84  }
85 
89  void startMetrics_() override {}
90 
101  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
102  {
103  std::string caName = prefix_ + ":" + name;
104  std::string tmpValue = value + " " + unit;
105 
106  if (checkChannel_(caName))
107  {
108  // DBR_STRING, 40 characters
109  if (tmpValue.size() > 40)
110  {
111  tmpValue = tmpValue.erase(40);
112  }
113  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
114  SEVCHK(ca_flush_io(), NULL);
115  }
116  }
117 
128  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
129  {
130  // DBR_LONG
131  std::string caName = prefix_ + ":" + name;
132  if (unit.size() > 0)
133  {
134  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
135  }
136 
137  if (checkChannel_(caName))
138  {
139  dbr_long_t val = static_cast<dbr_long_t>(value);
140  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
141  SEVCHK(ca_flush_io(), NULL);
142  }
143  }
144 
155  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
156  {
157  // DBR_DOUBLE
158  std::string caName = prefix_ + ":" + name;
159  if (unit.size() > 0)
160  {
161  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
162  }
163 
164  if (checkChannel_(caName))
165  {
166  dbr_double_t val = static_cast<dbr_double_t>(value);
167  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
168  SEVCHK(ca_flush_io(), NULL);
169  }
170  }
171 
182  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
183  {
184  // DBR_FLOAT
185  std::string caName = prefix_ + ":" + name;
186  if (unit.size() > 0)
187  {
188  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
189  }
190 
191  if (checkChannel_(caName))
192  {
193  dbr_float_t val = static_cast<dbr_float_t>(value);
194  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
195  SEVCHK(ca_flush_io(), NULL);
196  }
197  }
198 
209  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
210  {
211  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
212  std::string caName = prefix_ + ":" + name;
213  if (unit.size() > 0)
214  {
215  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
216  }
217 
218  if (checkChannel_(caName))
219  {
220  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
221  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
222  SEVCHK(ca_flush_io(), NULL);
223  }
224  }
225 };
226 } // End namespace artdaq
227 
228 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
229 
230 #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:77
void startMetrics_() override
No initialization is needed to start sending metrics.
Definition: epics_metric.cc:89
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:72
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:63
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.