API
 
Loading...
Searching...
No Matches
ocam2KCtrl.hpp
Go to the documentation of this file.
1/** \file ocam2KCtrl.hpp
2 * \brief The MagAO-X OCAM2K EMCCD camera controller.
3 *
4 * \ingroup ocam2KCtrl_files
5 */
6
7#ifndef ocam2KCtrl_hpp
8#define ocam2KCtrl_hpp
9
10#include <fcntl.h>
11#include <edtinc.h>
12#include <unistd.h>
13
14#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
15#include "../../magaox_git_version.h"
16
17typedef MagAOX::app::MagAOXApp<true> MagAOXAppT; // This needs to be before pdvUtils.hpp for logging to work.
18
19#include "fli/ocam2_sdk.h"
20#include "ocamUtils.hpp"
21
22namespace MagAOX
23{
24namespace app
25{
26
27/** \defgroup ocam2KCtrl OCAM2K EMCCD Camera
28 * \brief Control of the OCAM2K EMCCD Camera.
29 *
30 * <a href="../handbook/operating/software/apps/ocam2KCtrl.html">Application Documentation</a>
31 *
32 * \ingroup apps
33 *
34 */
35
36/** \defgroup ocam2KCtrl_files OCAM2K EMCCD Camera Files
37 * \ingroup ocam2KCtrl
38 */
39
40/** MagAO-X application to control the OCAM 2K EMCCD
41 *
42 * \ingroup ocam2KCtrl
43 *
44 */
45class ocam2KCtrl : public MagAOXApp<>,
46 public dev::stdCamera<ocam2KCtrl>,
47 public dev::edtCamera<ocam2KCtrl>,
48 public dev::frameGrabber<ocam2KCtrl>,
49 public dev::dssShutter<ocam2KCtrl>,
50 public dev::telemeter<ocam2KCtrl>
51{
52 friend class dev::stdCamera<ocam2KCtrl>;
53 friend class dev::edtCamera<ocam2KCtrl>;
54 friend class dev::frameGrabber<ocam2KCtrl>;
55 friend class dev::dssShutter<ocam2KCtrl>;
56 friend class dev::telemeter<ocam2KCtrl>;
57
59
60 public:
61 /** \name app::dev Configurations
62 *@{
63 */
64 static constexpr bool c_stdCamera_tempControl =
65 true; ///< app::dev config to tell stdCamera to expose temperature controls
66
67 static constexpr bool c_stdCamera_temp =
68 true; ///< app::dev config to tell stdCamera to expose temperature (ignored since tempControl==true)
69
70 static constexpr bool c_stdCamera_readoutSpeed =
71 false; ///< app::dev config to tell stdCamera not to expose readout speed controls
72
73 static constexpr bool c_stdCamera_vShiftSpeed =
74 false; ///< app:dev config to tell stdCamera not to expose vertical shift speed control
75 static constexpr bool c_stdCamera_fanSpeed =
76 false; ///< app::dev config to tell stdCamera not to expose fan-speed control
77
78 static constexpr bool c_stdCamera_emGain = true; ///< app::dev config to tell stdCamera to expose EM gain controls
79
80 static constexpr bool c_stdCamera_exptimeCtrl =
81 false; ///< app::dev config to tell stdCamera not to expose exposure time controls
82
83 static constexpr bool c_stdCamera_fpsCtrl = true; ///< app::dev config to tell stdCamera to expose FPS controls
84
85 static constexpr bool c_stdCamera_fps =
86 true; ///< app::dev config to tell stdCamera not to expose FPS status (ignored since fpsCtrl==true)
87
88 static constexpr bool c_stdCamera_synchro =
89 true; ///< app::dev config to tell stdCamera to expose synchro mode controls
90
91 static constexpr bool c_stdCamera_usesModes =
92 true; ///< app:dev config to tell stdCamera not to expose mode controls
93
94 static constexpr bool c_stdCamera_usesROI = false; ///< app:dev config to tell stdCamera to expose ROI controls
95
96 static constexpr bool c_stdCamera_cropMode =
97 false; ///< app:dev config to tell stdCamera to expose Crop Mode controls
98
99 static constexpr bool c_stdCamera_hasShutter =
100 true; ///< app:dev config to tell stdCamera to expose shutter controls
101
102 static constexpr bool c_stdCamera_usesStateString =
103 true; ///< app::dev confg to tell stdCamera to expose the state string property
104
105 static constexpr bool c_edtCamera_relativeConfigPath =
106 true; ///< app::dev config to tell edtCamera to use relative path to camera config file
107
108 static constexpr bool c_frameGrabber_flippable =
109 false; ///< app:dev config to tell framegrabber these images can not be flipped
110
111 ///@}
112 protected:
113 /** \name configurable parameters
114 *@{
115 */
116
117 std::string m_ocamDescrambleFile; ///< Path to the OCAM 2K pixel descrambling file, relative to the MagAO-X config
118 ///< directory.
119
120 std::string m_syncShmimName; ///< Name of the sync-only ImageStreamIO output. Defaults to `framegrabber.shmimName +
121 ///< "_sync"`.
122
123 ///@}
124
125 static constexpr uint32_t c_syncStreamWidth{ 1 }; ///< Width of the sync-only ImageStreamIO stream.
126 static constexpr uint32_t c_syncStreamHeight{ 1 }; ///< Height of the sync-only ImageStreamIO stream.
127 static constexpr uint32_t c_syncStreamDepth{ 1 }; ///< Depth of the sync-only ImageStreamIO stream.
128 static constexpr uint8_t c_syncStreamDataType{ _DATATYPE_UINT8 }; ///< Data type of the sync-only stream.
129
130 ocam2_id m_ocam2_id{ 0 }; ///< OCAM SDK id.
131
132 long m_currImageNumber{ -1 }; ///< The current image number, retrieved from the raw image itself.
133
134 long m_lastImageNumber{ -1 }; ///< The last image number saved from the previous acquisition loop.
135
136 bool m_protectionReset{ false }; ///< Flag indicating that protection has been reset at least once.
137
138 unsigned m_protectionResetConfirmed{ 0 }; ///< Counter indicating the number of times that the protection reset has
139 ///< been requested within 10 seconds, for confirmation.
140
142 0 }; ///< The time at which protection reset was requested. You have 10 seconds to confirm.
143
145 false }; ///< Tracks that power-on defaults still need to restore the configured temperature setpoint.
146
147 ocamTemps m_temps; ///< Structure holding the last temperature measurement.
148
149 unsigned m_digitalBinX{ 1 }; ///< Digital x-binning factor applied after descrambling.
150
151 unsigned m_digitalBinY{ 1 }; ///< Digital y-binning factor applied after descrambling.
152
153 bool m_digitalBin{ false }; ///< Indicates whether post-descramble digital binning is active for the current mode.
154
155 mx::improc::eigenImage<int16_t>
156 m_digitalBinWork; ///< Scratch image holding the full descrambled frame before digital binning.
157
158 std::string m_syncDevice{
159 "fxngensync" }; ///< INDI device providing the external sync frequency when synchro mode is enabled.
160 std::string m_syncFreqProp{ "C1freq" }; ///< INDI property name reporting the external sync frequency.
161
162 float m_syncFreq{ 0 }; ///< Current externally supplied sync frequency in Hz.
163
164 IMAGE *m_syncImageStream{ nullptr }; ///< Secondary 1x1 uint8 ImageStreamIO stream used only for frame metadata
165 ///< and semaphores. Its lifetime is sequenced by the framegrabber thread and
166 ///< app shutdown so per-frame publication can remain lock-free.
167
168 std::recursive_mutex
169 m_cameraMutex; ///< Protects EDT PDV access and OCAM SDK lifetime across reconfigure, grab, and control paths.
170
171 public:
172 /// Default c'tor
173 ocam2KCtrl();
174
175 /// Destructor
177
178 /// Setup the configuration system (called by MagAOXApp::setup())
179 virtual void setupConfig();
180
181 /// load the configuration system results (called by MagAOXApp::setup())
182 virtual void loadConfig();
183
184 /// Startup functions
185 /** Sets up the INDI vars, and the f.g. thread.
186 *
187 */
188 virtual int appStartup();
189
190 /// Implementation of the FSM for the OCAM 2K.
191 virtual int appLogic();
192
193 /// Implementation of the on-power-off FSM logic
194 virtual int onPowerOff();
195
196 /// Implementation of the while-powered-off FSM
198
199 /// Do any needed shutdown tasks.
200 virtual int appShutdown();
201
202 /// Get the current device temperatures
203 /**
204 * \returns 0 on success
205 * \returns -1 on error
206 */
207 int getTemps();
208
209 /// Get the current frame rate.
210 /**
211 * \returns 0 on success
212 * \returns -1 on error
213 */
214 int getFPS();
215
216 /** \name stdCamera Interface
217 *
218 * @{
219 */
220
221 /// Set defaults for a power on state.
222 /**
223 * \returns 0 on success
224 * \returns -1 on error
225 */
226 int powerOnDefaults();
227
228 /// Turn temperature control on or off.
229 /** Sets temperature control on or off based on the current value of m_tempControlStatus
230 * \returns 0 on success
231 * \returns -1 on error
232 */
233 int setTempControl();
234
235 /// Set the CCD temperature setpoint [stdCamera interface].
236 /** Sets the temperature to m_ccdTempSetpt.
237 * \returns 0 on success
238 * \returns -1 on error
239 */
240 int setTempSetPt();
241
242 /// Set the frame rate. [stdCamera interface]
243 /** Sets the frame rate to m_fpsSet.
244 *
245 * \returns 0 on success
246 * \returns -1 on error
247 */
248 int setFPS();
249
250 /// Set the synchro state. [stdCamera interface]
251 /** Sets the synchro state to m_synchroSet.
252 *
253 * \returns 0 on success
254 * \returns -1 on error
255 */
256 int setSynchro();
257
258 /// Required by stdCamera, but this does not do anything for this camera [stdCamera interface]
259 /**
260 * \returns 0 always
261 */
262 int setExpTime();
263
264 /// Required by stdCamera, but this does not do anything for this camera [stdCamera interface]
265 /**
266 * \returns 0 always
267 */
268 int setNextROI();
269
270 /// Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface]
271 /**
272 * \returns 0 always
273 */
274 int setShutter( int sh /**< [in] requested shutter state */ );
275
276 /// Return the current stdCamera state string.
277 std::string stateString();
278
279 /// Report whether the current stdCamera state string is valid for persistence and telemetry.
280 bool stateStringValid();
281
282 ///@}
283
284 /// Reset the EM Protection
285 /**
286 * \returns 0 on success
287 * \returns -1 on error
288 */
289 int resetEMProtection();
290
291 /// Get the current EM Gain.
292 /**
293 * \returns 0 on success
294 * \returns -1 on error
295 */
296 int getEMGain();
297
298 /// Set the EM gain.
299 /** Sets it to the value of stdCamera::m_emGainSet
300 *
301 * \returns 0 on success
302 * \returns -1 on error
303 */
304 int setEMGain();
305
306 /// Implementation of the framegrabber configureAcquisition interface
307 /** Sends the mode command over serial, sets the FPS, and initializes the OCAM SDK.
308 *
309 * \returns 0 on success
310 * \returns -1 on error
311 */
313
314 /// Implementation of the frameGrabber fps interface
315 /** Just returns the value of m_fps
316 */
317 float fps();
318
319 /// Implementation of the framegrabber startAcquisition interface
320 /** Initializes m_lastImageNumber, and calls edtCamera::pdvStartAcquisition
321 *
322 * \returns 0 on success
323 * \returns -1 on error
324 */
325 int startAcquisition();
326
327 /// Implementation of the framegrabber acquireAndCheckValid interface
328 /** Calls edtCamera::pdvAcquire, then analyzes the OCAM generated framenumber for skips and corruption.
329 *
330 * \returns 0 on success
331 * \returns -1 on error
332 */
334
335 /// Implementation of the framegrabber loadImageIntoStream interface
336 /** Conducts the OCAM descramble.
337 *
338 * \returns 0 on success
339 * \returns -1 on error
340 */
341 int loadImageIntoStream( void *dest /**< [in] destination image buffer */ );
342
343 /// Implementation of the framegrabber reconfig interface
344 /** Locks the INDI mutex and calls edtCamera::pdvReconfig.
345 * \returns 0 on success
346 * \returns -1 on error
347 */
348 int reconfig();
349
350 /// Publish the sync-only stream immediately after the main framegrabber publication.
351 /** This hot path relies on framegrabber sequencing: configureAcquisition() and this hook both run on the
352 * framegrabber thread, while appShutdown() destroys the sync stream only after frameGrabber::appShutdown()
353 * joins that thread.
354 */
355 int frameGrabberPostPublish( IMAGE *imageStream /**< [in] main framegrabber stream that was just posted */ );
356
357 protected:
358 /// Ensure the sync-only ImageStreamIO stream exists with the expected 1x1 uint8 layout.
359 int ensureSyncStream();
360
361 /// Destroy the sync-only ImageStreamIO stream owned by this app.
362 int destroySyncStream();
363
364 // INDI:
365 protected:
366 // declare our properties
367 pcf::IndiProperty m_indiP_temps; ///< INDI property publishing the latest camera temperatures.
368 pcf::IndiProperty m_indiP_emProt; ///< INDI property publishing the EM protection state.
369 pcf::IndiProperty m_indiP_emProtReset; ///< INDI property handling operator requests to reset EM protection.
370
371 pcf::IndiProperty m_indiP_syncFreq; ///< INDI subscription to the external sync-frequency source.
372
373 public:
375
377
378 /** \name Telemeter Interface
379 *
380 * @{
381 */
382 int checkRecordTimes();
383
385
387
389
390 int
391 recordTemps( bool force = false /**< [in] whether to force a telemetry record even if values have not changed */ );
392
393 ///@}
394};
395
397{
398 //--- MagAOXApp Power Mgt. ---
399 m_powerMgtEnabled = true;
400 m_powerOnWait = 10;
401
402 //--- stdCamera ---
403 m_startupTemp = 20;
404
405 m_maxEMGain = 600;
406
407 return;
408}
409
411{
412 return;
413}
414
416{
418
420
421 config.add( "camera.ocamDescrambleFile",
422 "",
423 "camera.ocamDescrambleFile",
424 argType::Required,
425 "camera",
426 "ocamDescrambleFile",
427 false,
428 "string",
429 "The path of the OCAM descramble file, relative to MagAOX/config." );
430
432
433 config.add( "framegrabber.syncShmimName",
434 "",
435 "framegrabber.syncShmimName",
436 argType::Required,
437 "framegrabber",
438 "syncShmimName",
439 false,
440 "string",
441 "The name of the 1x1 uint8 ImageStreamIO sync stream used only for frame metadata and semaphores. "
442 "Defaults to framegrabber.shmimName + \"_sync\"." );
443
445
447}
448
450{
453
454 config( m_ocamDescrambleFile, "camera.ocamDescrambleFile" );
455
456 if( m_maxEMGain < 1 )
457 {
458 m_maxEMGain = 1;
459 log<text_log>( "maxEMGain set to 1" );
460 }
461
462 if( m_maxEMGain > 600 )
463 {
464 m_maxEMGain = 600;
465 log<text_log>( "maxEMGain set to 600" );
466 }
467
469 config( m_syncShmimName, "framegrabber.syncShmimName" );
470 if( m_syncShmimName == "" )
471 {
472 m_syncShmimName = m_shmimName + "_sync";
473 }
476}
477
479{
480 if( m_syncImageStream != nullptr )
481 {
482 uint32_t syncWidth = m_syncImageStream->md[0].size[0];
485
486 if( m_syncImageStream->md[0].naxis > 1 )
487 {
488 syncHeight = m_syncImageStream->md[0].size[1];
489 }
490
491 if( m_syncImageStream->md[0].naxis > 2 )
492 {
493 syncDepth = m_syncImageStream->md[0].size[2];
494 }
495
498 {
499 return 0;
500 }
501
504 m_syncImageStream = nullptr;
505 }
506
507 char syncFileName[1024];
509
511 if( syncFd != -1 )
512 {
513 ::close( syncFd );
514
517 {
518 return log<software_error, -1>(
519 { __FILE__, __LINE__, "error opening existing sync ImageStreamIO stream" } );
520 }
521
523 {
524 return log<software_error, -1>(
525 { __FILE__, __LINE__, "error destroying existing sync ImageStreamIO stream" } );
526 }
527 }
528
529 m_syncImageStream = reinterpret_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
530 if( m_syncImageStream == nullptr )
531 {
532 return log<software_error, -1>( { __FILE__, __LINE__, "error allocating sync ImageStreamIO stream" } );
533 }
534
536
538 m_syncShmimName.c_str(),
539 3,
540 imsize,
542 -1,
543 1,
545 0,
547 0 ) != IMAGESTREAMIO_SUCCESS )
548 {
550 m_syncImageStream = nullptr;
551 return log<software_error, -1>( { __FILE__, __LINE__, "error creating sync ImageStreamIO stream" } );
552 }
553
554 m_syncImageStream->array.UI8[0] = 0;
555 m_syncImageStream->md[0].cnt0 = 0;
556 m_syncImageStream->md[0].cnt1 = 0;
557 m_syncImageStream->md[0].write = 0;
558 m_syncImageStream->writetimearray[0] = m_syncImageStream->md[0].writetime;
559 m_syncImageStream->atimearray[0] = m_syncImageStream->md[0].atime;
560 m_syncImageStream->cntarray[0] = 0;
561
562 return 0;
563}
564
566{
567 if( m_syncImageStream == nullptr )
568 {
569 return 0;
570 }
571
572 int rv = 0;
573
575 {
576 rv = log<software_error, -1>( { __FILE__, __LINE__, "error destroying sync ImageStreamIO stream" } );
577 }
578
580 m_syncImageStream = nullptr;
581
582 return rv;
583}
584
586{
587 REG_INDI_NEWPROP_NOCB( m_indiP_temps, "temps", pcf::IndiProperty::Number );
588 m_indiP_temps.add( pcf::IndiElement( "cpu" ) );
589 m_indiP_temps["cpu"].set( 0 );
590 m_indiP_temps.add( pcf::IndiElement( "power" ) );
591 m_indiP_temps["power"].set( 0 );
592 m_indiP_temps.add( pcf::IndiElement( "bias" ) );
593 m_indiP_temps["bias"].set( 0 );
594 m_indiP_temps.add( pcf::IndiElement( "water" ) );
595 m_indiP_temps["water"].set( 0 );
596 m_indiP_temps.add( pcf::IndiElement( "left" ) );
597 m_indiP_temps["left"].set( 0 );
598 m_indiP_temps.add( pcf::IndiElement( "right" ) );
599 m_indiP_temps["right"].set( 0 );
600 m_indiP_temps.add( pcf::IndiElement( "cooling" ) );
601 m_indiP_temps["cooling"].set( 0 );
602
603 REG_INDI_NEWPROP_NOCB( m_indiP_emProt, "emProtection", pcf::IndiProperty::Text );
604 m_indiP_emProt.add( pcf::IndiElement( "status" ) );
605 m_indiP_emProt["status"].set( "UNKNOWN" );
606 m_indiP_emProt.setState( INDI_IDLE );
607
608 createStandardIndiRequestSw( m_indiP_emProtReset, "emProtectionReset", "Reset", "EM Protection" );
610
612
614 {
615 return log<software_critical, -1>( { "" } );
616 }
617
619 {
620 return log<software_critical, -1>( { "" } );
621 }
622
624 {
625 return log<software_critical, -1>( { "" } );
626 }
627
629 {
630 return log<software_critical, -1>( { "" } );
631 }
632
635 {
636 return log<software_error, -1>( { "" } );
637 }
638
639 return 0;
640}
641
643{
644
645 // and run stdCamera's appLogic
647 {
648 return log<software_error, -1>( { "" } );
649 }
650
651 // and run edtCamera's appLogic
653 {
654 return log<software_error, -1>( { "" } );
655 }
656
657 // first run frameGrabber's appLogic to see if the f.g. thread has exited.
659 {
660 return log<software_error, -1>( { "" } );
661 }
662
663 // and run dssShutter's appLogic
665 {
666 return log<software_error, -1>( { "" } );
667 }
668
669 if( state() == stateCodes::POWERON )
670 return 0;
671
673 {
675
676 std::string response;
677
678 // Might have gotten here because of a power off.
679 if( MagAOXAppT::m_powerState == 0 )
680 return 0;
681
682 int ret = 0;
683 { // mutex scope
684 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
685 ret = pdvSerialWriteRead( response, "fps" ); // m_pdv, "fps", m_readTimeout);
686 }
687 if( ret == 0 )
688 {
690 }
691 else
692 {
693 sleep( 1 );
694 return 0;
695 }
696 }
697
699 {
700 // Get a lock
701 std::unique_lock<std::mutex> lock( m_indiMutex );
702
703 if( getFPS() == 0 )
704 {
705 if( m_fpsSet == 0 )
707 else
709
710 if( m_poweredOn && m_ccdTempSetpt > -999 )
711 {
712 m_poweredOn = false;
713 if( setTempSetPt() < 0 )
714 {
715 if( powerState() != 1 || powerStateTarget() != 1 )
716 {
717 return 0;
718 }
719 return log<software_error, 0>( { "" } );
720 }
721 }
722
723 // We always have to set synchro on connecting, b/c otherwise we don't know the state.
724 m_synchroSet = false;
725 if( setSynchro() != 0 )
726 {
727 log<software_error>( { "error from setSynchro on CONNECT" } );
728 }
729 }
730 else
731 {
732 if( powerState() != 1 || powerStateTarget() != 1 )
733 return 0;
735 return log<software_error, 0>( { "" } );
736 }
737 }
738
740 {
741 // Get a lock if we can
742 std::unique_lock<std::mutex> lock( m_indiMutex, std::try_to_lock );
743
744 // but don't wait for it, just go back around.
745 if( !lock.owns_lock() )
746 return 0;
747
748 if( getTemps() < 0 )
749 {
750 if( powerState() != 1 || powerStateTarget() != 1 )
751 return 0;
754 return 0;
755 }
756
757 if( getFPS() < 0 )
758 {
759 if( powerState() != 1 || powerStateTarget() != 1 )
760 return 0;
761
763 return 0;
764 }
765
767 {
768 if( mx::sys::get_curr_time() - m_protectionResetReqTime > 10.0 )
769 {
771 updateIfChanged( m_indiP_emProt, "status", std::string( "UNCONFIRMED" ) );
772 log<text_log>( "protection reset request not confirmed", logPrio::LOG_NOTICE );
773 }
774 }
775
776 if( getEMGain() < 0 )
777 {
778 if( MagAOXAppT::m_powerState == 0 )
779 return 0;
780
782 return 0;
783 }
784
786 {
787 log<software_error>( { "" } );
789 return 0;
790 }
791
793 {
794 log<software_error>( { "" } );
796 return 0;
797 }
798
800 {
801 log<software_error>( { "" } );
803 return 0;
804 }
805
807 {
808 log<software_error>( { "" } );
809 return 0;
810 }
811 }
812
813 ///\todo Fall through check?
814
815 return 0;
816}
817
819{
821
822 std::lock_guard<std::mutex> lock( m_indiMutex );
823
824 updateIfChanged( m_indiP_emProt, "status", std::string( "UNKNOWN" ), INDI_IDLE );
825
827
835
837 {
838 log<software_error>( { "" } );
839 }
840
842 {
843 log<software_error>( { "" } );
844 }
845
847 {
848 log<software_error>( { "" } );
849 }
850
852 {
853 log<software_error>( { "" } );
854 }
855
856 // Setting m_poweredOn
857 m_poweredOn = true;
858
859 return 0;
860}
861
863{
864 std::lock_guard<std::mutex> lock( m_indiMutex );
865
867 {
868 log<software_error>( { "" } );
869 }
870
872 {
873 log<software_error>( { "" } );
874 }
875
877 {
878 log<software_error>( { "" } );
879 }
880
881 return 0;
882}
883
885{
886 ///\todo error check these base class fxns.
887
889
891
893
895
897
899
900 return 0;
901}
902
904{
905 std::string response;
906
907 { // mutex scope
908 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
909 if( pdvSerialWriteRead( response, "temp" ) != 0 )
910 {
911 if( powerState() != 1 || powerStateTarget() != 1 )
912 return -1;
913 return log<software_error, -1>( { "" } );
914 }
915 }
916
917 {
918 ocamTemps temps;
919
920 if( parseTemps( temps, response ) < 0 )
921 {
922 if( powerState() != 1 || powerStateTarget() != 1 )
923 return -1;
924
928 m_tempControlStatus = false;
929 m_tempControlStatusStr = "UNKNOWN";
930
931 recordTemps();
932 recordCamera();
933
934 std::cerr << "Temp. parse error. Response:\n" << response << std::endl;
935
936 // We don't trust the temps, but don't reconfig just for this.
937 return log<software_error, 0>( { "Temp. parse error" } );
938 }
939
940 m_temps = temps;
941
942 // stdCamera temp control:
945
946 // Detect that temperature control is off
947 if( m_temps.COOLING_POWER < 5 )
948 {
949 if( m_temps.CCD - m_temps.SET > 2.99 )
950 {
951 m_tempControlStatus = false;
952 }
953 }
954 else
955 m_tempControlStatus = true;
956
957 if( m_tempControlStatus == true )
958 {
959 if( fabs( m_temps.CCD - m_temps.SET ) < 1.0 )
960 {
961 m_tempControlStatusStr = "ON TARGET";
963 }
964 else
965 {
966 m_tempControlStatusStr = "OFF TARGET";
967 m_tempControlOnTarget = false;
968 }
969 }
970 else
971 {
972 m_tempControlStatusStr = "TEMP OFF";
973 m_tempControlOnTarget = false;
974 }
975
976 // Telemeter:
977 recordTemps();
978 recordCamera();
979
987 return 0;
988 }
989}
990
992{
993 // Camera boots up with this true in most cases.
995 m_tempControlStatus = false;
996
997 return 0;
998}
999
1001{
1002 std::string response;
1003
1004 std::string command;
1005
1006 std::string comStr = "temp ";
1008 {
1009 command = "on";
1011 m_tempControlStatus = true;
1012 }
1013 else
1014 {
1015 if( m_ccdTemp > 19 ) // 19 is 20 with a 1 C slop
1016 {
1017 command = "off";
1018 m_tempControlStatusSet = false;
1019 m_tempControlStatus = false;
1020 }
1021 else
1022 {
1023 return log<text_log, -1>( "Can not turn temp control off when not at 20 C or higher", logPrio::LOG_ERROR );
1024 }
1025 }
1026
1027 comStr += command;
1028
1029 { // mutex scope
1030 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1031 if( pdvSerialWriteRead( response, comStr ) != 0 )
1032 {
1033 if( powerState() != 1 || powerStateTarget() != 1 )
1034 return -1;
1035 return log<software_error, -1>( { "" } );
1036 }
1037 }
1038
1039 {
1040 std::cerr << "response: " << response << "\n";
1041 ///\todo check response
1042 log<text_log, 0>( { "Set temperature control to " + command } );
1043 }
1044
1046 {
1047 return setTempSetPt();
1048 }
1049
1050 recordCamera();
1051
1052 return 0;
1053}
1054
1056{
1057 std::string response;
1058
1059 std::string tempStr = std::to_string( m_ccdTempSetpt );
1060
1061 ///\todo make more configurable
1062 if( m_ccdTempSetpt >= 30 || m_ccdTempSetpt < -50 )
1063 {
1064 return log<text_log, -1>( { "attempt to set temperature outside valid range: " + tempStr },
1066 }
1067
1068 { // mutex scope
1069 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1070 if( pdvSerialWriteRead( response, "temp " + tempStr ) != 0 )
1071 {
1072 if( powerState() != 1 || powerStateTarget() != 1 )
1073 return -1;
1074 return log<software_error, -1>( { "" } );
1075 }
1076 }
1077
1078 {
1079 std::cerr << "response: " << response << "\n";
1080
1081 recordCamera();
1082
1083 ///\todo check response
1084 std::cerr << "temp " << tempStr << " response: " << response << "\n";
1085
1086 return log<text_log, 0>( { "set temperature: " + tempStr } );
1087 }
1088}
1089
1091{
1092 if( !m_synchro )
1093 {
1094 std::string response;
1095
1096 { // mutex scope
1097 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1098 if( pdvSerialWriteRead( response, "fps" ) != 0 )
1099 return log<software_error, -1>( { "" } ); // m_pdv, "fps", m_readTimeout) == 0)
1100 }
1101
1102 {
1103 float fps;
1104 if( parseFPS( fps, response ) < 0 )
1105 {
1106 if( powerState() != 1 || powerStateTarget() != 1 )
1107 return -1;
1108
1109 std::cerr << "fps parse error. Response:\n" << response << "\n";
1110
1111 return log<software_error, 0>( { "fps parse error" } );
1112 }
1113 m_fps = fps;
1114
1115 recordCamera();
1116
1117 return 0;
1118 }
1119 }
1120 else
1121 {
1122 m_fps = m_syncFreq;
1123 recordCamera();
1124
1125 return 0;
1126 }
1127}
1128
1130{
1131 std::string fpsStr = std::to_string( m_fpsSet );
1132
1133 if( !m_synchro )
1134 {
1135 std::string response;
1136
1137 { // mutex scope
1138 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1139 if( pdvSerialWriteRead( response, "fps " + fpsStr ) != 0 )
1140 {
1141 if( powerState() != 1 || powerStateTarget() != 1 )
1142 return -1;
1143 return log<software_error, -1>( { "" } );
1144 }
1145 }
1146
1147 {
1148 ///\todo check response
1149 std::cerr << "fps " << fpsStr << " response: " << response << "\n";
1150 log<text_log>( { "set fps: " + fpsStr } );
1151
1152 // We always want to reset the latency circular buffers
1153 ///\todo verify that this works!!
1155 m_reconfig = true;
1156 }
1157 }
1158 else
1159 {
1160 std::cerr << "setting: " << fpsStr << "\n";
1161
1162 pcf::IndiProperty ipFreq( pcf::IndiProperty::Number );
1163
1164 ipFreq.setDevice( m_syncDevice );
1165 ipFreq.setName( m_syncFreqProp );
1166 ipFreq.add( pcf::IndiElement( "target" ) );
1167
1168 ipFreq["target"] = fpsStr;
1169
1171 }
1172
1173 return 0;
1174}
1175
1177{
1178 std::string response;
1179
1180 { // mutex scope
1181 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1182
1183 // First set the actual FPS to 0 to get to max
1184 std::string fpsStr = std::to_string( 0 );
1185 if( pdvSerialWriteRead( response, "fps " + fpsStr ) == 0 )
1186 {
1187 ///\todo check response
1188 std::cerr << "fps " << fpsStr << " response: " << response << "\n";
1189 log<text_log>( { "set fps: " + fpsStr } );
1190 }
1191 else
1192 {
1193 if( powerState() != 1 || powerStateTarget() != 1 )
1194 return -1;
1195 return log<software_error, -1>( { "" } );
1196 }
1197
1198 // Now actually turn synchro on
1199 std::string sStr;
1200 if( m_synchroSet )
1201 sStr = "on";
1202 else
1203 sStr = "off";
1204 if( pdvSerialWriteRead( response, "synchro " + sStr ) == 0 )
1205 {
1206 ///\todo check response
1207 std::cerr << "synchro " << sStr << " resonse: " << response << "\n";
1208 log<text_log>( { "set synchro: " + sStr } );
1209
1211
1212 if( m_synchro == false )
1213 {
1214 updateSwitchIfChanged( m_indiP_synchro, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1215 }
1216 else
1217 {
1218 updateSwitchIfChanged( m_indiP_synchro, "toggle", pcf::IndiElement::On, INDI_OK );
1219 }
1220 }
1221 else
1222 {
1223 if( powerState() != 1 || powerStateTarget() != 1 )
1224 return -1;
1225 return log<software_error, -1>( { "" } );
1226 }
1227 }
1228
1229 // Finally we set the FPS of the synchro device
1230 return setFPS();
1231}
1232
1234{
1235 return 0;
1236}
1237
1239{
1240 return 0;
1241}
1242
1244{
1246}
1247
1248inline std::string ocam2KCtrl::stateString()
1249{
1250 std::string ss;
1251
1252 ss += m_modeName + "_";
1253 ss += std::to_string( m_fps ) + "_";
1254 ss += std::to_string( m_emGain ) + "_";
1255 ss += std::to_string( m_ccdTempSetpt );
1256
1257 return ss;
1258}
1259
1261{
1263 {
1264 return true;
1265 }
1266 else
1267 return false;
1268}
1269
1271{
1272 std::string response;
1273
1274 { // mutex scope
1275 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1276 if( pdvSerialWriteRead( response, "protection reset" ) != 0 )
1277 {
1278 if( powerState() != 1 || powerStateTarget() != 1 )
1279 return -1;
1280 return log<software_error, -1>( { "" } );
1281 }
1282 }
1283
1284 {
1285 std::cerr << "\n******************************************\n";
1286 std::cerr << "protection reset:\n";
1287 std::cerr << response << "\n";
1288 std::cerr << "\n******************************************\n";
1289 ///\todo check response.
1290
1291 updateIfChanged( m_indiP_emProt, "status", std::string( "RESET" ), INDI_OK );
1292
1293 log<text_log>( "overillumination protection has been reset", logPrio::LOG_NOTICE );
1294
1296
1297 m_protectionReset = true;
1298
1299 return 0;
1300 }
1301}
1302
1304{
1305 std::string response;
1306
1307 { // mutex scope
1308 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1309 if( pdvSerialWriteRead( response, "gain" ) != 0 )
1310 {
1311 if( powerState() != 1 || powerStateTarget() != 1 )
1312 return -1;
1313 return log<software_error, -1>( { "" } );
1314 }
1315 }
1316
1317 {
1318 unsigned emGain;
1319 if( parseEMGain( emGain, response ) < 0 )
1320 {
1321 if( powerState() != 1 || powerStateTarget() != 1 )
1322 return -1;
1323
1324 if( response.find( "HV" ) != std::string::npos )
1325 {
1326 m_emGain = 1;
1327 updateIfChanged( m_indiP_emProt, "status", std::string( "TRIPPED" ), INDI_ALERT );
1328 return log<software_warning, -1>( { "EM Gain tripped!" } );
1329 }
1330
1331 std::cerr << "EM Gain parse error, response:\n" << response << "\n";
1332
1333 return log<software_error, -1>( { "EM Gain parse error" } );
1334 }
1335
1336 m_emGain = emGain;
1337
1338 return 0;
1339 }
1340}
1341
1343{
1344 std::string response;
1345
1346 if( m_protectionReset == false )
1347 {
1348 log<text_log>( "Attempt to set EM gain before protection reset", logPrio::LOG_NOTICE );
1349
1350 if( m_emGainSet > 1 ) // we allow setting to 1 for safety
1351 {
1352 return 0;
1353 }
1354 }
1355
1356 unsigned emg = m_emGainSet; // a float
1357
1359 {
1360 log<text_log>( "Attempt to set EM gain to " + std::to_string( emg ) + " outside limits refused",
1362 return 0;
1363 }
1364
1365 std::string emgStr = std::to_string( emg );
1366 { // mutex scope
1367 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1368 if( pdvSerialWriteRead( response, "gain " + emgStr ) != 0 ) // m_pdv, "gain " + emgStr, m_readTimeout) == 0)
1369 {
1370 if( powerState() != 1 || powerStateTarget() != 1 )
1371 return -1;
1372 return log<software_error, -1>( { "" } );
1373 }
1374 }
1375
1376 {
1377 ///\todo check response
1378 std::cerr << "gain " << emgStr << " response: " << emgStr << "\n";
1379
1380 log<text_log>( { "set EM Gain: " + emgStr } );
1381
1382 return 0;
1383 }
1384}
1385
1387{
1388 // lock mutex
1389 std::unique_lock<std::mutex> lock( m_indiMutex );
1390 std::lock_guard<std::recursive_mutex> cameraGuard( m_cameraMutex );
1391
1392 // Send command to camera to place it in the correct mode
1393 std::string response;
1394 if( pdvSerialWriteRead( response, m_cameraModes[m_modeName].m_serialCommand ) != 0 )
1395 {
1396 if( powerState() != 1 || powerStateTarget() != 1 )
1397 return -1;
1398
1399 log<software_error>( { "Error sending command to set mode" } );
1400 sleep( 1 );
1401 return -1;
1402 }
1403
1404 m_currentROI.x = 119.5;
1405 m_currentROI.y = 119.5;
1406 m_currentROI.w = 240;
1407 m_currentROI.h = 240;
1408 m_currentROI.bin_x = m_cameraModes[m_modeName].m_binningX;
1409 m_currentROI.bin_y = m_cameraModes[m_modeName].m_binningY;
1410
1411 m_digitalBinX = m_cameraModes[m_modeName].m_digitalBinX;
1412 m_digitalBinY = m_cameraModes[m_modeName].m_digitalBinY;
1413
1414 if( m_digitalBinX > 1 )
1415 {
1416 m_digitalBin = true;
1417 std::cerr << "digital binning!\n";
1418 }
1419 else
1420 {
1421 m_digitalBin = false;
1422 }
1423
1424 recordCamera();
1425
1426 ///\todo check response of pdvSerialWriteRead
1427 log<text_log>( "camera configured with: " + m_cameraModes[m_modeName].m_serialCommand );
1428
1429 if( m_fpsSet > 0 )
1430 {
1431 setFPS();
1432 }
1433
1434 log<text_log>( "Send command to set mode: " + m_cameraModes[m_modeName].m_serialCommand );
1435 log<text_log>( "Response was: " + response );
1436
1437 if( setSynchro() < 0 )
1438 {
1439 log<software_error>( { "Error setting synchro during configureAcquisition" } );
1440 }
1441
1442 /* Initialize the OCAM2 SDK
1443 */
1444
1445 if( m_ocam2_id > 0 )
1446 {
1448 m_ocam2_id = 0;
1449 }
1450 ocam2_rc rc;
1451 ocam2_mode mode;
1452
1453 int OCAM_SZw;
1454 int OCAM_SZh;
1455 if( m_raw_height == 121 )
1456 {
1457 mode = OCAM2_NORMAL;
1458 OCAM_SZw = 240;
1459 OCAM_SZh = 240;
1460 }
1461 else if( m_raw_height == 62 )
1462 {
1463 mode = OCAM2_BINNING;
1464 OCAM_SZw = 120;
1465 OCAM_SZh = 120;
1466 }
1467 else if( m_raw_height == 41 )
1468 {
1469 mode = OCAM2_BINNING1x3;
1470 OCAM_SZw = 240;
1471 OCAM_SZh = 80;
1472 }
1473 else if( m_raw_height == 31 )
1474 {
1475 mode = OCAM2_BINNING1x4;
1476 OCAM_SZw = 240;
1477 OCAM_SZh = 60;
1478 }
1479 else
1480 {
1481 log<text_log>( "Unrecognized OCAM2 mode.", logPrio::LOG_ERROR );
1482 return -1;
1483 }
1484
1486
1487 std::cerr << "ocamDescrambleFile: " << ocamDescrambleFile << std::endl;
1488
1490
1491 rc = ocam2_init( mode, ocamDescrambleFile.c_str(), &nextOcam2Id );
1492
1493 if( rc != OCAM2_OK )
1494 {
1495 if( powerState() != 1 || powerStateTarget() != 1 )
1496 return -1;
1497 log<text_log>( "ocam2_init error. Failed to initialize OCAM SDK with descramble file: " + ocamDescrambleFile,
1499 return -1;
1500 }
1501
1503
1504 log<text_log>( "OCAM2K initialized. id: " + std::to_string( m_ocam2_id ) );
1505
1506 log<text_log>( std::string( "OCAM2K mode is:" ) + ocam2_modeStr( ocam2_getMode( m_ocam2_id ) ) );
1507
1508 if( m_digitalBin )
1509 {
1510 std::cerr << "and digital binning!\n";
1512
1515 }
1516 else
1517 {
1518 m_width = OCAM_SZw;
1520 }
1521
1523
1524 if( ensureSyncStream() < 0 )
1525 {
1526 return log<software_error, -1>( { "Error preparing sync ImageStreamIO stream" } );
1527 }
1528
1530
1531 return 0;
1532}
1533
1534inline float ocam2KCtrl::fps()
1535{
1536 return m_fps;
1537}
1538
1544
1546{
1548
1549 /* Removed all pdv timeout and overrun checking, since we can rely on frame number from the camera
1550 to detect missed and corrupted frames.
1551
1552 See ef0dd24 for last version with full checks in it.
1553 */
1554
1555 // Get the image number to see if this is valid.
1556 // This is how it is in the ocam2_sdk:
1557 unsigned currImageNumber = ( reinterpret_cast<int *>( m_image_p ) )[OCAM2_IMAGE_NB_OFFSET / 4]; /* int offset */
1559
1560 // For the first loop after a restart
1561 if( m_lastImageNumber == -1 )
1562 {
1564 }
1565
1567 {
1568 // Detect exact condition of a wraparound on the unsigned int.
1569 // Yes, this can only happen once every 13.72 days at 3622 fps
1570 // But just in case . . .
1571 if( m_lastImageNumber != std::numeric_limits<unsigned int>::max() && m_currImageNumber != 0 )
1572 {
1573 // The far more likely case is a problem...
1574
1575 // If a reasonably small number of frames skipped, then we trust the image number
1577 {
1578 // This we handle as a non-timeout -- report how many frames were skipped
1580
1581 log<text_log>( "frames skipped: " + std::to_string( framesSkipped ), logPrio::LOG_ERROR );
1582
1583 m_lastImageNumber = -1;
1585 m_reconfig = 1;
1586 return 1;
1587 }
1588 else // but if it's any bigger or < 0, it's probably garbage
1589 {
1590 if( powerState() != 1 || powerStateTarget() != 1 )
1591 return -1;
1592
1593 ///\todo need frame corrupt log type
1594 log<text_log>( "frame number possibly corrupt: " + std::to_string( m_currImageNumber ) + " - " +
1595 std::to_string( m_lastImageNumber ),
1597
1599 m_reconfig = 1;
1600
1601 // Reset the counters.
1602 m_lastImageNumber = -1;
1603 return 1;
1604 }
1605 }
1606 }
1608 return 0;
1609}
1610
1612{
1613 unsigned currImageNumber = 0;
1614
1615 if( !m_digitalBin )
1616 {
1619 reinterpret_cast<int16_t *>( dest ),
1620 reinterpret_cast<int16_t *>( m_image_p ) );
1621 // memcpy(dest, m_image_p, 120*120*2); //This is about 10 usec faster -- but we have to descramble.
1622 }
1623 else
1624 {
1626 m_ocam2_id, &currImageNumber, m_digitalBinWork.data(), reinterpret_cast<int16_t *>( m_image_p ) );
1627
1628 mx::improc::eigenMap<int16_t> destMap( reinterpret_cast<int16_t *>( dest ), m_width, m_height );
1629
1630 if( m_digitalBinX > 1 )
1631 {
1632 for( int cc = 0; cc < destMap.cols(); ++cc )
1633 {
1634 for( int rr = 0; rr < destMap.rows(); ++rr )
1635 {
1637
1638 for( unsigned b = 1; b < m_digitalBinX; ++b )
1639 {
1641 }
1642 }
1643 }
1644 }
1645 }
1646
1647 return 0;
1648}
1649
1651{
1652 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1653
1655
1656 if( rv < 0 )
1657 {
1658 return rv;
1659 }
1660
1662 return 0;
1663}
1664
1666{
1667 if( imageStream == nullptr )
1668 {
1669 return 0;
1670 }
1671
1672 if( m_syncImageStream == nullptr )
1673 {
1674 return log<software_error, -1>( { "Sync ImageStreamIO stream unavailable during publication" } );
1675 }
1676
1677 m_syncImageStream->md[0].write = 1;
1678 m_syncImageStream->array.UI8[0] = 0;
1679 m_syncImageStream->md[0].writetime = imageStream->md[0].writetime;
1680 m_syncImageStream->md[0].atime = imageStream->md[0].atime;
1681 m_syncImageStream->md[0].cnt0 = imageStream->md[0].cnt0;
1682 m_syncImageStream->md[0].cnt1 = 0;
1683 m_syncImageStream->writetimearray[0] = imageStream->md[0].writetime;
1684 m_syncImageStream->atimearray[0] = imageStream->md[0].atime;
1685 m_syncImageStream->cntarray[0] = imageStream->md[0].cnt0;
1686 m_syncImageStream->md[0].write = 0;
1687
1689
1690 return 0;
1691}
1692
1694{
1695 if( MagAOXAppT::m_powerState == 0 )
1696 return 0;
1697
1698 if( ipRecv.getName() != m_indiP_emProtReset.getName() )
1699 {
1700 log<software_error>( { "wrong INDI property received." } );
1701 return -1;
1702 }
1703
1704 if( !ipRecv.find( "request" ) )
1705 {
1706 return 0;
1707 }
1708
1709 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::Off )
1710 {
1711 return 0;
1712 }
1713
1714 std::unique_lock<std::mutex> lock( m_indiMutex );
1715
1717 {
1718 updateIfChanged( m_indiP_emProt, "status", std::string( "CONFIRM" ), INDI_BUSY );
1719
1721
1722 m_protectionResetReqTime = mx::sys::get_curr_time();
1723
1724 log<text_log>( "protection reset requested", logPrio::LOG_NOTICE );
1725
1726 return 0;
1727 }
1728
1729 // If here, this is a confirmation.
1730 return resetEMProtection();
1731}
1732
1734{
1736
1737 if( !ipRecv.find( "current" ) )
1738 {
1739 return -1;
1740 }
1741
1742 m_syncFreq = ipRecv["current"].get<double>();
1743
1744 if( m_synchro && m_syncFreq != m_fps )
1745 {
1746 recordCamera( true );
1747 m_fps = m_syncFreq;
1748
1749 // We always want to reset the latency circular buffers
1751 m_reconfig = true;
1752 }
1753
1754 return 0;
1755}
1756
1761
1763{
1764 return recordTemps( true );
1765}
1766
1768{
1769 return recordCamera( true );
1770}
1771
1773{
1774 return recordFGTimings( true );
1775}
1776
1778{
1779 static ocamTemps lastTemps;
1780
1781 if( !( lastTemps == m_temps ) || force )
1782 {
1784 m_temps.CPU,
1785 m_temps.POWER,
1786 m_temps.BIAS,
1787 m_temps.WATER,
1788 m_temps.LEFT,
1789 m_temps.RIGHT,
1792 }
1793
1794 return 0;
1795}
1796
1797} // namespace app
1798} // namespace MagAOX
1799
1800#endif
The base-class for XWCTk applications.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int powerState()
Returns the current power state.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
int powerStateTarget()
Returns the target power state.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::string m_configDir
The path to configuration files for MagAOX.
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.
int sendNewProperty(const pcf::IndiProperty &ipSend, const std::string &el, const T &newVal)
Send a newProperty command to another device (using the INDI Client interface)
MagAO-X Uniblitz DSS Shutter interface.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int appShutdown()
applogic shutdown
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
MagAO-X EDT framegrabber interface.
Definition edtCamera.hpp:55
u_char * m_image_p
The image data grabbed.
Definition edtCamera.hpp:75
int m_raw_height
The height of the frame, according to the framegrabber.
Definition edtCamera.hpp:81
int pdvSerialWriteRead(std::string &response, const std::string &command, bool logErrors=true)
Send a serial command over cameralink and retrieve the response.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int appShutdown()
Application the shutdown.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
int appShutdown()
Shuts down the framegrabber thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
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.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
MagAO-X standard camera interface.
float m_maxEMGain
The configurable maximum EM gain. To be enforced in derivedT.
float m_fpsSet
The commanded fps, as set by user.
bool m_synchroSet
Target status of m_synchro.
std::string m_tempControlStatusStr
Camera specific description of temperature control status.
float m_emGain
The camera's current EM gain (if available).
float m_emGainSet
The camera's EM gain, as set by the user.
std::string m_nextMode
The mode to be set by the next reconfiguration.
float m_ccdTempSetpt
The desired temperature, in C.
bool m_tempControlStatus
Whether or not temperature control is active.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
std::string m_modeName
The current mode name.
float m_startupTemp
The temperature to set after a power-on. Set to <= -999 to not use [default].
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
bool m_synchro
Status of synchronization, true is on, false is off.
float m_ccdTemp
The current temperature, in C.
bool m_tempControlOnTarget
Whether or not the temperature control system is on its target temperature.
cameraConfigMap m_cameraModes
Map holding the possible camera mode configurations.
int appShutdown()
Application shutdown.
bool m_tempControlStatusSet
Desired state of temperature control.
static constexpr bool c_stdCamera_fps
app::dev config to tell stdCamera not to expose FPS status (ignored since fpsCtrl==true)
pcf::IndiProperty m_indiP_temps
INDI property publishing the latest camera temperatures.
static constexpr bool c_stdCamera_usesModes
app:dev config to tell stdCamera not to expose mode controls
float m_syncFreq
Current externally supplied sync frequency in Hz.
bool m_poweredOn
Tracks that power-on defaults still need to restore the configured temperature setpoint.
int resetEMProtection()
Reset the EM Protection.
bool m_protectionReset
Flag indicating that protection has been reset at least once.
int setShutter(int sh)
Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface].
mx::improc::eigenImage< int16_t > m_digitalBinWork
Scratch image holding the full descrambled frame before digital binning.
std::string stateString()
Return the current stdCamera state string.
virtual int appLogic()
Implementation of the FSM for the OCAM 2K.
int recordTelem(const ocam_temps *)
int frameGrabberPostPublish(IMAGE *imageStream)
Publish the sync-only stream immediately after the main framegrabber publication.
static constexpr bool c_stdCamera_usesStateString
app::dev confg to tell stdCamera to expose the state string property
bool m_digitalBin
Indicates whether post-descramble digital binning is active for the current mode.
static constexpr bool c_stdCamera_exptimeCtrl
app::dev config to tell stdCamera not to expose exposure time controls
static constexpr uint32_t c_syncStreamHeight
Height of the sync-only ImageStreamIO stream.
int setNextROI()
Required by stdCamera, but this does not do anything for this camera [stdCamera interface].
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
pcf::IndiProperty m_indiP_emProtReset
INDI property handling operator requests to reset EM protection.
static constexpr uint32_t c_syncStreamDepth
Depth of the sync-only ImageStreamIO stream.
static constexpr bool c_stdCamera_fanSpeed
app::dev config to tell stdCamera not to expose fan-speed control
~ocam2KCtrl() noexcept
Destructor.
int ensureSyncStream()
Ensure the sync-only ImageStreamIO stream exists with the expected 1x1 uint8 layout.
virtual int onPowerOff()
Implementation of the on-power-off FSM logic.
std::string m_ocamDescrambleFile
ocamTemps m_temps
Structure holding the last temperature measurement.
static constexpr bool c_edtCamera_relativeConfigPath
app::dev config to tell edtCamera to use relative path to camera config file
bool stateStringValid()
Report whether the current stdCamera state string is valid for persistence and telemetry.
int powerOnDefaults()
Set defaults for a power on state.
int setSynchro()
Set the synchro state. [stdCamera interface].
virtual int appShutdown()
Do any needed shutdown tasks.
static constexpr bool c_stdCamera_synchro
app::dev config to tell stdCamera to expose synchro mode controls
int getEMGain()
Get the current EM Gain.
unsigned m_protectionResetConfirmed
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
int setExpTime()
Required by stdCamera, but this does not do anything for this camera [stdCamera interface].
float fps()
Implementation of the frameGrabber fps interface.
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
static constexpr uint32_t c_syncStreamWidth
Width of the sync-only ImageStreamIO stream.
static constexpr uint8_t c_syncStreamDataType
Data type of the sync-only stream.
int setTempControl()
Turn temperature control on or off.
std::string m_syncDevice
INDI device providing the external sync frequency when synchro mode is enabled.
pcf::IndiProperty m_indiP_emProt
INDI property publishing the EM protection state.
int reconfig()
Implementation of the framegrabber reconfig interface.
static constexpr bool c_stdCamera_emGain
app::dev config to tell stdCamera to expose EM gain controls
long m_currImageNumber
The current image number, retrieved from the raw image itself.
int setTempSetPt()
Set the CCD temperature setpoint [stdCamera interface].
static constexpr bool c_stdCamera_vShiftSpeed
app:dev config to tell stdCamera not to expose vertical shift speed control
std::string m_syncFreqProp
INDI property name reporting the external sync frequency.
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
static constexpr bool c_stdCamera_tempControl
app::dev config to tell stdCamera to expose temperature controls
int setEMGain()
Set the EM gain.
int setFPS()
Set the frame rate. [stdCamera interface].
static constexpr bool c_stdCamera_temp
app::dev config to tell stdCamera to expose temperature (ignored since tempControl==true)
unsigned m_digitalBinY
Digital y-binning factor applied after descrambling.
unsigned m_digitalBinX
Digital x-binning factor applied after descrambling.
static constexpr bool c_stdCamera_usesROI
app:dev config to tell stdCamera to expose ROI controls
int recordTemps(bool force=false)
int getFPS()
Get the current frame rate.
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
double m_protectionResetReqTime
The time at which protection reset was requested. You have 10 seconds to confirm.
std::recursive_mutex m_cameraMutex
Protects EDT PDV access and OCAM SDK lifetime across reconfigure, grab, and control paths.
ocam2KCtrl()
Default c'tor.
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
static constexpr bool c_stdCamera_fpsCtrl
app::dev config to tell stdCamera to expose FPS controls
static constexpr bool c_stdCamera_cropMode
app:dev config to tell stdCamera to expose Crop Mode controls
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber these images can not be flipped
static constexpr bool c_stdCamera_readoutSpeed
app::dev config to tell stdCamera not to expose readout speed controls
ocam2_id m_ocam2_id
OCAM SDK id.
virtual int whilePowerOff()
Implementation of the while-powered-off FSM.
long m_lastImageNumber
The last image number saved from the previous acquisition loop.
int getTemps()
Get the current device temperatures.
virtual int appStartup()
Startup functions.
static constexpr bool c_stdCamera_hasShutter
app:dev config to tell stdCamera to expose shutter controls
pcf::IndiProperty m_indiP_syncFreq
INDI subscription to the external sync-frequency source.
int destroySyncStream()
Destroy the sync-only ImageStreamIO stream owned by this app.
#define protected
go_lp b(m_lp.m_c)
Shared EDT SDK stub declarations for MagAO-X test builds.
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#define INDI_SETCALLBACK_DECL(class, prop)
Declare the callback for a set property request, and declare and define the static wrapper.
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
#define INDI_NEWCALLBACK_DECL(class, prop)
Declare the callback for a new property request, and declare and define the static wrapper.
int parseFPS(float &fps, const std::string &fstr)
Parse the FPS response.
int parseTemps(ocamTemps &temps, const std::string &tstr)
Parse the OCAM temp query and fill the ocamTemps structure.
Definition ocamUtils.hpp:71
int parseEMGain(unsigned &emGain, const std::string &fstr)
Parse the EM gain response.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_BUSY
Definition indiUtils.hpp:29
#define INDI_ALERT
Definition indiUtils.hpp:30
#define INDI_OK
Definition indiUtils.hpp:28
const pcf::IndiProperty & ipRecv
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_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
MagAOX::app::MagAOXApp< true > MagAOXAppT
ocam2_rc ocam2_init(ocam2_mode mode, const char *descrbFile, ocam2_id *id)
Create a camera instance with the provided mode.
Definition ocam2_sdk.c:431
void ocam2_descramble(ocam2_id id, unsigned int *number, short *image, const short *imageRaw)
Create a camera instance with the provided mode.
Definition ocam2_sdk.c:418
const char * ocam2_modeStr(ocam2_mode mode)
Return a description text for camera mode.
Definition ocam2_sdk.c:77
ocam2_rc ocam2_exit(ocam2_id id)
Clear a camera instance.
Definition ocam2_sdk.c:490
ocam2_mode ocam2_getMode(ocam2_id id)
Return the camera mode.
Definition ocam2_sdk.c:69
The purpose of the libocam2sdk library is to provide an easy way to achieve ocam2 specific opération....
int ocam2_id
Library camera identifier.
Definition ocam2_sdk.h:268
ocam2_rc
Enum of ocam2 library return code.
Definition ocam2_sdk.h:258
@ OCAM2_OK
Definition ocam2_sdk.h:260
@ OCAM2_BINNING
Definition ocam2_sdk.h:236
@ OCAM2_BINNING1x3
Definition ocam2_sdk.h:244
@ OCAM2_BINNING1x4
Definition ocam2_sdk.h:246
@ OCAM2_NORMAL
Definition ocam2_sdk.h:226
enum workMode ocam2_mode
typedef of ocam2 camera mode
#define OCAM2_IMAGE_NB_OFFSET
Definition ocam2_sdk.h:208
Utilities for the OCAM camera.
A device base class which saves telemetry.
Definition telemeter.hpp:75
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Structure to hold the OCAM camera temperature readings returned by the device.
Definition ocamUtils.hpp:22
float WATER
Cooling water temperature.
Definition ocamUtils.hpp:27
int setInvalid()
Set all values to the invalid value, -999.
Definition ocamUtils.hpp:45
float COOLING_POWER
the cooling power in 100 mw.
Definition ocamUtils.hpp:31
float BIAS
Bias temperature.
Definition ocamUtils.hpp:26
float SET
The CCD set temeperature.
Definition ocamUtils.hpp:30
float CCD
The detector temperature.
Definition ocamUtils.hpp:23
float POWER
Power supply temperature.
Definition ocamUtils.hpp:25
float CPU
The CPU temperature.
Definition ocamUtils.hpp:24
float LEFT
The left amplifier temperature.
Definition ocamUtils.hpp:28
float RIGHT
The right amplifier temperature.
Definition ocamUtils.hpp:29
@ OPERATING
The device is operating, other than homing.
@ 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.
Log entry recording the build-time git state.
Software CRITICAL log entry.
Software ERR log entry.
Software WARN log entry.
Log entry recording framegrabber timings.
Log entry recording stdcam stage specific status.
A simple text log, a string-type log.
Definition text_log.hpp:24