Line data Source code
1 : /** \file streamCircBuff.hpp
2 : * \brief The MagAO-X streamCircBuff app header file
3 : *
4 : * \ingroup streamCircBuff_files
5 : */
6 :
7 : #ifndef streamCircBuff_hpp
8 : #define streamCircBuff_hpp
9 :
10 :
11 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12 : #include "../../magaox_git_version.h"
13 :
14 : /** \defgroup streamCircBuff
15 : * \brief An application to keep a circular buffer of a stream
16 : *
17 : * <a href="../handbook/operating/software/apps/streamCircBuff.html">Application Documentation</a>
18 : *
19 : * \ingroup apps
20 : *
21 : */
22 :
23 : /** \defgroup streamCircBuff_files
24 : * \ingroup streamCircBuff
25 : */
26 :
27 : namespace MagAOX
28 : {
29 : namespace app
30 : {
31 :
32 : /// Class for application to keep a circular buffer of a stream and publish it to another stream
33 : /**
34 : * \ingroup streamCircBuff
35 : */
36 : class streamCircBuff : public MagAOXApp<true>,
37 : public dev::shmimMonitor<streamCircBuff>,
38 : public dev::frameGrabber<streamCircBuff>,
39 : public dev::telemeter<streamCircBuff>
40 : {
41 : friend class dev::shmimMonitor<streamCircBuff>;
42 : friend class dev::frameGrabber<streamCircBuff>;
43 : friend class dev::telemeter<streamCircBuff>;
44 :
45 : public:
46 :
47 : /** \name app::dev Configurations
48 : *@{
49 : */
50 :
51 : static constexpr bool c_frameGrabber_flippable = false; ///< app:dev config to tell framegrabber these images can not be flipped
52 :
53 : ///@}
54 :
55 : typedef float realT;
56 :
57 : /// The base shmimMonitor type
58 : typedef dev::shmimMonitor<streamCircBuff> shmimMonitorT;
59 :
60 : /// The base frameGrabber type
61 : typedef dev::frameGrabber<streamCircBuff> frameGrabberT;
62 :
63 : /// The telemeter type
64 : typedef dev::telemeter<streamCircBuff> telemeterT;
65 :
66 :
67 : protected:
68 :
69 : /** \name Configurable Parameters
70 : *@{
71 : */
72 : ///@}
73 :
74 : char * m_currSrc {nullptr};
75 :
76 : sem_t m_smSemaphore {0}; ///< Semaphore used to synchronize the fg thread and the sm thread.
77 :
78 : public:
79 : /// Default c'tor.
80 : streamCircBuff();
81 :
82 : /// D'tor, declared and defined for noexcept.
83 0 : ~streamCircBuff() noexcept
84 0 : {}
85 :
86 : virtual void setupConfig();
87 :
88 : /// Implementation of loadConfig logic, separated for testing.
89 : /** This is called by loadConfig().
90 : */
91 : int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
92 :
93 : virtual void loadConfig();
94 :
95 : /// Startup function
96 : /**
97 : *
98 : */
99 : virtual int appStartup();
100 :
101 : /// Implementation of the FSM for streamCircBuff.
102 : /**
103 : * \returns 0 on no critical error
104 : * \returns -1 on an error requiring shutdown
105 : */
106 : virtual int appLogic();
107 :
108 : /// Shutdown the app.
109 : /**
110 : *
111 : */
112 : virtual int appShutdown();
113 :
114 :
115 : protected:
116 :
117 : float (*pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as float
118 :
119 : //shmimMonitor Interface
120 : int allocate( const dev::shmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
121 :
122 : int allocatePSDStreams();
123 :
124 : int processImage( void * curr_src, ///< [in] pointer to start of current frame.
125 : const dev::shmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
126 : );
127 :
128 : /** \name dev::frameGrabber interface
129 : *
130 : * @{
131 : */
132 :
133 : /// Implementation of the framegrabber configureAcquisition interface
134 : /**
135 : * \returns 0 on success
136 : * \returns -1 on error
137 : */
138 : int configureAcquisition();
139 :
140 : /// Implementation of the framegrabber fps interface
141 : /**
142 : * \todo this needs to infer the stream fps and return it
143 : */
144 0 : float fps()
145 : {
146 0 : return 1.0;
147 : }
148 :
149 : /// Implementation of the framegrabber startAcquisition interface
150 : /**
151 : * \returns 0 on success
152 : * \returns -1 on error
153 : */
154 : int startAcquisition();
155 :
156 : /// Implementation of the framegrabber acquireAndCheckValid interface
157 : /**
158 : * \returns 0 on success
159 : * \returns -1 on error
160 : */
161 : int acquireAndCheckValid();
162 :
163 : /// Implementation of the framegrabber loadImageIntoStream interface
164 : /**
165 : * \returns 0 on success
166 : * \returns -1 on error
167 : */
168 : int loadImageIntoStream( void * dest /**< [in] */);
169 :
170 : /// Implementation of the framegrabber reconfig interface
171 : /**
172 : * \returns 0 on success
173 : * \returns -1 on error
174 : */
175 : int reconfig();
176 :
177 : /** \name Telemeter Interface
178 : *
179 : * @{
180 : */
181 : int checkRecordTimes();
182 :
183 : int recordTelem( const telem_fgtimings * );
184 :
185 : ///@}
186 :
187 : };
188 :
189 0 : streamCircBuff::streamCircBuff() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
190 : {
191 :
192 0 : return;
193 0 : }
194 :
195 0 : void streamCircBuff::setupConfig()
196 : {
197 0 : SHMIMMONITOR_SETUP_CONFIG(config);
198 :
199 0 : FRAMEGRABBER_SETUP_CONFIG(config);
200 :
201 0 : TELEMETER_SETUP_CONFIG(config);
202 :
203 : }
204 :
205 0 : int streamCircBuff::loadConfigImpl( mx::app::appConfigurator & _config )
206 : {
207 0 : SHMIMMONITOR_LOAD_CONFIG(_config);
208 :
209 0 : FRAMEGRABBER_LOAD_CONFIG(_config);
210 :
211 0 : TELEMETER_LOAD_CONFIG(config);
212 :
213 0 : return 0;
214 : }
215 :
216 0 : void streamCircBuff::loadConfig()
217 : {
218 0 : loadConfigImpl(config);
219 0 : }
220 :
221 0 : int streamCircBuff::appStartup()
222 : {
223 0 : if(sem_init(&m_smSemaphore, 0,0) < 0)
224 : {
225 0 : log<software_critical>({__FILE__, __LINE__, errno,0, "Initializing S.M. semaphore"});
226 0 : return -1;
227 : }
228 :
229 0 : SHMIMMONITOR_APP_STARTUP;
230 :
231 0 : FRAMEGRABBER_APP_STARTUP;
232 :
233 0 : TELEMETER_APP_STARTUP;
234 :
235 0 : state(stateCodes::OPERATING);
236 :
237 0 : return 0;
238 : }
239 :
240 0 : int streamCircBuff::appLogic()
241 : {
242 0 : SHMIMMONITOR_APP_LOGIC;
243 :
244 0 : FRAMEGRABBER_APP_LOGIC;
245 :
246 0 : TELEMETER_APP_LOGIC;
247 :
248 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
249 :
250 0 : SHMIMMONITOR_UPDATE_INDI;
251 :
252 0 : FRAMEGRABBER_UPDATE_INDI;
253 :
254 0 : return 0;
255 0 : }
256 :
257 0 : int streamCircBuff::appShutdown()
258 : {
259 0 : SHMIMMONITOR_APP_SHUTDOWN;
260 0 : FRAMEGRABBER_APP_SHUTDOWN;
261 0 : TELEMETER_APP_SHUTDOWN;
262 :
263 0 : return 0;
264 : }
265 :
266 0 : int streamCircBuff::allocate( const dev::shmimT & dummy)
267 : {
268 : static_cast<void>(dummy);
269 :
270 : //we don't actually do anything here -- just a pass through to f.g.
271 :
272 0 : pixget = getPixPointer<float>(shmimMonitorT::m_dataType);
273 :
274 0 : m_reconfig = true;
275 :
276 0 : return 0;
277 : }
278 :
279 0 : int streamCircBuff::processImage( void * curr_src,
280 : const dev::shmimT & dummy
281 : )
282 : {
283 : static_cast<void>(dummy);
284 :
285 0 : m_currSrc = static_cast<char *>(curr_src);
286 :
287 : //Now tell the f.g. to get going
288 0 : if(sem_post(&m_smSemaphore) < 0)
289 : {
290 0 : log<software_critical>({__FILE__, __LINE__, errno, 0, "Error posting to semaphore"});
291 0 : return -1;
292 : }
293 :
294 0 : return 0;
295 : }
296 :
297 0 : int streamCircBuff::configureAcquisition()
298 : {
299 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
300 :
301 : ///\todo potential but verrrrry unlikely bug: shmimMonitorT could change these before allocate sets the lock above. Should use a local set of w/h instead.
302 0 : if(shmimMonitorT::m_width==0 || shmimMonitorT::m_height==0)
303 : {
304 : //This means we haven't connected to the stream to accumulate. so wait.
305 0 : lock.unlock(); //don't hold the lock for a whole second.
306 0 : sleep(1);
307 0 : return -1;
308 : }
309 :
310 0 : frameGrabberT::m_width = shmimMonitorT::m_width;
311 0 : frameGrabberT::m_height = shmimMonitorT::m_height;
312 0 : frameGrabberT::m_dataType = IMAGESTRUCT_FLOAT;
313 :
314 0 : return 0;
315 0 : }
316 :
317 0 : int streamCircBuff::startAcquisition()
318 : {
319 0 : return 0;
320 : }
321 :
322 0 : int streamCircBuff::acquireAndCheckValid()
323 : {
324 : timespec ts;
325 :
326 0 : if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
327 : {
328 0 : log<software_critical>({__FILE__,__LINE__,errno,0,"clock_gettime"});
329 0 : return -1;
330 : }
331 :
332 0 : ts.tv_sec += 1;
333 :
334 0 : if(sem_timedwait(&m_smSemaphore, &ts) == 0)
335 : {
336 0 : clock_gettime(CLOCK_REALTIME, &m_currImageTimestamp);
337 0 : return 0;
338 : }
339 : else
340 : {
341 0 : return 1;
342 : }
343 :
344 : if(m_currSrc == nullptr)
345 : {
346 : return 1;
347 : }
348 : }
349 :
350 0 : int streamCircBuff::loadImageIntoStream(void * dest)
351 : {
352 0 : if(m_currSrc == nullptr)
353 : {
354 0 : return -1;
355 : }
356 :
357 0 : float * fdest = reinterpret_cast<float *>(dest);
358 :
359 0 : for(size_t n = 0; n < shmimMonitorT::m_width*shmimMonitorT::m_height; ++n)
360 : {
361 0 : fdest[n] = pixget(m_currSrc,n);
362 : }
363 :
364 : //memcpy(dest, m_currSrc, shmimMonitorT::m_width*shmimMonitorT::m_height*frameGrabberT::m_typeSize );
365 0 : return 0;
366 : }
367 :
368 0 : int streamCircBuff::reconfig()
369 : {
370 0 : return 0;
371 : }
372 :
373 0 : int streamCircBuff::checkRecordTimes()
374 : {
375 0 : return telemeterT::checkRecordTimes(telem_fgtimings());
376 : }
377 :
378 0 : int streamCircBuff::recordTelem( const telem_fgtimings * )
379 : {
380 0 : return recordFGTimings(true);
381 : }
382 :
383 :
384 : } //namespace app
385 : } //namespace MagAOX
386 :
387 : #endif //streamCircBuff_hpp
|