API
 
Loading...
Searching...
No Matches
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
28namespace MagAOX
29{
30namespace 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 */
38class indiTSAccumulator : public MagAOXApp<true>
39{
40
41 //Give the test harness access.
43
44protected:
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
82public:
83 /// Default c'tor.
85
86 /// D'tor, declared and defined for noexcept.
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
118pcf::IndiProperty prop;
119 int setCallBack_all( const pcf::IndiProperty &ipRecv );
120
121};
122
123indiTSAccumulator::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
134int 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
244int 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;
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
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
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.
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)
const pcf::IndiProperty & ipRecv
Definition dm.hpp:24
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.