API
indiTSAccumulator.hpp
Go to the documentation of this file.
1 /** \file indiTSAccumulator.hpp
2  * \brief The MagAO-X indiTSAccumulator header file
3  *
4  * \ingroup indiTSAccumulator_files
5  */
6 
7 #ifndef indiTSAccumulator_hpp
8 #define indiTSAccumulator_hpp
9 
10 #include <map>
11 
12 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
13 #include "../../magaox_git_version.h"
14 
15 /** \defgroup indiTSAccumulator
16  * \brief The indiTSAccumulator application to do YYYYYYY
17  *
18  * <a href="../handbook/operating/software/apps/indiTSAccumulator.html">Application Documentation</a>
19  *
20  * \ingroup apps
21  *
22  */
23 
24 /** \defgroup indiTSAccumulator_files
25  * \ingroup indiTSAccumulator
26  */
27 
28 namespace MagAOX
29 {
30 namespace app
31 {
32 
33 /// The MagAO-X indiTSAccumulator
34 /** An application to accumulate a time-series from an INDI element.
35  *
36  * \ingroup indiTSAccumulator
37  */
38 class indiTSAccumulator : public MagAOXApp<true>
39 {
40 
41  //Give the test harness access.
42  friend class indiTSAccumulator_test;
43 
44 protected:
45 
46  /** \name Configurable Parameters
47  *@{
48  */
49 
50  int m_maxEntries {36000};
51 
52  ///@}
53 
54  struct element
55  {
56  std::string m_name;
57 
58  timespec m_lastUpdate {0,0};
59 
60  IMAGE * m_imageStream {nullptr};
61 
62  explicit element(const std::string & el) : m_name{el}
63  {}
64  };
65 
66  struct property
67  {
68  pcf::IndiProperty m_property;
69  std::vector<element> m_elements;
70  };
71 
72  std::map<std::string, property> m_properties;
73 
74 
75  static int st_setCallBack_all( void * app, const pcf::IndiProperty &ipRecv)
76  {
77  return static_cast<indiTSAccumulator *>(app)->setCallBack_all(ipRecv);
78  }
79 
80 
81 
82 public:
83  /// Default c'tor.
85 
86  /// D'tor, declared and defined for noexcept.
87  ~indiTSAccumulator() noexcept
88  {}
89 
90  virtual void setupConfig();
91 
92  /// Implementation of loadConfig logic, separated for testing.
93  /** This is called by loadConfig().
94  */
95  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
96 
97  virtual void loadConfig();
98 
99  /// Startup function
100  /**
101  *
102  */
103  virtual int appStartup();
104 
105  /// Implementation of the FSM for indiTSAccumulator.
106  /**
107  * \returns 0 on no critical error
108  * \returns -1 on an error requiring shutdown
109  */
110  virtual int appLogic();
111 
112  /// Shutdown the app.
113  /**
114  *
115  */
116  virtual int appShutdown();
117 
118 pcf::IndiProperty prop;
119  int setCallBack_all( const pcf::IndiProperty &ipRecv );
120 
121 };
122 
123 indiTSAccumulator::indiTSAccumulator() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
124 {
125 
126  return;
127 }
128 
130 {
131  config.add("elements", "", "elements", argType::Required, "", "elements", false, "vector<string>", "Comma separated List of elements specified as device.property.element.");
132 }
133 
134 int indiTSAccumulator::loadConfigImpl( mx::app::appConfigurator & _config )
135 {
136  std::vector<std::string> elements;
137  _config(elements, "elements");
138 
139  if(elements.size() < 1)
140  {
141  log<text_log>("no elements specified", logPrio::LOG_CRITICAL);
142  m_shutdown = true;
143  return -1;
144  }
145 
146  for(size_t n = 0; n < elements.size(); ++n)
147  {
148  size_t p1 = elements[n].find('.');
149  if(p1 == std::string::npos)
150  {
151  log<text_log>("error parsing " + elements[n] + ": no . found", logPrio::LOG_CRITICAL);
152  m_shutdown = true;
153  return -1;
154  }
155  size_t p2 = elements[n].find('.', p1+1);
156  if(p2 == std::string::npos)
157  {
158  log<text_log>("error parsing " + elements[n] + ": second . not found", logPrio::LOG_CRITICAL);
159  m_shutdown = true;
160  return -1;
161  }
162 
163  try
164  {
165  std::string devName = elements[n].substr(0,p1);
166  std::string propName = elements[n].substr(p1+1, p2-p1-1);
167  std::string elName = elements[n].substr(p2+1);
168  std::string key = devName + "." + propName;
169 
170  m_properties[key].m_property.setDevice(devName);
171  m_properties[key].m_property.setName(propName);
172  m_properties[key].m_elements.push_back(element(elName));
173  }
174  catch(const std::exception& e)
175  {
176  log<software_critical>({__FILE__, __LINE__, std::string("Exception caught: ") + e.what() + " [on element " + std::to_string(n) + "]"});
177  m_shutdown = true;
178  return -1;
179  }
180  }
181 
182  return 0;
183 }
184 
186 {
187  loadConfigImpl(config);
188 }
189 
191 {
192  for(auto it = m_properties.begin(); it != m_properties.end(); ++it)
193  {
194  //Have to make these pass-by-const-referencable
195  std::string devName = it->second.m_property.getDevice();
196  std::string propName = it->second.m_property.getName();
197  if( registerIndiPropertySet( it->second.m_property, devName, propName, st_setCallBack_all) < 0 )
198  {
199  log<software_critical>({__FILE__, __LINE__, "Error inserting property: " + devName + "." + propName});
200  return -1;
201  }
202 
203  for(size_t n=0; n < it->second.m_elements.size(); ++n)
204  {
205  it->second.m_elements[n].m_imageStream = (IMAGE *) malloc(sizeof(IMAGE));
206 
207  uint32_t imsize[3] = {0,0,0};
208  imsize[0] = 1;
209  imsize[1] = 1;
210  imsize[2] = m_maxEntries;
211  std::string shmimName = devName + "." + propName + "." + it->second.m_elements[n].m_name;
212 
213  std::cerr << "Creating: " << shmimName << " " << imsize[0] << " " << imsize[1] << " " << imsize[2] << "\n";
214 
215  ImageStreamIO_createIm_gpu(it->second.m_elements[n].m_imageStream, shmimName.c_str(), 3, imsize, IMAGESTRUCT_FLOAT, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
216 
217  it->second.m_elements[n].m_imageStream->md->cnt1 = it->second.m_elements[n].m_imageStream->md->size[2] - 1;
218 
219  it->second.m_elements[n].m_imageStream->md->atime = {0,0};
220  it->second.m_elements[n].m_imageStream->md->writetime = {0,0};
221 
222  for(size_t m = 0; m < it->second.m_elements[n].m_imageStream->md->size[2]; ++m )
223  {
224  it->second.m_elements[n].m_imageStream->cntarray[m] = std::numeric_limits<uint64_t>::max();
225  it->second.m_elements[n].m_imageStream->atimearray[m] = {0,0};
226  it->second.m_elements[n].m_imageStream->writetimearray[m] = {0,0};
227  }
228  }
229  }
230 
231  return 0;
232 }
233 
235 {
236  return 0;
237 }
238 
240 {
241  return 0;
242 }
243 
244 int indiTSAccumulator::setCallBack_all( const pcf::IndiProperty &ipRecv )
245 {
246  std::string key = ipRecv.createUniqueKey();
247  if(m_properties.count(key) > 0)
248  {
249  if(ipRecv.getType() != pcf::IndiProperty::Number)
250  {
251  log<text_log>(key + " is not a Number property. Can't time-series this.", logPrio::LOG_WARNING);
252  return -1; //only numbers are supported for now.
253  }
254 
255  //Now look for this property's elements
256  for(size_t n=0; n < m_properties[key].m_elements.size(); ++n)
257  {
258  if(!ipRecv.find( m_properties[key].m_elements[n].m_name)) continue;
259 
260  IMAGE * image = m_properties[key].m_elements[n].m_imageStream;
261 
262  if(image == nullptr)
263  {
264  log<software_error>({__FILE__, __LINE__, "Image for " + key + "." + m_properties[key].m_elements[n].m_name + " is nullptr"});
265  continue;
266  }
267 
268  timespec ts;
269  ts.tv_sec = ipRecv.getTimeStamp().getTimeValSecs();
270  ts.tv_nsec = ipRecv.getTimeStamp().getTimeValMicros()*1000;
271 
272  if(ts.tv_sec != image->md->atime.tv_sec || ts.tv_nsec != image->md->atime.tv_nsec)
273  {
274  //Get the value as a float
275  float val = ipRecv[ m_properties[key].m_elements[n].m_name].get<float>();
276 
277  //Get cnt1 and rollover if needed
278  uint64_t cnt1 = image->md->cnt1 + 1;
279  if(cnt1 >= image->md->size[2]) cnt1 = 0;
280 
281  //Set the writing flag
282  image->md->write=1;
283 
284  //Set the times
285  clock_gettime(CLOCK_REALTIME, &image->md->writetime);
286  image->writetimearray[cnt1] = image->md->writetime;
287 
288  image->md->atime = ts;
289  image->atimearray[cnt1] = ts;
290 
291  //Set the value
292  image->array.F[cnt1] = val;
293 
294  //Now update counters
295  image->md->cnt0++;
296  image->cntarray[cnt1] = image->md->cnt0;
297  image->md->cnt1 = cnt1;
298 
299  //And post
300  image->md->write=0;
301  ImageStreamIO_sempost(image,-1);
302  std::cerr << ipRecv.createUniqueKey() << " " << ts.tv_sec << " " << ts.tv_nsec << "\n";
303  }
304  }
305  }
306 
307  return 0;
308 }
309 
310 } //namespace app
311 } //namespace MagAOX
312 
313 #endif //indiTSAccumulator_hpp
#define IMAGESTRUCT_FLOAT
Definition: ImageStruct.hpp:22
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
Definition: MagAOXApp.hpp:102
int registerIndiPropertySet(pcf::IndiProperty &prop, const std::string &devName, const std::string &propName, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is monitored for updates from others.
Definition: MagAOXApp.hpp:2569
The MagAO-X indiTSAccumulator.
virtual int appStartup()
Startup function.
int setCallBack_all(const pcf::IndiProperty &ipRecv)
~indiTSAccumulator() noexcept
D'tor, declared and defined for noexcept.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
virtual int appLogic()
Implementation of the FSM for indiTSAccumulator.
std::map< std::string, property > m_properties
virtual int appShutdown()
Shutdown the app.
static int st_setCallBack_all(void *app, const pcf::IndiProperty &ipRecv)
std::ostream & cerr()
const pcf::IndiProperty & ipRecv
Definition: dm.hpp:24
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
Definition: logPriority.hpp:37
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
Definition: logPriority.hpp:43