artdaq_epics_plugin  v1_02_02
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 #include <cadef.h>
15 
19 namespace artdaq
20 {
24  class EpicsMetric : public MetricPlugin
25  {
26  private:
27  std::string prefix_;
28  std::unordered_map<std::string, chid> channels_;
29 
30  bool checkChannel_(std::string name)
31  {
32  if (!channels_.count(name))
33  {
34  chid channel;
35  auto sts = ca_search(name.c_str(), &channel);
36  sts = ca_pend_io(5.0);
37  if (sts != ECA_NORMAL)
38  {
39  SEVCHK(ca_clear_channel(channel), NULL);
40  mf::LogWarning("EPICS Plugin") << "Channel " << name << " not found!";
41  channels_[name] = nullptr;
42  return false;
43  }
44  channels_[name] = channel;
45  return true;
46  }
47  return channels_[name] != nullptr;
48  }
49 
50  public:
55  explicit EpicsMetric(fhicl::ParameterSet pset)
56  : MetricPlugin(pset)
57  , prefix_(pset.get<std::string>("channel_name_prefix", "artdaq"))
58  , channels_() {}
59 
60  virtual ~EpicsMetric()
61  {
62  MetricPlugin::stopMetrics();
63  }
64 
69  std::string getLibName() const override { return "epics"; }
70 
74  void stopMetrics_() override
75  {
76  for (auto channel : channels_)
77  {
78  SEVCHK(ca_clear_channel(channel.second), NULL);
79  }
80  channels_.clear();
81  }
82 
86  void startMetrics_() override {}
87 
98  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
99  {
100  std::string caName = prefix_ + ":" + name;
101  std::string tmpValue = value + " " + unit;
102 
103  if (checkChannel_(caName))
104  {
105  //DBR_STRING, 40 characters
106  if (tmpValue.size() > 40) { tmpValue = tmpValue.erase(40); }
107  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
108  SEVCHK(ca_flush_io(), NULL);
109  }
110  }
111 
122  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
123  {
124  //DBR_LONG
125  std::string caName = prefix_ + ":" + name;
126  if (unit.size() > 0)
127  {
128  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
129  }
130 
131  if (checkChannel_(caName))
132  {
133  dbr_long_t val = static_cast<dbr_long_t>(value);
134  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
135  SEVCHK(ca_flush_io(), NULL);
136  }
137  }
138 
149  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
150  {
151  //DBR_DOUBLE
152  std::string caName = prefix_ + ":" + name;
153  if (unit.size() > 0)
154  {
155  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
156  }
157 
158  if (checkChannel_(caName))
159  {
160  dbr_double_t val = static_cast<dbr_double_t>(value);
161  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
162  SEVCHK(ca_flush_io(), NULL);
163  }
164  }
165 
176  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
177  {
178  //DBR_FLOAT
179  std::string caName = prefix_ + ":" + name;
180  if (unit.size() > 0)
181  {
182  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
183  }
184 
185  if (checkChannel_(caName))
186  {
187  dbr_float_t val = static_cast<dbr_float_t>(value);
188  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
189  SEVCHK(ca_flush_io(), NULL);
190  }
191  }
192 
203  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
204  {
205  //DBR_LONG, only unsigned type is only 16 bits, use widest integral field
206  std::string caName = prefix_ + ":" + name;
207  if (unit.size() > 0)
208  {
209  mf::LogDebug("EPICS Plugin") << "Not sure if I can send ChannelAccess Units...configure in db instead.";
210  }
211 
212  if (checkChannel_(caName))
213  {
214  dbr_ulong_t val = static_cast<dbr_ulong_t>(value);
215  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
216  SEVCHK(ca_flush_io(), NULL);
217  }
218  }
219  };
220 } //End namespace artdaq
221 
222 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
223 
224 #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:24
void stopMetrics_() override
Clears the registered ChannelAccess channels.
Definition: epics_metric.cc:74
void startMetrics_() override
No initialization is needed to start sending metrics.
Definition: epics_metric.cc:86
std::string getLibName() const override
Gets the unique library name of this plugin.
Definition: epics_metric.cc:69
EpicsMetric(fhicl::ParameterSet pset)
Construct an instance of the EpicsMetric plugin.
Definition: epics_metric.cc:55
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:98
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.