API
 
Loading...
Searching...
No Matches
pvcamCtrl.hpp
Go to the documentation of this file.
1/** \file pvcamCtrl.hpp
2 * \brief The MagAO-X pvcam controller header file
3 *
4 * \ingroup pvcamCtrl_files
5 */
6
7#ifndef pvcamCtrl_hpp
8#define pvcamCtrl_hpp
9
10#include <string.h>
11
12// PVCAM
13#include <master.h>
14#include <pvcam.h>
15
16#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
17#include "../../magaox_git_version.h"
18
19/** \defgroup pvcamCtrl
20 * \brief The pvcam controller application for teledyne cameras
21 *
22 * <a href="../handbook/operating/software/apps/pvcamCtrl.html">Application Documentation</a>
23 *
24 * \ingroup apps
25 *
26 */
27
28#ifndef PL_ERR_LIBRARY_NOT_INITIALIZED
29 #define PL_ERR_LIBRARY_NOT_INITIALIZED ( 157 )
30#endif
31
32/// Format an error message using pvcam facilities
33/**
34 * \returns a string of format "<func> failed: <pl_error_message>. <more>"
35 */
36std::string pvcamErrMessage( const std::string &func, ///< [in] the pvcam function which failed
37 int pec, ///< [in] the code from pl_error_code
38 const std::string &more ///< [in] extra information to include
39)
40{
41 char pvmsg[ERROR_MSG_LEN];
42 pl_error_message( pec, pvmsg );
43
44 std::string msg = func + " failed: " + pvmsg;
45 if( more != "" )
46 msg += " " + more;
47
48 return msg;
49}
50
51/// Helper for logging an error from pvcam
52#define log_pvcam_software_error( func, /**< [in] the pvcam function which failed*/ \
53 more /**< [in] extra information to include*/ \
54) \
55 { \
56 int pec = pl_error_code(); \
57 log<software_error>( { __FILE__, __LINE__, 0, pec, pvcamErrMessage( func, pec, more ) } ); \
58 }
59
60/** \defgroup pvcamCtrl_files
61 * \ingroup pvcamCtrl
62 */
63
64namespace MagAOX
65{
66namespace app
67{
68
69/// The MagAO-X pvcam controller
70/**
71 * \ingroup pvcamCtrl
72 */
73class pvcamCtrl : public MagAOXApp<true>,
74 public dev::stdCamera<pvcamCtrl>,
75 public dev::frameGrabber<pvcamCtrl>,
76 public dev::dssShutter<pvcamCtrl>,
77 public dev::telemeter<pvcamCtrl>
78{
79
84
85 // Give the test harness access.
86 friend class pvcamCtrl_test;
87
88 friend class dev::stdCamera<pvcamCtrl>;
89 friend class dev::frameGrabber<pvcamCtrl>;
90 friend class dev::dssShutter<pvcamCtrl>;
91 friend class dev::telemeter<pvcamCtrl>;
92
94
95 public:
96 /** \name app::dev Configurations
97 *@{
98 */
99 static constexpr bool c_stdCamera_tempControl =
100 false; ///< app::dev config to tell stdCamera not to expose temperature controls
101
102 static constexpr bool c_stdCamera_temp = false; ///< app::dev config to tell stdCamera not to expose temperature
103
104 static constexpr bool c_stdCamera_readoutSpeed =
105 true; ///< app::dev config to tell stdCamera to expose readout speed controls
106
107 static constexpr bool c_stdCamera_vShiftSpeed =
108 false; ///< app:dev config to tell stdCamera not to expose vertical shift speed control
109
110 static constexpr bool c_stdCamera_emGain =
111 false; ///< app::dev config to tell stdCamera not to expose EM gain controls
112
113 static constexpr bool c_stdCamera_exptimeCtrl =
114 true; ///< app::dev config to tell stdCamera to expose exposure time controls
115
116 static constexpr bool c_stdCamera_fpsCtrl = true; ///< app::dev config to tell stdCamera to expose FPS controls
117
118 static constexpr bool c_stdCamera_fps = true; ///< app::dev config to tell stdCamera to expose FPS status
119
120 static constexpr bool c_stdCamera_synchro =
121 false; ///< app::dev config to tell stdCamera to not expose synchro mode controls
122
123 static constexpr bool c_stdCamera_usesModes =
124 false; ///< app:dev config to tell stdCamera not to expose mode controls
125
126 static constexpr bool c_stdCamera_usesROI = true; ///< app:dev config to tell stdCamera to expose ROI controls
127
128 static constexpr bool c_stdCamera_cropMode =
129 false; ///< app:dev config to tell stdCamera to expose Crop Mode controls
130
131 static constexpr bool c_stdCamera_hasShutter =
132 true; ///< app:dev config to tell stdCamera to expose shutter controls
133
134 static constexpr bool c_stdCamera_usesStateString =
135 false; ///< app::dev confg to tell stdCamera to expose the state string property
136
137 static constexpr bool c_frameGrabber_flippable =
138 false; ///< app:dev config to tell framegrabber this camera can not be flipped
139
140 ///@}
141
142 protected:
143 /** \name Configurable Parameters
144 *@{
145 */
146
147 std::string m_serialNumber; ///< The camera serial number.
148
149 ///\todo implement config-ing of this
150 float m_tempTol{ 0.1 }; ///< Tolerance in degrees C to declare the temperature control locked.
151
153 536870912 }; ///< Max size in bytes of the circular buffer to allocate. Default is 0.5 GB.
154
155 uint32_t m_acqSleep{ 5000 }; ///< The acquisition pause time, in ns, when no frame is ready.Default is 5000.
156
157 ///@}
158
159 int16 m_handle{ -1 }; ///< Camera handle, set when camera is opened
160
161 std::string m_camName; ///< Camera name, filled in as part of opening the camera.
162
163 struct gain
164 {
165 int index;
166 std::string name;
167
169 };
170
171 struct speed
172 {
173 int index;
175 int minG;
176 int maxG;
177 std::vector<gain> gains;
178 };
179
180 struct port
181 {
182 int index;
183 int value;
184 std::string name;
185
186 std::vector<speed> speeds;
187 };
188
189 std::vector<port> m_ports;
190
191 bool m_8bit{ false };
192
193 bool m_fpsSetted{ false }; ///< Flag indicating that FPS was set, not exposure time.
194
196 uns8 *m_circBuff{ nullptr };
197
199
200 sem_t m_frSemaphore; ///< Semaphore used to signal that a frame is ready.
201 sem_t m_frDoneSemaphore; ///< Semaphore used to signal that a frame has been processed
202
205
206 public:
207 /// Default c'tor.
208 pvcamCtrl();
209
210 /// D'tor, declared and defined for noexcept.
212 {
213 }
214
215 // MagAOXApp:
216
217 virtual void setupConfig();
218
219 /// Implementation of loadConfig logic, separated for testing.
220 /** This is called by loadConfig().
221 */
222 int loadConfigImpl(
223 mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
224
225 virtual void loadConfig();
226
227 /// Startup function
228 /**
229 *
230 */
231 virtual int appStartup();
232
233 /// Implementation of the FSM for pvcamCtrl.
234 /**
235 * \returns 0 on no critical error
236 * \returns -1 on an error requiring shutdown
237 */
238 virtual int appLogic();
239
240 /// Shutdown the app.
241 /**
242 *
243 */
244 virtual int appShutdown();
245
246 // stdCamera interface:
247
248 // This must set the power-on default values of
249 /* -- m_ccdTempSetpt
250 * -- m_currentROI
251 */
252 int powerOnDefaults();
253
254 int setTempControl();
255 int setTempSetPt();
256 int setReadoutSpeed();
257 int setVShiftSpeed();
258 int setEMGain();
259 int setExpTime();
260 int setFPS();
261
262 /// Check the next ROI
263 /** Checks if the target values are valid and adjusts them to the closest valid values if needed.
264 *
265 * \returns 0 if successful
266 * \returns -1 otherwise
267 */
268 int checkNextROI();
269
270 int setNextROI();
271
272 /// Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface]
273 /**
274 * \returns 0 always
275 */
276 int setShutter( int sh );
277
278 // Framegrabber interface:
280 float fps();
281 int startAcquisition();
283 int loadImageIntoStream( void *dest );
284 int reconfig();
285
286 // pvcam specific:
287 int connect();
288
289 int fillSpeedTable();
290
291 void dumpEnum( uns32 paramID, const std::string &paramMnem );
292
293 int getTemp();
294
296
298
299 /** \name Telemeter Interface
300 *
301 * @{
302 */
303 int checkRecordTimes();
304
305 int recordTelem( const telem_stdcam * );
306
307 int recordTelem( const telem_fgtimings * );
308
309 ///@}
310};
311
312pvcamCtrl::pvcamCtrl() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
313{
314 m_powerMgtEnabled = true;
315 m_powerOnWait = 15;
316
317 m_expTime = 0.01;
318 m_expTimeSet = 0.01;
319
320 m_default_x = 1599.5;
321 m_default_y = 1599.5;
322 m_default_w = 512; //we make this smaller by default
323 m_default_h = 512;
324 m_default_bin_x = 1;
325 m_default_bin_y = 1;
326
327 m_full_x = 1599.5;
328 m_full_y = 1599.5;
329 m_full_w = 3200;
330 m_full_h = 3200;
331
332
333 m_defaultReadoutSpeed = "dynamic_range";
334 m_readoutSpeedNames = { "sensitivity", "speed", "dynamic_range", "sub_electron" };
335 m_readoutSpeedNameLabels = { "Sensitivity", "Speed", "Dynamic Range", "Sub-Electron" };
336
339
340 return;
341}
342
344{
345 config.add( "camera.serialNumber",
346 "",
347 "camera.serialNumber",
348 argType::Required,
349 "camera",
350 "serialNumber",
351 false,
352 "int",
353 "The identifying serial number of the camera." );
354
355 // put this in camera because it is a camera interface config, not a framegrabber thing per se:
356 config.add( "camera.circBuffMaxBytes",
357 "",
358 "camera.circBuffMaxBytes",
359 argType::Required,
360 "camera",
361 "circBuffMaxBytes",
362 false,
363 "int",
364 "Maximum size in bytes of the circular buffer to allocate. Default is 0.5 GB." );
365
366 STDCAMERA_SETUP_CONFIG( config );
367
369
370 config.add( "framegrabber.acqSleep",
371 "",
372 "framegrabber.acqSleep",
373 argType::Required,
374 "framegrabber",
375 "acqSleep",
376 false,
377 "int",
378 "The acquisition pause time, in ns, when no frame is ready. Default is 5000." );
379
380 shutterT::setupConfig( config );
381
382 TELEMETER_SETUP_CONFIG( config );
383}
384
385int pvcamCtrl::loadConfigImpl( mx::app::appConfigurator &_config )
386{
387 _config( m_serialNumber, "camera.serialNumber" );
388 _config( m_circBuffMaxBytes, "camera.circBuffMaxBytes" );
389
390 if( m_serialNumber == "" )
391 {
392 log<text_log>( "camera serial number not provided", logPrio::LOG_CRITICAL );
393 return -1;
394 }
395
397
399
400 _config( m_acqSleep, "framegrabber.acqSleep" );
402
404
405 return 0;
406}
407
409{
410 if( loadConfigImpl( config ) != 0 )
411 {
412 log<text_log>( "error loading config", logPrio::LOG_CRITICAL );
413 m_shutdown = true;
414 }
415}
416
418{
419
421
422 if( sem_init( &m_frSemaphore, 0, 0 ) < 0 )
423 {
424 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing frame ready semaphore" } );
425 }
426
427 if( sem_init( &m_frDoneSemaphore, 0, 0 ) < 0 )
428 {
429 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing frame done semaphore" } );
430 }
431
433
434 if( shutterT::appStartup() < 0 )
435 {
436 return log<software_critical, -1>( { __FILE__, __LINE__ } );
437 }
438
440
441 return 0;
442}
443
445{
446 ///\todo why do we run dev appLogics first?
447
448 if( state() == stateCodes::POWERON )
449 {
450 if( !powerOnWaitElapsed() )
451 {
452 return 0;
453 }
454
456 }
457
459
461
462 // and run dssShutter's appLogic
463 if( shutterT::appLogic() < 0 )
464 {
465 return log<software_error, -1>( { __FILE__, __LINE__ } );
466 }
467
469 {
470 m_reconfig = true; // Trigger a f.g. thread reconfig.
471
472 // Might have gotten here because of a power off.
473 if( powerState() != 1 )
474 {
475 return 0;
476 }
477
478 std::unique_lock<std::mutex> lock( m_indiMutex );
479 if( connect() < 0 )
480 {
481 if( powerState() != 1 || powerStateTarget() != 1 )
482 return 0;
484 }
485
487 return 0;
488 }
489
491 {
494 }
495
497 {
498 if( getTemp() != 0 )
499 {
500 if( powerState() != 1 || powerStateTarget() != 1 )
501 return 0;
503 return 0;
504 }
505
507
509
511 recordCamera();
512 }
513
514 return 0;
515}
516
518{
519 if( m_handle != -1 )
520 {
521 if( !pl_cam_close( m_handle ) )
522 {
523 log_pvcam_software_error( "pl_cam_close", "continuing" );
524 }
525 m_handle = -1;
526 }
527
528 if( !pl_pvcam_uninit() )
529 {
530 if( pl_error_code() != PL_ERR_LIBRARY_NOT_INITIALIZED ) /// \todo this error code is manually defined
531 {
532 log_pvcam_software_error( "pl_pvcam_uninit", "continuing" );
533 }
534 }
535
537
539
540 if( shutterT::appShutdown() < 0 )
541 {
542 log<software_error>( { __FILE__, __LINE__, "error from shutterT::appShutdown()" } );
543 }
544
546
547 return 0;
548}
549
560
562{
563 return 0;
564}
565
567{
568 return 0;
569}
570
572{
574
575 return 0;
576}
577
579{
580 return 0;
581}
582
584{
585 return 0;
586}
587
589{
591
592 if( !pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_MIN, static_cast<void *>( &minExpTime ) ) )
593 {
594 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME ATTR_MIN" );
595 log<software_error>( { __FILE__, __LINE__, "could not set exposure time" } );
596 return -1;
597 }
598
599 if( !pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_MAX, static_cast<void *>( &maxExpTime ) ) )
600 {
601 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME ATTR_MAX" );
602 log<software_error>( { __FILE__, __LINE__, "could not set exposure time" } );
603 return -1;
604 }
605
606 if( m_expTimeSet * 1e6 < minExpTime )
607 {
608 m_expTimeSet = (int)( minExpTime / 1e6 + 0.5 );
609 log<text_log>( "increased m_expTimeSet to: " + std::to_string( m_expTimeSet ), logPrio::LOG_INFO );
610 }
611
612 if( m_expTimeSet * 1e6 > maxExpTime )
613 {
614 m_expTimeSet = (int)( maxExpTime / 1e6 - 0.5 );
615 log<text_log>( "decreased m_expTimeSet to: " + std::to_string( m_expTimeSet ), logPrio::LOG_INFO );
616 }
617
619
620 return 0;
621}
622
624{
625 m_expTimeSet = 1.0 / m_fpsSet;
626 m_fpsSetted = true;
627 return setExpTime();
628}
629
631{
632 if( m_nextROI.w > 3200 )
633 {
634 m_nextROI.w = 3200;
635 }
636
637 int x0 = m_nextROI.x - 0.5 * m_nextROI.w;
638
639 if( x0 < 0 )
640 {
641 m_nextROI.w += x0;
642 m_nextROI.x = 0;
643 }
644
645 int x1 = m_nextROI.x + 0.5 * m_nextROI.w;
646
647 if( x1 > 3199 )
648 {
649 m_nextROI.w = 3199 - x0;
650 m_nextROI.x = x0 + 0.5 * m_nextROI.w;
651 }
652
653 if( m_nextROI.h > 3200 )
654 {
655 m_nextROI.h = 3200;
656 }
657
658 int y0 = m_nextROI.y - 0.5 * m_nextROI.h;
659
660 if( y0 < 0 )
661 {
662 m_nextROI.h += y0;
663 m_nextROI.y = 0;
664 }
665
666 int y1 = m_nextROI.y + 0.5 * m_nextROI.h;
667
668 if( y1 > 3199 )
669 {
670 m_nextROI.h = 3199 - y0;
671 m_nextROI.y = y0 + 0.5 * m_nextROI.h;
672 }
673
674 return 0;
675}
676
678{
679 // This is done in setup acq
681 return 0;
682}
683
685{
686 recordCamera( true );
688}
689
691{
692
693 recordCamera( true );
694 //-- 0: register the callback
696 false ) // Because we registered it last time we configured acq:
697 {
698 log_pvcam_software_error( "pl_cam_deregister_callback", "PL_CALLBACK_EOF" );
699 }
700
703 reinterpret_cast<void *>( &st_endOfFrameCallback ),
704 static_cast<void *>( this ) ) != true )
705 {
706 log_pvcam_software_error( "pl_cam_register_callback_ex3", "PL_CALLBACK_EOF" );
707 return -1;
708 }
709
710 //-- 1: Set speed:
711 int32 value;
712
713 if( m_readoutSpeedNameSet == "sensitivity" )
714 {
715 value = 0;
716 m_8bit = false;
717 }
718 else if( m_readoutSpeedNameSet == "speed" )
719 {
720 value = 1;
721 m_8bit = true;
722 }
723 else if( m_readoutSpeedNameSet == "dynamic_range" )
724 {
725 value = 2;
726 m_8bit = false;
727 }
728 else if( m_readoutSpeedNameSet == "sub_electron" )
729 {
730 value = 3;
731 m_8bit = false;
732 }
733 else
734 {
735 value = 2;
736 m_8bit = false;
737 m_readoutSpeedNameSet = "dynamic_range";
738 }
740
741 if( pl_set_param( m_handle, PARAM_READOUT_PORT, static_cast<void *>( &value ) ) == false )
742 {
743 log_pvcam_software_error( "pl_set_param", "PARAM_READOUT_PORT" );
744 return -1;
745 }
746
747 //-- 2: Set ROI:
749 pvROI.s1 = m_nextROI.x - 0.5 * m_nextROI.w;
750 pvROI.s2 = pvROI.s1 + m_nextROI.w - 1;
751 pvROI.sbin = m_nextROI.bin_x;
752 pvROI.p1 = m_nextROI.y - 0.5 * m_nextROI.h;
753 pvROI.p2 = pvROI.p1 + m_nextROI.h - 1;
754 pvROI.pbin = m_nextROI.bin_y;
755
757
758 m_width = ( pvROI.s2 - pvROI.s1 + 1 ) / pvROI.sbin;
759 m_height = ( pvROI.p2 - pvROI.p1 + 1 ) / pvROI.pbin;
761
762 //-- 3: Setup continuous acquisition
763 uns32 fsize;
764
765 uns32 exptime = m_expTimeSet * 1e6;
766 if( pl_exp_setup_cont( m_handle, 1, &pvROI, TIMED_MODE, exptime, &fsize, CIRC_OVERWRITE ) == false )
767 {
768 log_pvcam_software_error( "pl_exp_setup_cont", "" );
769 m_shutdown = true;
770 return -1;
771 }
772
773 if( pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_CURRENT, &exptime ) == false )
774 {
775 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME" );
776 }
777 m_expTime = ( 1.0 * exptime ) / 1e6;
779
780 uns32 readouttime = 0;
782 {
783 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_TIME" );
784 }
785
786 long64 predelay = 0;
788 {
789 log_pvcam_software_error( "pl_get_param", "PARAM_PRE_TRIGGER_DELAY" );
790 }
791
792 long64 clearing = 0;
794 {
795 log_pvcam_software_error( "pl_get_param", "PARAM_CLEARING_TIME" );
796 }
797
798 long64 postdelay = 0;
800 {
801 log_pvcam_software_error( "pl_get_param", "PARAM_POST_TRIGGER_DELAY" );
802 }
803
804 if( m_fpsSetted )
805 {
806 if( static_cast<long64>( m_expTime * 1000000 ) < readouttime )
807 {
808 // This is as fast as we can go, set expTime to longest possible
809 m_expTimeSet = ( readouttime - 1 ) / 1e6; // Go one usec lower, which will get cleaned up by the camera
810 }
811 else
812 {
813 m_expTimeSet = ( 1.0 / m_fpsSet ) - 2.0 * postdelay / 1e9;
814
815 if( static_cast<long64>( m_expTimeSet * 1000000 ) < readouttime )
816 {
817 // again, Set expTime to longest possible
818 m_expTimeSet = ( readouttime - 1.0 ) / 1e6; // Go one usec lower, which will get cleaned up by the
819 // camera
820 }
821 }
822
823 exptime = m_expTimeSet * 1e6;
825 {
826 log_pvcam_software_error( "pl_exp_setup_cont", "" );
827 m_shutdown = true;
828 return -1;
829 }
830
831 // Note: this call apparently resets exptime to 0 ....
832 if( pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_CURRENT, &exptime ) == false )
833 {
834 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME" );
835 }
836
837 m_expTime = ( 1.0 * exptime ) / 1e6;
838
840
841 m_fpsSetted = false;
842
844 {
845 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_TIME" );
846 }
847 }
848
849 if( static_cast<long64>( m_expTime * 1000000 ) < readouttime )
850 {
851 m_fps = 1.0 / ( readouttime / 1e6 + postdelay / 1e9 );
852 }
853 else
854 {
855 m_fps =
856 1.0 / ( m_expTime + 2.0 * postdelay / 1e9 ); // At some speeds there is an extra + ~250/1e9 that is needed.
857 }
858
859 m_fpsSet = m_fps;
860
861 //-- 4: Allocate the acq circular buffer
862 if( m_circBuff != nullptr )
863 {
864 delete[] m_circBuff;
865 m_circBuffBytes = 0;
866 m_circBuff = nullptr;
867 }
868
870
871 m_circBuff = new( std::nothrow ) uns8[m_circBuffBytes];
872
873 if( m_circBuff == nullptr )
874 {
875 log<software_critical>( { __FILE__, __LINE__, "failed to allocate acquisition circular buffer." } );
877 return -1;
878 }
879
880 recordCamera( true );
881
882 return 0;
883}
884
886{
887 return m_fps;
888}
889
891{
893 {
894 log_pvcam_software_error( "pv_exp_start_cont", "" );
895 return -1;
896 }
897
898 log<text_log>( "continuous acquisition started", logPrio::LOG_INFO );
899 return 0;
900}
901
903{
904 // See if a frame is ready without waiting
905 int rv = sem_trywait( &m_frSemaphore );
906 if( rv == 0 )
907 {
909 {
910 log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
911 }
912
913 return 0;
914 }
915 else if( errno != EAGAIN )
916 {
917 log<software_critical>( { __FILE__, __LINE__, errno, 0, "sem_trywait" } );
918 return -1;
919 }
920
921 // if none is ready we pause before going on
922 mx::sys::nanoSleep( m_acqSleep );
923
924 return 1;
925}
926
928{
929
930 // Obtain a pointer to the last acquired frame
931 uns8 *frame;
932 if( pl_exp_get_latest_frame( m_handle, reinterpret_cast<void **>( &frame ) ) == false )
933 {
934 log_pvcam_software_error( "pl_exp_get_latest_frame", "" );
935 }
936
937 if( m_8bit )
938 {
939 uint16_t *dest16 = static_cast<uint16_t *>( dest );
940 uint8_t *src8 = static_cast<uint8_t *>( frame );
941 for( uint32_t i = 0; i < m_width * m_height; ++i )
942 {
943 dest16[i] = src8[i];
944 }
945 }
946 else
947 {
948 memcpy( dest, frame, m_width * m_height * 2 );
949 }
950
951 // Now tell the callback it can go on
952 if( sem_post( &m_frDoneSemaphore ) < 0 )
953 {
954 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to frame done semaphore" } );
955 return -1;
956 }
957
958 return 0;
959}
960
962{
963 if( pl_exp_stop_cont( m_handle, CCS_HALT ) == false )
964 {
965 log_pvcam_software_error( "pl_exp_stop_cont", "" );
966 }
967 return 0;
968}
969
971{
972
973 // In picam, we had to initialize every time. We'll do that here too.
974
975 // So close handle if it's open
976 if( m_handle != -1 )
977 {
978 if( !pl_cam_close( m_handle ) )
979 {
980 log_pvcam_software_error( "pl_cam_close", "" );
981 return -1;
982 }
983 m_handle = -1;
984 }
985
986 // Uninit
987 if( !pl_pvcam_uninit() )
988 {
989 if( pl_error_code() != PL_ERR_LIBRARY_NOT_INITIALIZED ) /// \todo this error code is manually defined
990 {
991 log_pvcam_software_error( "pl_pvcam_uninit", "continuing" );
992 }
993 }
994
995 if( !pl_pvcam_init() )
996 {
997 log_pvcam_software_error( "pl_pvcam_init", "" );
998 return -1;
999 }
1000
1002
1003 // Read the number of cameras in the system.
1004 // This will return total number of PVCAM cameras regardless of interface.
1006 {
1007 log_pvcam_software_error( "pl_cam_get_total", "" );
1008 return -1;
1009 }
1010
1011 if( nrOfCameras == 0 )
1012 {
1013 if( !stateLogged() )
1014 {
1015 log<text_log>( "Found 0 pvcam cameras.", logPrio::LOG_INFO );
1016 }
1018 return 0;
1019 }
1020
1021 log<text_log>( "Found " + std::to_string( nrOfCameras ) + " pvcam cameras.", logPrio::LOG_INFO );
1022
1023 for( int n = 0; n < nrOfCameras; ++n )
1024 {
1025 char camName[CAM_NAME_LEN]{ '\0' };
1026
1027 // Obtain PVCAM-name for this particular camera
1028 if( pl_cam_get_name( n, camName ) != PV_OK )
1029 {
1030 log_pvcam_software_error( "pl_cam_get_name", "" );
1031 return -1;
1032 }
1033
1034 int16_t handle = -1;
1035
1036 // Open to check its serial number
1038 {
1039 log_pvcam_software_error( "pl_cam_open",
1040 "" ); // We log this for now, but with 2 apps running we prob want to ignore
1041 continue;
1042 }
1043
1044 // Read the version of the Device Driver
1045
1047 if( !pl_get_param( handle, PARAM_HEAD_SER_NUM_ALPHA, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1048 {
1049 log_pvcam_software_error( "pl_get_param", "PARAM_HEAD_SER_NUM_ALPHA ATTR_AVAIL" );
1050
1051 if( !pl_cam_close( handle ) )
1052 {
1053 log_pvcam_software_error( "pl_cam_close", "" );
1054 }
1055
1056 return -1;
1057 }
1058
1059 if( isAvailable )
1060 {
1061 char camSerial[MAX_ALPHA_SER_NUM_LEN]{ '\0' };
1062
1063 if( !pl_get_param( handle, PARAM_HEAD_SER_NUM_ALPHA, ATTR_CURRENT, static_cast<void *>( camSerial ) ) )
1064 {
1065 log_pvcam_software_error( "pl_get_param", "PARAM_HEAD_SER_NUM_ALPHA ATTR_CURRENT" );
1066
1067 if( !pl_cam_close( handle ) )
1068 {
1069 log_pvcam_software_error( "pl_cam_close", "" );
1070 }
1071
1072 return -1;
1073 }
1074
1075 if( camSerial == m_serialNumber )
1076 {
1077 state( stateCodes::NOTCONNECTED ); // not strictly true, but logically true until m_handle is set
1079 m_handle = handle;
1080 break;
1081 }
1082 }
1083
1084 // If we're here then either it didn't have a serial number, or it didn't have the right serial number
1085 if( !pl_cam_close( handle ) )
1086 {
1087 log_pvcam_software_error( "pl_cam_close", "" );
1088 return -1;
1089 }
1090 }
1091
1092 if( m_handle > -1 )
1093 {
1094 log<text_log>( "Opened camera " + m_serialNumber + " at " + m_camName, logPrio::LOG_INFO );
1096
1097 int32 res;
1098 uns16 idx;
1099
1100 // Set exposure resolution to usec.
1101
1102 idx = 1;
1103 if( pl_set_param( m_handle, PARAM_EXP_RES_INDEX, &idx ) == false )
1104 {
1105 log_pvcam_software_error( "pl_set_param", "PARAM_EXP_RES_INDEX" );
1106 }
1107
1108 if( pl_get_param( m_handle, PARAM_EXP_RES, ATTR_CURRENT, &res ) == false )
1109 {
1110 log_pvcam_software_error( "pl_get_param", "PARAM_EXP_RES" );
1111 }
1112
1114 {
1115 log_pvcam_software_error( "pl_get_param", "PARAM_EXP_RES_INDEX" );
1116 }
1117
1119 }
1120 else
1121 {
1122 if( !stateLogged() )
1123 {
1124 log<text_log>( "camera not found", logPrio::LOG_INFO );
1125 }
1127 }
1128
1129 return 0;
1130}
1131
1133{
1135 {
1136 return -1;
1137 }
1138
1139 uns32 nports;
1140
1141 if( pl_get_param( m_handle, PARAM_READOUT_PORT, ATTR_COUNT, static_cast<void *>( &nports ) ) == false )
1142 {
1143 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_PORT" );
1144 return -1;
1145 }
1146
1147 std::cerr << "Found " << nports << " ports\n";
1148
1149 m_ports.resize( nports );
1150
1151 for( uns32 p = 0; p < nports; ++p )
1152 {
1155 {
1156 log_pvcam_software_error( "pl_enum_str_length", "PARAM_READOUT_PORT" );
1157 return -1;
1158 }
1159
1160 char *text = new( std::nothrow ) char[strLength];
1161 if( !text )
1162 {
1163 ///\todo log this properly
1164 std::cerr << "failed to allocate string\n";
1165 return -1;
1166 }
1167
1168 int32 value;
1170 {
1171 log_pvcam_software_error( "pl_get_enum_param", "PARAM_READOUT_PORT" );
1172 delete[] text;
1173 return false;
1174 }
1175
1176 m_ports[p].index = p;
1177 m_ports[p].value = value;
1178 m_ports[p].name = text;
1179
1180 std::cerr << "Port: " << p << " name: " << text << " value: " << value << "\n";
1181
1182 delete[] text;
1183
1184 if( pl_set_param( m_handle, PARAM_READOUT_PORT, static_cast<void *>( &value ) ) == false )
1185 {
1186 log_pvcam_software_error( "pl_set_param", "PARAM_READOUT_PORT" );
1187 return -1;
1188 }
1189
1190 uns32 nspeeds;
1191 if( pl_get_param( m_handle, PARAM_SPDTAB_INDEX, ATTR_COUNT, static_cast<void *>( &nspeeds ) ) == false )
1192 {
1193 log_pvcam_software_error( "pl_get_param", "PARAM_SPDTAB_INDEX" );
1194 return -1;
1195 }
1196 std::cerr << " Speeds: " << nspeeds << "\n";
1197
1198 m_ports[p].speeds.resize( nspeeds );
1199
1200 for( uns32 s = 0; s < nspeeds; ++s )
1201 {
1202 if( pl_set_param( m_handle, PARAM_SPDTAB_INDEX, static_cast<void *>( &s ) ) == false )
1203 {
1204 log_pvcam_software_error( "pl_set_param", "PARAM_SPDTAB_INDEX" );
1205 return -1;
1206 }
1207
1208 uns16 pixtime;
1209 if( pl_get_param( m_handle, PARAM_PIX_TIME, ATTR_CURRENT, static_cast<void *>( &pixtime ) ) == false )
1210 {
1211 log_pvcam_software_error( "pl_get_param", "PARAM_PIX_TIME" );
1212 return -1;
1213 }
1214
1215 m_ports[p].speeds[s].pixTime = pixtime;
1216
1217 uns32 ngains;
1218 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_COUNT, static_cast<void *>( &ngains ) ) == false )
1219 {
1220 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_COUNT" );
1221 return -1;
1222 }
1223
1224 int16 ming;
1225 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_MIN, static_cast<void *>( &ming ) ) == false )
1226 {
1227 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_MIN" );
1228 return -1;
1229 }
1230
1231 int16 maxg;
1232 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_MIN, static_cast<void *>( &maxg ) ) == false )
1233 {
1234 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_MAX" );
1235 return -1;
1236 }
1237
1238 std::cerr << " Speed: " << s << " " << " pixtime: " << pixtime << " gains: " << ngains << " [" << ming
1239 << "-" << maxg << "]\n";
1240
1241 m_ports[p].speeds[s].minG = ming;
1242 m_ports[p].speeds[s].maxG = maxg;
1243
1244 m_ports[p].speeds[s].gains.resize( ngains );
1245
1246 for( uns32 g = 0; g < ngains; ++g )
1247 {
1248
1249 int16 gg = ming + g;
1250 if( pl_set_param( m_handle, PARAM_GAIN_INDEX, static_cast<void *>( &gg ) ) == false )
1251 {
1252 log_pvcam_software_error( "pl_set_param", "PARAM_GAIN_INDEX" );
1253 return -1;
1254 }
1255
1257 if( pl_get_param( m_handle, PARAM_BIT_DEPTH, ATTR_CURRENT, static_cast<void *>( &bitdepth ) ) == false )
1258 {
1259 log_pvcam_software_error( "pl_get_param", "PARAM_BIT_DEPTH ATTR_CURRENT" );
1260 return -1;
1261 }
1262 std::cerr << " Gain: " << g << " bitdepth: " << bitdepth << "\n";
1263 }
1264 }
1265 }
1266
1267 return 0;
1268}
1269
1270void pvcamCtrl::dumpEnum( uns32 paramID, const std::string &paramMnem )
1271{
1272
1273 if( state() == stateCodes::CONNECTED )
1274 {
1275 uns32 count;
1276
1277 if( PV_OK != pl_get_param( m_handle, paramID, ATTR_COUNT, static_cast<void *>( &count ) ) )
1278 {
1279 log_pvcam_software_error( "pl_get_param", paramMnem );
1280 // TODO: Handle error
1281 return;
1282 }
1283 if( count == 0 )
1284 {
1285 std::cerr << paramMnem << ": count 0\n";
1286 return;
1287 }
1288 for( uns32 n = 0; n < count; ++n )
1289 {
1292 {
1293 log_pvcam_software_error( "pl_enum_str_length", paramMnem );
1294 // TODO: Handle error
1295 break;
1296 }
1297 char *text = new( std::nothrow ) char[strLength];
1298 if( !text )
1299 {
1300 // TODO: Handle error
1301 break;
1302 }
1303 int32 value;
1304 if( PV_OK != pl_get_enum_param( m_handle, paramID, n, &value, text, strLength ) )
1305 {
1306 log_pvcam_software_error( "pl_get_enum_param", paramMnem );
1307 // TODO: Handle error
1308 delete[] text;
1309 break;
1310 }
1311 std::cerr << paramMnem;
1312 fprintf( stderr, " item at index %u, value: %d, text: '%s'\n", n, value, text );
1313 delete[] text;
1314 }
1315 }
1316 else
1317 {
1318 std::cerr << "dumpEnum: not CONNECTED\n";
1319 }
1320}
1321
1323{
1324 if( state() == stateCodes::OPERATING )
1325 {
1326 return 0;
1327 }
1328
1330 if( !pl_get_param( m_handle, PARAM_TEMP_SETPOINT, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1331 {
1332 if( powerState() != 1 || powerStateTarget() != 1 )
1333 return 0;
1334 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1336 }
1337
1338 int16 stemp;
1339 if( isAvailable ) // Maybe this is a separate check. Don't yet know what happens when acquiring
1340 {
1341 if( !pl_get_param( m_handle, PARAM_TEMP_SETPOINT, ATTR_CURRENT, static_cast<void *>( &stemp ) ) )
1342 {
1343 if( powerState() != 1 || powerStateTarget() != 1 )
1344 return 0;
1345 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1347 }
1348
1349 m_ccdTempSetpt = stemp / 100.0;
1350 }
1351
1352 if( !pl_get_param( m_handle, PARAM_TEMP, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1353 {
1354 if( powerState() != 1 || powerStateTarget() != 1 )
1355 return 0;
1356 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1358 }
1359
1360 int16 ctemp;
1361 if( isAvailable ) // Maybe this is a separate check. Don't yet know what happens when acquiring
1362 {
1363 if( !pl_get_param( m_handle, PARAM_TEMP, ATTR_CURRENT, static_cast<void *>( &ctemp ) ) )
1364 {
1365 if( powerState() != 1 || powerStateTarget() != 1 )
1366 return 0;
1367 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1369 }
1370
1371 m_ccdTemp = ctemp / 100.0;
1372 }
1373
1375 {
1376 m_tempControlStatus = true;
1377 m_tempControlOnTarget = false;
1378 m_tempControlStatusStr = "UNLOCKED";
1379 }
1380 else
1381 {
1382 m_tempControlStatus = true;
1383 m_tempControlOnTarget = true;
1384 m_tempControlStatusStr = "LOCKED";
1385 }
1386
1387 return 0;
1388}
1389
1390void pvcamCtrl::st_endOfFrameCallback( FRAME_INFO *finfo, void *pvcamCtrlInst )
1391{
1392 static_cast<pvcamCtrl *>( pvcamCtrlInst )->endOfFrameCallback( finfo );
1393}
1394
1395void pvcamCtrl::endOfFrameCallback( FRAME_INFO *finfo )
1396{
1397 m_frameInfo = *finfo;
1398
1399 // 0 out the frDoneSemaphore just to be sure
1400 int semval;
1402 while( semval > 0 )
1403 {
1406 }
1407
1408 // Now tell the writer to get going
1409 if( sem_post( &m_frSemaphore ) < 0 )
1410 {
1411 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to frame ready semaphore" } );
1412 return;
1413 }
1414
1415 // Now wait on the frame done semaphore
1416 timespec ts;
1417
1418 if( clock_gettime( CLOCK_REALTIME, &ts ) < 0 )
1419 {
1420 log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
1421 }
1422
1423 mx::sys::timespecAddNsec( ts, 1e9 ); // We wait for up to one second for the frame done processing signal
1424
1426}
1427
1432
1434{
1435 return recordCamera( true );
1436}
1437
1439{
1440 return recordFGTimings( true );
1441}
1442
1443} // namespace app
1444} // namespace MagAOX
1445
1446#endif // pvcamCtrl_hpp
The base-class for XWCTk applications.
stateCodes::stateCodeT state()
Get the current state code.
int powerState()
Returns the current power state.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int powerStateTarget()
Returns the target power state.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
bool powerOnWaitElapsed()
This method tests whether the power on wait time has elapsed.
unsigned long m_powerOnWait
Time in sec to wait for device to boot after power on.
std::mutex m_indiMutex
Mutex for locking INDI communications.
MagAO-X Uniblitz DSS Shutter interface.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int setShutterState(int sh)
Change shutter state.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_reconfig
Flag to set if a camera reconfiguration requires a framegrabber reset.
uint32_t m_height
The height of the image, once deinterlaced etc.
MagAO-X standard camera interface.
std::vector< std::string > m_readoutSpeedNames
float m_fpsSet
The commanded fps, as set by user.
float m_default_x
Power-on ROI center x coordinate.
std::string m_tempControlStatusStr
Camera specific description of temperature control status.
std::vector< std::string > m_readoutSpeedNameLabels
std::string m_defaultReadoutSpeed
The default readout speed of the camera.
float m_expTime
The current exposure time, in seconds.
int m_default_bin_x
Power-on ROI x binning.
float m_expTimeSet
The exposure time, in seconds, as set by user.
float m_full_y
The full ROI center y coordinate.
std::string m_readoutSpeedName
The current readout speed name.
float m_ccdTempSetpt
The desired temperature, in C.
bool m_tempControlStatus
Whether or not temperature control is active.
float m_full_x
The full ROI center x coordinate.
float m_ccdTemp
The current temperature, in C.
bool m_tempControlOnTarget
Whether or not the temperature control system is on its target temperature.
float m_default_y
Power-on ROI center y coordinate.
int m_default_bin_y
Power-on ROI y binning.
std::string m_readoutSpeedNameSet
The user requested readout speed name, to be set by derived()
The MagAO-X pvcam controller.
Definition pvcamCtrl.hpp:78
static constexpr bool c_stdCamera_exptimeCtrl
app::dev config to tell stdCamera to expose exposure time controls
int16 m_handle
Camera handle, set when camera is opened.
static constexpr bool c_stdCamera_usesROI
app:dev config to tell stdCamera to expose ROI controls
uint32_t m_acqSleep
The acquisition pause time, in ns, when no frame is ready.Default is 5000.
static constexpr bool c_stdCamera_emGain
app::dev config to tell stdCamera not to expose EM gain controls
static constexpr bool c_stdCamera_usesStateString
app::dev confg to tell stdCamera to expose the state string property
static constexpr bool c_stdCamera_fps
app::dev config to tell stdCamera to expose FPS status
friend class pvcamCtrl_test
Definition pvcamCtrl.hpp:86
void endOfFrameCallback(FRAME_INFO *finfo)
virtual void loadConfig()
static constexpr bool c_stdCamera_tempControl
app::dev config to tell stdCamera not to expose temperature controls
Definition pvcamCtrl.hpp:99
int recordTelem(const telem_stdcam *)
static void st_endOfFrameCallback(FRAME_INFO *finfo, void *pvcamCtrlInst)
int setShutter(int sh)
Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface].
static constexpr bool c_stdCamera_usesModes
app:dev config to tell stdCamera not to expose mode controls
std::vector< port > m_ports
virtual int appShutdown()
Shutdown the app.
bool m_fpsSetted
Flag indicating that FPS was set, not exposure time.
uint32_t m_circBuffMaxBytes
Max size in bytes of the circular buffer to allocate. Default is 0.5 GB.
int checkNextROI()
Check the next ROI.
std::vector< speed > speeds
static constexpr bool c_stdCamera_hasShutter
app:dev config to tell stdCamera to expose shutter controls
static constexpr bool c_stdCamera_fpsCtrl
app::dev config to tell stdCamera to expose FPS controls
dev::stdCamera< pvcamCtrl > stdCameraT
Definition pvcamCtrl.hpp:80
dev::frameGrabber< pvcamCtrl > frameGrabberT
Definition pvcamCtrl.hpp:81
static constexpr bool c_stdCamera_temp
app::dev config to tell stdCamera not to expose temperature
pvcamCtrl()
Default c'tor.
virtual int appLogic()
Implementation of the FSM for pvcamCtrl.
sem_t m_frSemaphore
Semaphore used to signal that a frame is ready.
sem_t m_frDoneSemaphore
Semaphore used to signal that a frame has been processed.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
~pvcamCtrl() noexcept
D'tor, declared and defined for noexcept.
std::string m_camName
Camera name, filled in as part of opening the camera.
virtual int appStartup()
Startup function.
int loadImageIntoStream(void *dest)
dev::dssShutter< pvcamCtrl > shutterT
Definition pvcamCtrl.hpp:82
static constexpr bool c_stdCamera_readoutSpeed
app::dev config to tell stdCamera to expose readout speed controls
void dumpEnum(uns32 paramID, const std::string &paramMnem)
static constexpr bool c_stdCamera_synchro
app::dev config to tell stdCamera to not expose synchro mode controls
dev::telemeter< pvcamCtrl > telemeterT
Definition pvcamCtrl.hpp:83
std::vector< gain > gains
static constexpr bool c_stdCamera_cropMode
app:dev config to tell stdCamera to expose Crop Mode controls
float m_tempTol
Tolerance in degrees C to declare the temperature control locked.
std::string m_serialNumber
The camera serial number.
virtual void setupConfig()
static constexpr bool c_stdCamera_vShiftSpeed
app:dev config to tell stdCamera not to expose vertical shift speed control
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber this camera can not be flipped
#define FRAMEGRABBER_SETUP_CONFIG(cfig)
Call frameGrabberT::setupConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_LOGIC
Call frameGrabberT::appLogic with error checking for frameGrabber.
#define FRAMEGRABBER_APP_SHUTDOWN
Call frameGrabberT::appShutdown with error checking for frameGrabber.
#define FRAMEGRABBER_UPDATE_INDI
Call frameGrabberT::updateINDI with error checking for frameGrabber.
#define FRAMEGRABBER_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:28
static constexpr logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
#define PL_ERR_LIBRARY_NOT_INITIALIZED
Definition pvcamCtrl.hpp:29
std::string pvcamErrMessage(const std::string &func, int pec, const std::string &more)
Format an error message using pvcam facilities.
Definition pvcamCtrl.hpp:36
#define log_pvcam_software_error(func, more)
Helper for logging an error from pvcam.
Definition pvcamCtrl.hpp:52
#define STDCAMERA_SETUP_CONFIG(cfig)
Call stdCameraT::setupConfig with error checking for stdCamera.
#define STDCAMERA_APP_LOGIC
Call stdCameraT::appLogic with error checking for stdCamera.
#define STDCAMERA_APP_STARTUP
Call stdCameraT::appStartup with error checking for stdCamera.
#define STDCAMERA_LOAD_CONFIG(cfig)
Call stdCameraT::loadConfig with error checking for stdCamera.
#define STDCAMERA_UPDATE_INDI
Call stdCameraT::updateINDI with error checking for stdCamera.
#define STDCAMERA_APP_SHUTDOWN
Call stdCameraT::appShutdown with error checking for stdCamera.
A device base class which saves telemetry.
Definition telemeter.hpp:75
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording framegrabber timings.
Log entry recording stdcam stage specific status.
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.