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_fanSpeed =
111 true; ///< app::dev config to tell stdCamera to expose fan-speed control
112
113 static constexpr bool c_stdCamera_emGain =
114 false; ///< app::dev config to tell stdCamera not to expose EM gain controls
115
116 static constexpr bool c_stdCamera_exptimeCtrl =
117 true; ///< app::dev config to tell stdCamera to expose exposure time controls
118
119 static constexpr bool c_stdCamera_fpsCtrl = true; ///< app::dev config to tell stdCamera to expose FPS controls
120
121 static constexpr bool c_stdCamera_fps = true; ///< app::dev config to tell stdCamera to expose FPS status
122
123 static constexpr bool c_stdCamera_synchro =
124 false; ///< app::dev config to tell stdCamera to not expose synchro mode controls
125
126 static constexpr bool c_stdCamera_usesModes =
127 false; ///< app:dev config to tell stdCamera not to expose mode controls
128
129 static constexpr bool c_stdCamera_usesROI = true; ///< app:dev config to tell stdCamera to expose ROI controls
130
131 static constexpr bool c_stdCamera_cropMode =
132 false; ///< app:dev config to tell stdCamera to expose Crop Mode controls
133
134 static constexpr bool c_stdCamera_hasShutter =
135 true; ///< app:dev config to tell stdCamera to expose shutter controls
136
137 static constexpr bool c_stdCamera_usesStateString =
138 false; ///< app::dev confg to tell stdCamera to expose the state string property
139
140 static constexpr bool c_frameGrabber_flippable =
141 false; ///< app:dev config to tell framegrabber this camera can not be flipped
142
143 ///@}
144
145 protected:
146 /** \name Configurable Parameters
147 *@{
148 */
149
150 std::string m_serialNumber; ///< The camera serial number.
151
152 ///\todo implement config-ing of this
153 float m_tempTol{ 0.1 }; ///< Tolerance in degrees C to declare the temperature control locked.
154
156 536870912 }; ///< Max size in bytes of the circular buffer to allocate. Default is 0.5 GB.
157
158 uint32_t m_acqSleep{ 5000 }; ///< The acquisition pause time, in ns, when no frame is ready.Default is 5000.
159
160 ///@}
161
162 int16 m_handle{ -1 }; ///< Camera handle, set when camera is opened
163
164 std::string m_camName; ///< Camera name, filled in as part of opening the camera.
165
166 struct gain
167 {
168 int index;
169 std::string name;
170
172 };
173
174 struct speed
175 {
176 int index;
178 int minG;
179 int maxG;
180 std::vector<gain> gains;
181 };
182
183 struct port
184 {
185 int index;
186 int value;
187 std::string name;
188
189 std::vector<speed> speeds;
190 };
191
192 std::vector<port> m_ports;
193
194 bool m_8bit{ false };
195
196 bool m_fpsSetted{ false }; ///< Flag indicating that FPS was set, not exposure time.
197
199 uns8 *m_circBuff{ nullptr };
200
202
203 sem_t m_frSemaphore; ///< Semaphore used to signal that a frame is ready.
204 sem_t m_frDoneSemaphore; ///< Semaphore used to signal that a frame has been processed
205
208
209 public:
210 /// Default c'tor.
211 pvcamCtrl();
212
213 /// D'tor, declared and defined for noexcept.
215 {
216 }
217
218 // MagAOXApp:
219
220 virtual void setupConfig();
221
222 /// Implementation of loadConfig logic, separated for testing.
223 /** This is called by loadConfig().
224 */
225 int loadConfigImpl(
226 mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
227
228 virtual void loadConfig();
229
230 /// Startup function
231 /**
232 *
233 */
234 virtual int appStartup();
235
236 /// Implementation of the FSM for pvcamCtrl.
237 /**
238 * \returns 0 on no critical error
239 * \returns -1 on an error requiring shutdown
240 */
241 virtual int appLogic();
242
243 /// Shutdown the app.
244 /**
245 *
246 */
247 virtual int appShutdown();
248
249 /** \name stdCamera Interface
250 * @{
251 */
252
253 /// Set defaults for a power-on state.
254 int powerOnDefaults();
255
256 /// PVCAM does not expose a separate temperature-control toggle.
257 int setTempControl();
258
259 /// PVCAM does not expose a writable detector temperature setpoint in this app.
260 int setTempSetPt();
261
262 /// Queue the requested readout-speed selection for the next acquisition setup.
263 int setReadoutSpeed();
264
265 /// PVCAM does not expose vertical-shift control through this app.
266 int setVShiftSpeed();
267
268 /// Set the fan speed according to the configured stdCamera target.
269 int setFanSpeed();
270
271 /// PVCAM does not expose EM gain through this app.
272 int setEMGain();
273
274 /// Queue the requested exposure time for the next acquisition setup.
275 int setExpTime();
276
277 /// PVCAM does not expose FPS as a direct settable control in this app.
278 int setFPS();
279
280 /// Check the next ROI
281 /** Checks if the target values are valid and adjusts them to the closest valid values if needed.
282 *
283 * \returns 0 if successful
284 * \returns -1 otherwise
285 */
286 int checkNextROI();
287
288 /// Queue the requested ROI for the next acquisition setup.
289 int setNextROI();
290
291 /// Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface]
292 /**
293 * \returns 0 always
294 */
295 int setShutter( int sh );
296
297 ///@}
298
299 /** \name Framegrabber Interface
300 * @{
301 */
302
303 /// Configure the PVCAM acquisition state for the pending settings.
305
306 /// Return the current measured frame rate.
307 float fps();
308
309 /// Start continuous PVCAM acquisition.
310 int startAcquisition();
311
312 /// Wait for the next frame-ready signal and validate the acquisition state.
314
315 /// Copy the latest PVCAM frame into the destination image stream.
316 int loadImageIntoStream( void *dest );
317
318 /// Stop acquisition so the framegrabber can reconfigure.
319 int reconfig();
320
321 ///@}
322
323 /** \name PVCAM Interface
324 * @{
325 */
326
327 /// Find and open the configured PVCAM camera.
328 int connect();
329
330 /// Enumerate the PVCAM readout-speed table for the connected camera.
331 int fillSpeedTable();
332
333 /// Dump the values of a PVCAM enumerated parameter for debugging.
334 void dumpEnum( uns32 paramID, const std::string &paramMnem );
335
336 /// Get the current fan speed from the camera.
337 int getFanSpeed();
338
339 /// Get the current detector temperature and set point from the camera.
340 int getTemp();
341
342 /// Static trampoline for the PVCAM end-of-frame callback.
344
345 /// Process a PVCAM end-of-frame callback.
347
348 ///@}
349
350 /** \name Telemeter Interface
351 *
352 * @{
353 */
354 int checkRecordTimes();
355
356 int recordTelem( const telem_stdcam * );
357
358 int recordTelem( const telem_fgtimings * );
359
360 ///@}
361};
362
363pvcamCtrl::pvcamCtrl() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
364{
365 m_powerMgtEnabled = true;
366 m_powerOnWait = 15;
367
368 m_expTime = 0.01;
369 m_expTimeSet = 0.01;
370
371 m_default_x = 1599.5;
372 m_default_y = 1599.5;
373 m_default_w = 512; // we make this smaller by default
374 m_default_h = 512;
375 m_default_bin_x = 1;
376 m_default_bin_y = 1;
377
378 m_full_x = 1599.5;
379 m_full_y = 1599.5;
380 m_full_w = 3200;
381 m_full_h = 3200;
382
383 m_defaultReadoutSpeed = "dynamic_range";
384 m_readoutSpeedNames = { "sensitivity", "speed", "dynamic_range", "sub_electron" };
385 m_readoutSpeedNameLabels = { "Sensitivity", "Speed", "Dynamic Range", "Sub-Electron" };
386
387 m_defaultFanSpeed = "high";
388 m_fanSpeedNames = { "high", "medium", "low", "off" };
389 m_fanSpeedNameLabels = { "High", "Medium", "Low", "Off" };
390
395
396 return;
397}
398
400{
401 config.add( "camera.serialNumber",
402 "",
403 "camera.serialNumber",
404 argType::Required,
405 "camera",
406 "serialNumber",
407 false,
408 "int",
409 "The identifying serial number of the camera." );
410
411 // put this in camera because it is a camera interface config, not a framegrabber thing per se:
412 config.add( "camera.circBuffMaxBytes",
413 "",
414 "camera.circBuffMaxBytes",
415 argType::Required,
416 "camera",
417 "circBuffMaxBytes",
418 false,
419 "int",
420 "Maximum size in bytes of the circular buffer to allocate. Default is 0.5 GB." );
421
422 STDCAMERA_SETUP_CONFIG( config );
423
425
426 config.add( "framegrabber.acqSleep",
427 "",
428 "framegrabber.acqSleep",
429 argType::Required,
430 "framegrabber",
431 "acqSleep",
432 false,
433 "int",
434 "The acquisition pause time, in ns, when no frame is ready. Default is 5000." );
435
436 shutterT::setupConfig( config );
437
438 TELEMETER_SETUP_CONFIG( config );
439}
440
441int pvcamCtrl::loadConfigImpl( mx::app::appConfigurator &_config )
442{
443 _config( m_serialNumber, "camera.serialNumber" );
444 _config( m_circBuffMaxBytes, "camera.circBuffMaxBytes" );
445
446 if( m_serialNumber == "" )
447 {
448 log<text_log>( "camera serial number not provided", logPrio::LOG_CRITICAL );
449 return -1;
450 }
451
453
455
456 _config( m_acqSleep, "framegrabber.acqSleep" );
458
460
461 return 0;
462}
463
465{
466 if( loadConfigImpl( config ) != 0 )
467 {
468 log<text_log>( "error loading config", logPrio::LOG_CRITICAL );
469 m_shutdown = true;
470 }
471}
472
474{
475
477
478 if( sem_init( &m_frSemaphore, 0, 0 ) < 0 )
479 {
480 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing frame ready semaphore" } );
481 }
482
483 if( sem_init( &m_frDoneSemaphore, 0, 0 ) < 0 )
484 {
485 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing frame done semaphore" } );
486 }
487
489
490 if( shutterT::appStartup() < 0 )
491 {
492 return log<software_critical, -1>( { __FILE__, __LINE__ } );
493 }
494
496
497 return 0;
498}
499
501{
502 ///\todo why do we run dev appLogics first?
503
504 if( state() == stateCodes::POWERON )
505 {
506 if( !powerOnWaitElapsed() )
507 {
508 return 0;
509 }
510
512 }
513
515
517
518 // and run dssShutter's appLogic
519 if( shutterT::appLogic() < 0 )
520 {
521 return log<software_error, -1>( { __FILE__, __LINE__ } );
522 }
523
525 {
526 m_reconfig = true; // Trigger a f.g. thread reconfig.
527
528 // Might have gotten here because of a power off.
529 if( powerState() != 1 )
530 {
531 return 0;
532 }
533
534 std::unique_lock<std::mutex> lock( m_indiMutex );
535 if( connect() < 0 )
536 {
537 if( powerState() != 1 || powerStateTarget() != 1 )
538 return 0;
540 }
541
543 return 0;
544 }
545
547 {
550 }
551
553 {
554 if( getTemp() != 0 )
555 {
556 if( powerState() != 1 || powerStateTarget() != 1 )
557 return 0;
559 return 0;
560 }
561
563 {
564 if( powerState() != 1 || powerStateTarget() != 1 )
565 return 0;
567 return 0;
568 }
569
571
573
575 recordCamera();
576 }
577
578 return 0;
579}
580
582{
583 if( m_handle != -1 )
584 {
585 if( !pl_cam_close( m_handle ) )
586 {
587 log_pvcam_software_error( "pl_cam_close", "continuing" );
588 }
589 m_handle = -1;
590 }
591
592 if( !pl_pvcam_uninit() )
593 {
594 if( pl_error_code() != PL_ERR_LIBRARY_NOT_INITIALIZED ) /// \todo this error code is manually defined
595 {
596 log_pvcam_software_error( "pl_pvcam_uninit", "continuing" );
597 }
598 }
599
601
603
604 if( shutterT::appShutdown() < 0 )
605 {
606 log<software_error>( { __FILE__, __LINE__, "error from shutterT::appShutdown()" } );
607 }
608
610
611 return 0;
612}
613
615{
616 m_expTime = 0.01;
617 m_expTimeSet = 0.01;
618
621
623 {
626 }
627 else
628 {
629 m_fanSpeedName.clear();
630 m_fanSpeedNameSet.clear();
631 }
632
633 m_fanSpeedValid = false;
634
635 return 0;
636}
637
639{
640 return 0;
641}
642
644{
645 return 0;
646}
647
649{
651
652 return 0;
653}
654
656{
657 return 0;
658}
659
661{
662 std::string priorFanSpeed = m_fanSpeedName;
663
664 int32 fanSpeed = FAN_SPEED_HIGH;
665
666 if( m_fanSpeedNameSet == "high" )
667 {
668 fanSpeed = FAN_SPEED_HIGH;
669 }
670 else if( m_fanSpeedNameSet == "medium" )
671 {
672 fanSpeed = FAN_SPEED_MEDIUM;
673 }
674 else if( m_fanSpeedNameSet == "low" )
675 {
676 fanSpeed = FAN_SPEED_LOW;
677 }
678 else if( m_fanSpeedNameSet == "off" )
679 {
680 fanSpeed = FAN_SPEED_OFF;
681 }
682 else
683 {
684 return log<software_error, -1>( { __FILE__, __LINE__, "invalid fan-speed target: " + m_fanSpeedNameSet } );
685 }
686
687 if( pl_set_param( m_handle, PARAM_FAN_SPEED_SETPOINT, static_cast<void *>( &fanSpeed ) ) == false )
688 {
689 log_pvcam_software_error( "pl_set_param", "PARAM_FAN_SPEED_SETPOINT" );
690 return -1;
691 }
692
694 m_fanSpeedValid = true;
695
697 {
698 log<text_log>( "fan speed changed from '" + priorFanSpeed + "' to '" + m_fanSpeedName + "'",
700 }
701 else
702 {
703 log<text_log>( "fan speed set to '" + m_fanSpeedName + "'", logPrio::LOG_NOTICE );
704 }
705
706 recordCamera( true );
707
708 return 0;
709}
710
712{
713 return 0;
714}
715
717{
719
720 if( !pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_MIN, static_cast<void *>( &minExpTime ) ) )
721 {
722 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME ATTR_MIN" );
723 log<software_error>( { __FILE__, __LINE__, "could not set exposure time" } );
724 return -1;
725 }
726
727 if( !pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_MAX, static_cast<void *>( &maxExpTime ) ) )
728 {
729 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME ATTR_MAX" );
730 log<software_error>( { __FILE__, __LINE__, "could not set exposure time" } );
731 return -1;
732 }
733
734 if( m_expTimeSet * 1e6 < minExpTime )
735 {
736 m_expTimeSet = (int)( minExpTime / 1e6 + 0.5 );
737 log<text_log>( "increased m_expTimeSet to: " + std::to_string( m_expTimeSet ), logPrio::LOG_INFO );
738 }
739
740 if( m_expTimeSet * 1e6 > maxExpTime )
741 {
742 m_expTimeSet = (int)( maxExpTime / 1e6 - 0.5 );
743 log<text_log>( "decreased m_expTimeSet to: " + std::to_string( m_expTimeSet ), logPrio::LOG_INFO );
744 }
745
747
748 return 0;
749}
750
752{
753 m_expTimeSet = 1.0 / m_fpsSet;
754 m_fpsSetted = true;
755 return setExpTime();
756}
757
759{
760 if( m_nextROI.w > 3200 )
761 {
762 m_nextROI.w = 3200;
763 }
764
765 int x0 = m_nextROI.x - 0.5 * m_nextROI.w;
766
767 if( x0 < 0 )
768 {
769 m_nextROI.w += x0;
770 m_nextROI.x = 0;
771 }
772
773 int x1 = m_nextROI.x + 0.5 * m_nextROI.w;
774
775 if( x1 > 3199 )
776 {
777 m_nextROI.w = 3199 - x0;
778 m_nextROI.x = x0 + 0.5 * m_nextROI.w;
779 }
780
781 if( m_nextROI.h > 3200 )
782 {
783 m_nextROI.h = 3200;
784 }
785
786 int y0 = m_nextROI.y - 0.5 * m_nextROI.h;
787
788 if( y0 < 0 )
789 {
790 m_nextROI.h += y0;
791 m_nextROI.y = 0;
792 }
793
794 int y1 = m_nextROI.y + 0.5 * m_nextROI.h;
795
796 if( y1 > 3199 )
797 {
798 m_nextROI.h = 3199 - y0;
799 m_nextROI.y = y0 + 0.5 * m_nextROI.h;
800 }
801
802 return 0;
803}
804
806{
807 // This is done in setup acq
809 return 0;
810}
811
813{
814 recordCamera( true );
816}
817
819{
820
821 recordCamera( true );
822 //-- 0: register the callback
824 false ) // Because we registered it last time we configured acq:
825 {
826 log_pvcam_software_error( "pl_cam_deregister_callback", "PL_CALLBACK_EOF" );
827 }
828
831 reinterpret_cast<void *>( &st_endOfFrameCallback ),
832 static_cast<void *>( this ) ) != true )
833 {
834 log_pvcam_software_error( "pl_cam_register_callback_ex3", "PL_CALLBACK_EOF" );
835 return -1;
836 }
837
838 //-- 1: Set speed:
839 int32 value;
840
841 if( m_readoutSpeedNameSet == "sensitivity" )
842 {
843 value = 0;
844 m_8bit = false;
845 }
846 else if( m_readoutSpeedNameSet == "speed" )
847 {
848 value = 1;
849 m_8bit = true;
850 }
851 else if( m_readoutSpeedNameSet == "dynamic_range" )
852 {
853 value = 2;
854 m_8bit = false;
855 }
856 else if( m_readoutSpeedNameSet == "sub_electron" )
857 {
858 value = 3;
859 m_8bit = false;
860 }
861 else
862 {
863 value = 2;
864 m_8bit = false;
865 m_readoutSpeedNameSet = "dynamic_range";
866 }
868
869 if( pl_set_param( m_handle, PARAM_READOUT_PORT, static_cast<void *>( &value ) ) == false )
870 {
871 log_pvcam_software_error( "pl_set_param", "PARAM_READOUT_PORT" );
872 return -1;
873 }
874
875 //-- 2: Set ROI:
877 pvROI.s1 = m_nextROI.x - 0.5 * m_nextROI.w;
878 pvROI.s2 = pvROI.s1 + m_nextROI.w - 1;
879 pvROI.sbin = m_nextROI.bin_x;
880 pvROI.p1 = m_nextROI.y - 0.5 * m_nextROI.h;
881 pvROI.p2 = pvROI.p1 + m_nextROI.h - 1;
882 pvROI.pbin = m_nextROI.bin_y;
883
885
886 m_width = ( pvROI.s2 - pvROI.s1 + 1 ) / pvROI.sbin;
887 m_height = ( pvROI.p2 - pvROI.p1 + 1 ) / pvROI.pbin;
889
890 //-- 3: Setup continuous acquisition
891 uns32 fsize;
892
893 uns32 exptime = m_expTimeSet * 1e6;
894 if( pl_exp_setup_cont( m_handle, 1, &pvROI, TIMED_MODE, exptime, &fsize, CIRC_OVERWRITE ) == false )
895 {
896 log_pvcam_software_error( "pl_exp_setup_cont", "" );
897 m_shutdown = true;
898 return -1;
899 }
900
901 if( pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_CURRENT, &exptime ) == false )
902 {
903 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME" );
904 }
905 m_expTime = ( 1.0 * exptime ) / 1e6;
907
908 uns32 readouttime = 0;
910 {
911 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_TIME" );
912 }
913
914 long64 predelay = 0;
916 {
917 log_pvcam_software_error( "pl_get_param", "PARAM_PRE_TRIGGER_DELAY" );
918 }
919
920 long64 clearing = 0;
922 {
923 log_pvcam_software_error( "pl_get_param", "PARAM_CLEARING_TIME" );
924 }
925
926 long64 postdelay = 0;
928 {
929 log_pvcam_software_error( "pl_get_param", "PARAM_POST_TRIGGER_DELAY" );
930 }
931
932 if( m_fpsSetted )
933 {
934 if( static_cast<long64>( m_expTime * 1000000 ) < readouttime )
935 {
936 // This is as fast as we can go, set expTime to longest possible
937 m_expTimeSet = ( readouttime - 1 ) / 1e6; // Go one usec lower, which will get cleaned up by the camera
938 }
939 else
940 {
941 m_expTimeSet = ( 1.0 / m_fpsSet ) - 2.0 * postdelay / 1e9;
942
943 if( static_cast<long64>( m_expTimeSet * 1000000 ) < readouttime )
944 {
945 // again, Set expTime to longest possible
946 m_expTimeSet = ( readouttime - 1.0 ) / 1e6; // Go one usec lower, which will get cleaned up by the
947 // camera
948 }
949 }
950
951 exptime = m_expTimeSet * 1e6;
953 {
954 log_pvcam_software_error( "pl_exp_setup_cont", "" );
955 m_shutdown = true;
956 return -1;
957 }
958
959 // Note: this call apparently resets exptime to 0 ....
960 if( pl_get_param( m_handle, PARAM_EXPOSURE_TIME, ATTR_CURRENT, &exptime ) == false )
961 {
962 log_pvcam_software_error( "pl_get_param", "PARAM_EXPOSURE_TIME" );
963 }
964
965 m_expTime = ( 1.0 * exptime ) / 1e6;
966
968
969 m_fpsSetted = false;
970
972 {
973 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_TIME" );
974 }
975 }
976
977 if( static_cast<long64>( m_expTime * 1000000 ) < readouttime )
978 {
979 m_fps = 1.0 / ( readouttime / 1e6 + postdelay / 1e9 );
980 }
981 else
982 {
983 m_fps =
984 1.0 / ( m_expTime + 2.0 * postdelay / 1e9 ); // At some speeds there is an extra + ~250/1e9 that is needed.
985 }
986
987 m_fpsSet = m_fps;
988
989 //-- 4: Allocate the acq circular buffer
990 if( m_circBuff != nullptr )
991 {
992 delete[] m_circBuff;
993 m_circBuffBytes = 0;
994 m_circBuff = nullptr;
995 }
996
998
999 m_circBuff = new( std::nothrow ) uns8[m_circBuffBytes];
1000
1001 if( m_circBuff == nullptr )
1002 {
1003 log<software_critical>( { __FILE__, __LINE__, "failed to allocate acquisition circular buffer." } );
1005 return -1;
1006 }
1007
1009 {
1010 if( getFanSpeed() < 0 )
1011 {
1012 return log<software_error, -1>( { __FILE__, __LINE__, "could not get fan speed after acquisition setup" } );
1013 }
1014
1016 {
1017 return log<software_error, -1>(
1018 { __FILE__, __LINE__, "could not restore configured fan speed after acquisition setup" } );
1019 }
1020 }
1021
1022 recordCamera( true );
1023
1024 return 0;
1025}
1026
1028{
1029 return m_fps;
1030}
1031
1033{
1035 {
1036 log_pvcam_software_error( "pv_exp_start_cont", "" );
1037 return -1;
1038 }
1039
1040 log<text_log>( "continuous acquisition started", logPrio::LOG_INFO );
1041 return 0;
1042}
1043
1045{
1046 // See if a frame is ready without waiting
1047 int rv = sem_trywait( &m_frSemaphore );
1048 if( rv == 0 )
1049 {
1051 {
1052 log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
1053 }
1054
1055 return 0;
1056 }
1057 else if( errno != EAGAIN )
1058 {
1059 log<software_critical>( { __FILE__, __LINE__, errno, 0, "sem_trywait" } );
1060 return -1;
1061 }
1062
1063 // if none is ready we pause before going on
1064 mx::sys::nanoSleep( m_acqSleep );
1065
1066 return 1;
1067}
1068
1070{
1071
1072 // Obtain a pointer to the last acquired frame
1073 uns8 *frame;
1074 if( pl_exp_get_latest_frame( m_handle, reinterpret_cast<void **>( &frame ) ) == false )
1075 {
1076 log_pvcam_software_error( "pl_exp_get_latest_frame", "" );
1077 }
1078
1079 if( m_8bit )
1080 {
1081 uint16_t *dest16 = static_cast<uint16_t *>( dest );
1082 uint8_t *src8 = static_cast<uint8_t *>( frame );
1083 for( uint32_t i = 0; i < m_width * m_height; ++i )
1084 {
1085 dest16[i] = src8[i];
1086 }
1087 }
1088 else
1089 {
1090 memcpy( dest, frame, m_width * m_height * 2 );
1091 }
1092
1093 // Now tell the callback it can go on
1094 if( sem_post( &m_frDoneSemaphore ) < 0 )
1095 {
1096 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to frame done semaphore" } );
1097 return -1;
1098 }
1099
1100 return 0;
1101}
1102
1104{
1105 if( pl_exp_stop_cont( m_handle, CCS_HALT ) == false )
1106 {
1107 log_pvcam_software_error( "pl_exp_stop_cont", "" );
1108 }
1109 return 0;
1110}
1111
1113{
1114
1115 // In picam, we had to initialize every time. We'll do that here too.
1116
1117 // So close handle if it's open
1118 if( m_handle != -1 )
1119 {
1120 if( !pl_cam_close( m_handle ) )
1121 {
1122 log_pvcam_software_error( "pl_cam_close", "" );
1123 return -1;
1124 }
1125 m_handle = -1;
1126 }
1127
1128 // Uninit
1129 if( !pl_pvcam_uninit() )
1130 {
1131 if( pl_error_code() != PL_ERR_LIBRARY_NOT_INITIALIZED ) /// \todo this error code is manually defined
1132 {
1133 log_pvcam_software_error( "pl_pvcam_uninit", "continuing" );
1134 }
1135 }
1136
1137 if( !pl_pvcam_init() )
1138 {
1139 log_pvcam_software_error( "pl_pvcam_init", "" );
1140 return -1;
1141 }
1142
1144
1145 // Read the number of cameras in the system.
1146 // This will return total number of PVCAM cameras regardless of interface.
1148 {
1149 log_pvcam_software_error( "pl_cam_get_total", "" );
1150 return -1;
1151 }
1152
1153 if( nrOfCameras == 0 )
1154 {
1155 if( !stateLogged() )
1156 {
1157 log<text_log>( "Found 0 pvcam cameras.", logPrio::LOG_INFO );
1158 }
1160 return 0;
1161 }
1162
1163 log<text_log>( "Found " + std::to_string( nrOfCameras ) + " pvcam cameras.", logPrio::LOG_INFO );
1164
1165 for( int n = 0; n < nrOfCameras; ++n )
1166 {
1167 char camName[CAM_NAME_LEN]{ '\0' };
1168
1169 // Obtain PVCAM-name for this particular camera
1170 if( pl_cam_get_name( n, camName ) != PV_OK )
1171 {
1172 log_pvcam_software_error( "pl_cam_get_name", "" );
1173 return -1;
1174 }
1175
1176 int16_t handle = -1;
1177
1178 // Open to check its serial number
1180 {
1181 log_pvcam_software_error( "pl_cam_open",
1182 "" ); // We log this for now, but with 2 apps running we prob want to ignore
1183 continue;
1184 }
1185
1186 // Read the version of the Device Driver
1187
1189 if( !pl_get_param( handle, PARAM_HEAD_SER_NUM_ALPHA, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1190 {
1191 log_pvcam_software_error( "pl_get_param", "PARAM_HEAD_SER_NUM_ALPHA ATTR_AVAIL" );
1192
1193 if( !pl_cam_close( handle ) )
1194 {
1195 log_pvcam_software_error( "pl_cam_close", "" );
1196 }
1197
1198 return -1;
1199 }
1200
1201 if( isAvailable )
1202 {
1203 char camSerial[MAX_ALPHA_SER_NUM_LEN]{ '\0' };
1204
1205 if( !pl_get_param( handle, PARAM_HEAD_SER_NUM_ALPHA, ATTR_CURRENT, static_cast<void *>( camSerial ) ) )
1206 {
1207 log_pvcam_software_error( "pl_get_param", "PARAM_HEAD_SER_NUM_ALPHA ATTR_CURRENT" );
1208
1209 if( !pl_cam_close( handle ) )
1210 {
1211 log_pvcam_software_error( "pl_cam_close", "" );
1212 }
1213
1214 return -1;
1215 }
1216
1217 if( camSerial == m_serialNumber )
1218 {
1219 state( stateCodes::NOTCONNECTED ); // not strictly true, but logically true until m_handle is set
1221 m_handle = handle;
1222 break;
1223 }
1224 }
1225
1226 // If we're here then either it didn't have a serial number, or it didn't have the right serial number
1227 if( !pl_cam_close( handle ) )
1228 {
1229 log_pvcam_software_error( "pl_cam_close", "" );
1230 return -1;
1231 }
1232 }
1233
1234 if( m_handle > -1 )
1235 {
1236 log<text_log>( "Opened camera " + m_serialNumber + " at " + m_camName, logPrio::LOG_INFO );
1238
1239 int32 res;
1240 uns16 idx;
1241
1242 // Set exposure resolution to usec.
1243
1244 idx = 1;
1245 if( pl_set_param( m_handle, PARAM_EXP_RES_INDEX, &idx ) == false )
1246 {
1247 log_pvcam_software_error( "pl_set_param", "PARAM_EXP_RES_INDEX" );
1248 }
1249
1250 if( pl_get_param( m_handle, PARAM_EXP_RES, ATTR_CURRENT, &res ) == false )
1251 {
1252 log_pvcam_software_error( "pl_get_param", "PARAM_EXP_RES" );
1253 }
1254
1256 {
1257 log_pvcam_software_error( "pl_get_param", "PARAM_EXP_RES_INDEX" );
1258 }
1259
1261
1263 {
1264 return log<software_error, -1>( { __FILE__, __LINE__, "could not get fan speed" } );
1265 }
1266
1268 {
1270 }
1271
1273 {
1274 return log<software_error, -1>( { __FILE__, __LINE__, "could not set fan speed" } );
1275 }
1276 }
1277 else
1278 {
1279 if( !stateLogged() )
1280 {
1281 log<text_log>( "camera not found", logPrio::LOG_INFO );
1282 }
1284 }
1285
1286 return 0;
1287}
1288
1290{
1292 {
1293 return -1;
1294 }
1295
1296 uns32 nports;
1297
1298 if( pl_get_param( m_handle, PARAM_READOUT_PORT, ATTR_COUNT, static_cast<void *>( &nports ) ) == false )
1299 {
1300 log_pvcam_software_error( "pl_get_param", "PARAM_READOUT_PORT" );
1301 return -1;
1302 }
1303
1304 std::cerr << "Found " << nports << " ports\n";
1305
1306 m_ports.resize( nports );
1307
1308 for( uns32 p = 0; p < nports; ++p )
1309 {
1312 {
1313 log_pvcam_software_error( "pl_enum_str_length", "PARAM_READOUT_PORT" );
1314 return -1;
1315 }
1316
1317 char *text = new( std::nothrow ) char[strLength];
1318 if( !text )
1319 {
1320 ///\todo log this properly
1321 std::cerr << "failed to allocate string\n";
1322 return -1;
1323 }
1324
1325 int32 value;
1327 {
1328 log_pvcam_software_error( "pl_get_enum_param", "PARAM_READOUT_PORT" );
1329 delete[] text;
1330 return false;
1331 }
1332
1333 m_ports[p].index = p;
1334 m_ports[p].value = value;
1335 m_ports[p].name = text;
1336
1337 std::cerr << "Port: " << p << " name: " << text << " value: " << value << "\n";
1338
1339 delete[] text;
1340
1341 if( pl_set_param( m_handle, PARAM_READOUT_PORT, static_cast<void *>( &value ) ) == false )
1342 {
1343 log_pvcam_software_error( "pl_set_param", "PARAM_READOUT_PORT" );
1344 return -1;
1345 }
1346
1347 uns32 nspeeds;
1348 if( pl_get_param( m_handle, PARAM_SPDTAB_INDEX, ATTR_COUNT, static_cast<void *>( &nspeeds ) ) == false )
1349 {
1350 log_pvcam_software_error( "pl_get_param", "PARAM_SPDTAB_INDEX" );
1351 return -1;
1352 }
1353 std::cerr << " Speeds: " << nspeeds << "\n";
1354
1355 m_ports[p].speeds.resize( nspeeds );
1356
1357 for( uns32 s = 0; s < nspeeds; ++s )
1358 {
1359 if( pl_set_param( m_handle, PARAM_SPDTAB_INDEX, static_cast<void *>( &s ) ) == false )
1360 {
1361 log_pvcam_software_error( "pl_set_param", "PARAM_SPDTAB_INDEX" );
1362 return -1;
1363 }
1364
1365 uns16 pixtime;
1366 if( pl_get_param( m_handle, PARAM_PIX_TIME, ATTR_CURRENT, static_cast<void *>( &pixtime ) ) == false )
1367 {
1368 log_pvcam_software_error( "pl_get_param", "PARAM_PIX_TIME" );
1369 return -1;
1370 }
1371
1372 m_ports[p].speeds[s].pixTime = pixtime;
1373
1374 uns32 ngains;
1375 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_COUNT, static_cast<void *>( &ngains ) ) == false )
1376 {
1377 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_COUNT" );
1378 return -1;
1379 }
1380
1381 int16 ming;
1382 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_MIN, static_cast<void *>( &ming ) ) == false )
1383 {
1384 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_MIN" );
1385 return -1;
1386 }
1387
1388 int16 maxg;
1389 if( pl_get_param( m_handle, PARAM_GAIN_INDEX, ATTR_MIN, static_cast<void *>( &maxg ) ) == false )
1390 {
1391 log_pvcam_software_error( "pl_get_param", "PARAM_GAIN_INDEX ATTR_MAX" );
1392 return -1;
1393 }
1394
1395 std::cerr << " Speed: " << s << " " << " pixtime: " << pixtime << " gains: " << ngains << " [" << ming
1396 << "-" << maxg << "]\n";
1397
1398 m_ports[p].speeds[s].minG = ming;
1399 m_ports[p].speeds[s].maxG = maxg;
1400
1401 m_ports[p].speeds[s].gains.resize( ngains );
1402
1403 for( uns32 g = 0; g < ngains; ++g )
1404 {
1405
1406 int16 gg = ming + g;
1407 if( pl_set_param( m_handle, PARAM_GAIN_INDEX, static_cast<void *>( &gg ) ) == false )
1408 {
1409 log_pvcam_software_error( "pl_set_param", "PARAM_GAIN_INDEX" );
1410 return -1;
1411 }
1412
1414 if( pl_get_param( m_handle, PARAM_BIT_DEPTH, ATTR_CURRENT, static_cast<void *>( &bitdepth ) ) == false )
1415 {
1416 log_pvcam_software_error( "pl_get_param", "PARAM_BIT_DEPTH ATTR_CURRENT" );
1417 return -1;
1418 }
1419 std::cerr << " Gain: " << g << " bitdepth: " << bitdepth << "\n";
1420 }
1421 }
1422 }
1423
1424 return 0;
1425}
1426
1427void pvcamCtrl::dumpEnum( uns32 paramID, const std::string &paramMnem )
1428{
1429
1430 if( state() == stateCodes::CONNECTED )
1431 {
1432 uns32 count;
1433
1434 if( PV_OK != pl_get_param( m_handle, paramID, ATTR_COUNT, static_cast<void *>( &count ) ) )
1435 {
1436 log_pvcam_software_error( "pl_get_param", paramMnem );
1437 // TODO: Handle error
1438 return;
1439 }
1440 if( count == 0 )
1441 {
1442 std::cerr << paramMnem << ": count 0\n";
1443 return;
1444 }
1445 for( uns32 n = 0; n < count; ++n )
1446 {
1449 {
1450 log_pvcam_software_error( "pl_enum_str_length", paramMnem );
1451 // TODO: Handle error
1452 break;
1453 }
1454 char *text = new( std::nothrow ) char[strLength];
1455 if( !text )
1456 {
1457 // TODO: Handle error
1458 break;
1459 }
1460 int32 value;
1461 if( PV_OK != pl_get_enum_param( m_handle, paramID, n, &value, text, strLength ) )
1462 {
1463 log_pvcam_software_error( "pl_get_enum_param", paramMnem );
1464 // TODO: Handle error
1465 delete[] text;
1466 break;
1467 }
1468 std::cerr << paramMnem;
1469 fprintf( stderr, " item at index %u, value: %d, text: '%s'\n", n, value, text );
1470 delete[] text;
1471 }
1472 }
1473 else
1474 {
1475 std::cerr << "dumpEnum: not CONNECTED\n";
1476 }
1477}
1478
1480{
1481 if( state() == stateCodes::OPERATING )
1482 {
1483 return 0;
1484 }
1485
1487 if( !pl_get_param( m_handle, PARAM_TEMP_SETPOINT, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1488 {
1489 if( powerState() != 1 || powerStateTarget() != 1 )
1490 return 0;
1491 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1493 }
1494
1495 int16 stemp;
1496 if( isAvailable ) // Maybe this is a separate check. Don't yet know what happens when acquiring
1497 {
1498 if( !pl_get_param( m_handle, PARAM_TEMP_SETPOINT, ATTR_CURRENT, static_cast<void *>( &stemp ) ) )
1499 {
1500 if( powerState() != 1 || powerStateTarget() != 1 )
1501 return 0;
1502 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1504 }
1505
1506 m_ccdTempSetpt = stemp / 100.0;
1507 }
1508
1509 if( !pl_get_param( m_handle, PARAM_TEMP, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1510 {
1511 if( powerState() != 1 || powerStateTarget() != 1 )
1512 return 0;
1513 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1515 }
1516
1517 int16 ctemp;
1518 if( isAvailable ) // Maybe this is a separate check. Don't yet know what happens when acquiring
1519 {
1520 if( !pl_get_param( m_handle, PARAM_TEMP, ATTR_CURRENT, static_cast<void *>( &ctemp ) ) )
1521 {
1522 if( powerState() != 1 || powerStateTarget() != 1 )
1523 return 0;
1524 log_pvcam_software_error( "pl_get_param", "PARAM_TEMP ATTR_AVAIL" );
1526 }
1527
1528 m_ccdTemp = ctemp / 100.0;
1529 }
1530
1532 {
1533 m_tempControlStatus = true;
1534 m_tempControlOnTarget = false;
1535 m_tempControlStatusStr = "UNLOCKED";
1536 }
1537 else
1538 {
1539 m_tempControlStatus = true;
1540 m_tempControlOnTarget = true;
1541 m_tempControlStatusStr = "LOCKED";
1542 }
1543
1544 return 0;
1545}
1546
1548{
1550 {
1551 return 0;
1552 }
1553
1555 if( !pl_get_param( m_handle, PARAM_FAN_SPEED_SETPOINT, ATTR_AVAIL, static_cast<void *>( &isAvailable ) ) )
1556 {
1557 if( powerState() != 1 || powerStateTarget() != 1 )
1558 return 0;
1559 log_pvcam_software_error( "pl_get_param", "PARAM_FAN_SPEED_SETPOINT ATTR_AVAIL" );
1561 return -1;
1562 }
1563
1564 if( !isAvailable )
1565 {
1566 return log<software_error, -1>(
1567 { __FILE__, __LINE__, "PARAM_FAN_SPEED_SETPOINT not available while fan control is enabled" } );
1568 }
1569
1570 int32 fanSpeed;
1571 if( !pl_get_param( m_handle, PARAM_FAN_SPEED_SETPOINT, ATTR_CURRENT, static_cast<void *>( &fanSpeed ) ) )
1572 {
1573 if( powerState() != 1 || powerStateTarget() != 1 )
1574 return 0;
1575 log_pvcam_software_error( "pl_get_param", "PARAM_FAN_SPEED_SETPOINT ATTR_CURRENT" );
1577 return -1;
1578 }
1579
1580 if( fanSpeed == FAN_SPEED_HIGH )
1581 {
1582 m_fanSpeedName = "high";
1583 }
1584 else if( fanSpeed == FAN_SPEED_MEDIUM )
1585 {
1586 m_fanSpeedName = "medium";
1587 }
1588 else if( fanSpeed == FAN_SPEED_LOW )
1589 {
1590 m_fanSpeedName = "low";
1591 }
1592 else if( fanSpeed == FAN_SPEED_OFF )
1593 {
1594 m_fanSpeedName = "off";
1595 }
1596 else
1597 {
1598 return log<software_error, -1>(
1599 { __FILE__, __LINE__, "unknown PVCAM fan-speed value: " + std::to_string( fanSpeed ) } );
1600 }
1601
1602 m_fanSpeedValid = true;
1603
1604 return 0;
1605}
1606
1607void pvcamCtrl::st_endOfFrameCallback( FRAME_INFO *finfo, void *pvcamCtrlInst )
1608{
1609 static_cast<pvcamCtrl *>( pvcamCtrlInst )->endOfFrameCallback( finfo );
1610}
1611
1612void pvcamCtrl::endOfFrameCallback( FRAME_INFO *finfo )
1613{
1614 m_frameInfo = *finfo;
1615
1616 // 0 out the frDoneSemaphore just to be sure
1617 int semval;
1619 while( semval > 0 )
1620 {
1623 }
1624
1625 // Now tell the writer to get going
1626 if( sem_post( &m_frSemaphore ) < 0 )
1627 {
1628 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to frame ready semaphore" } );
1629 return;
1630 }
1631
1632 // Now wait on the frame done semaphore
1633 timespec ts;
1634
1635 if( clock_gettime( CLOCK_REALTIME, &ts ) < 0 )
1636 {
1637 log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
1638 }
1639
1640 mx::sys::timespecAddNsec( ts, 1e9 ); // We wait for up to one second for the frame done processing signal
1641
1643}
1644
1649
1651{
1652 return recordCamera( true );
1653}
1654
1656{
1657 return recordFGTimings( true );
1658}
1659
1660} // namespace app
1661} // namespace MagAOX
1662
1663#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
Default 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_fanSpeedNames
Valid fan-control option names for the INDI selection switch.
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.
std::string m_fanSpeedNameSet
Requested fan-control option name.
bool m_fanSpeedControlEnabled
Whether or not fan-speed control is published through INDI.
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.
std::string m_fanSpeedName
Current fan-control option name.
float m_full_x
The full ROI center x coordinate.
std::string m_defaultFanSpeed
The default fan speed to apply after power on.
float m_ccdTemp
The current temperature, in C.
bool m_fanSpeedValid
True once the current fan-control state is known.
bool m_tempControlOnTarget
Whether or not the temperature control system is on its target temperature.
std::vector< std::string > m_fanSpeedNameLabels
Optional GUI labels for the fan-control options.
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
int setNextROI()
Queue the requested ROI for the next acquisition setup.
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
int setTempControl()
PVCAM does not expose a separate temperature-control toggle.
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
int connect()
Find and open the configured PVCAM camera.
friend class pvcamCtrl_test
Definition pvcamCtrl.hpp:86
void endOfFrameCallback(FRAME_INFO *finfo)
Process a PVCAM end-of-frame callback.
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 setFPS()
PVCAM does not expose FPS as a direct settable control in this app.
int recordTelem(const telem_stdcam *)
float fps()
Return the current measured frame rate.
int setExpTime()
Queue the requested exposure time for the next acquisition setup.
static void st_endOfFrameCallback(FRAME_INFO *finfo, void *pvcamCtrlInst)
Static trampoline for the PVCAM end-of-frame callback.
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.
int setReadoutSpeed()
Queue the requested readout-speed selection for the next acquisition setup.
int setFanSpeed()
Set the fan speed according to the configured stdCamera target.
std::vector< speed > speeds
static constexpr bool c_stdCamera_hasShutter
app:dev config to tell stdCamera to expose shutter controls
int acquireAndCheckValid()
Wait for the next frame-ready signal and validate the acquisition state.
static constexpr bool c_stdCamera_fpsCtrl
app::dev config to tell stdCamera to expose FPS controls
int configureAcquisition()
Configure the PVCAM acquisition state for the pending settings.
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
int startAcquisition()
Start continuous PVCAM acquisition.
static constexpr bool c_stdCamera_fanSpeed
app::dev config to tell stdCamera to expose fan-speed control
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.
int powerOnDefaults()
Set defaults for a power-on state.
~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)
Copy the latest PVCAM frame into the destination image stream.
dev::dssShutter< pvcamCtrl > shutterT
Definition pvcamCtrl.hpp:82
int setEMGain()
PVCAM does not expose EM gain through this app.
static constexpr bool c_stdCamera_readoutSpeed
app::dev config to tell stdCamera to expose readout speed controls
int fillSpeedTable()
Enumerate the PVCAM readout-speed table for the connected camera.
int reconfig()
Stop acquisition so the framegrabber can reconfigure.
void dumpEnum(uns32 paramID, const std::string &paramMnem)
Dump the values of a PVCAM enumerated parameter for debugging.
int setTempSetPt()
PVCAM does not expose a writable detector temperature setpoint in this app.
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
int getFanSpeed()
Get the current fan speed from the camera.
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.
int setVShiftSpeed()
PVCAM does not expose vertical-shift control through this app.
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
int getTemp()
Get the current detector temperature and set point from the camera.
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.
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:19
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
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.
@ 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.
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.