API
 
Loading...
Searching...
No Matches
cred2Ctrl.hpp
Go to the documentation of this file.
1/** \file cred2Ctrl.hpp
2 * \brief The MagAO-X C-RED 2 camera controller.
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup cred2Ctrl_files
7 */
8
9#ifndef cred2Ctrl_hpp
10#define cred2Ctrl_hpp
11
12#include <algorithm>
13#include <cmath>
14#include <dlfcn.h>
15#include <fstream>
16#include <mutex>
17#include <sstream>
18#include <string>
19
20#include "../../libMagAOX/libMagAOX.hpp" // Note this is included on command line to trigger pch
21#include "../../magaox_git_version.h"
22
23#include "cred2Utils.hpp"
24
25namespace MagAOX
26{
27namespace app
28{
29
30/** \defgroup cred2Ctrl C-RED 2 Camera
31 * \brief Control of the First Light Imaging C-RED 2 camera.
32 *
33 * <a href="../handbook/operating/software/apps/cred2Ctrl.html">Application Documentation</a>
34 *
35 * \ingroup apps
36 */
37
38/** \defgroup cred2Ctrl_files C-RED 2 Camera Files
39 * \ingroup cred2Ctrl
40 */
41
42/// MagAO-X application to control the C-RED 2 camera.
43/**
44 * \ingroup cred2Ctrl
45 */
46class cred2Ctrl : public MagAOXApp<>,
47 public dev::stdCamera<cred2Ctrl>,
48 public dev::edtCamera<cred2Ctrl>,
49 public dev::frameGrabber<cred2Ctrl>,
50 public dev::telemeter<cred2Ctrl>
51{
52 friend class dev::stdCamera<cred2Ctrl>;
53 friend class dev::edtCamera<cred2Ctrl>;
54 friend class dev::frameGrabber<cred2Ctrl>;
55 friend class dev::telemeter<cred2Ctrl>;
56
61
62 public:
63 /** \name app::dev Configurations
64 * @{
65 */
66 static constexpr bool c_stdCamera_tempControl = true; ///< Expose temperature setpoint control.
67 static constexpr bool c_stdCamera_temp = true; ///< Expose detector temperature status.
68 static constexpr bool c_stdCamera_readoutSpeed = false; ///< Do not expose readout-speed controls.
69 static constexpr bool c_stdCamera_vShiftSpeed = false; ///< Do not expose vertical-shift controls.
70 static constexpr bool c_stdCamera_emGain = false; ///< Do not expose EM-gain controls.
71 static constexpr bool c_stdCamera_exptimeCtrl = false; ///< Do not expose exposure-time controls.
72 static constexpr bool c_stdCamera_fpsCtrl = true; ///< Expose FPS controls.
73 static constexpr bool c_stdCamera_fps = true; ///< Expose FPS status.
74 static constexpr bool c_stdCamera_fanSpeed = true; ///< Expose fan-speed controls.
75 static constexpr bool c_stdCamera_analogGain = true; ///< Expose discrete analog-gain controls.
76 static constexpr bool c_stdCamera_led = true; ///< Expose status LED controls.
77 static constexpr bool c_stdCamera_synchro = false; ///< Do not expose synchro controls in the first pass.
78 static constexpr bool c_stdCamera_usesModes = false; ///< Use one synthetic runtime mode rather than INDI modes.
79 static constexpr bool c_stdCamera_usesROI = true; ///< Expose ROI controls.
80 static constexpr bool c_stdCamera_cropMode = false; ///< Do not expose crop-mode controls separately.
81 static constexpr bool c_stdCamera_hasShutter = false; ///< Do not expose shutter controls.
82 static constexpr bool c_stdCamera_usesStateString = false; ///< Do not expose a dark-management state string.
83 static constexpr bool c_edtCamera_relativeConfigPath = false; ///< Use an absolute temporary EDT config path.
84 static constexpr bool c_frameGrabber_flippable = true; ///< Expose image flip controls through the framegrabber.
85
86 ///@}
87
88 protected:
89 /** \name Configurable Parameters - Data
90 * @{
91 */
92 std::string m_configFile; ///< Absolute path to the temporary EDT configuration file.
93
94 int m_serialBaud{ 115200 }; ///< Camera Link serial baud rate used for C-RED 2 CLI access.
95 ///@}
96
97 /** \name C-RED 2 State - Data
98 * @{
99 */
100 cred2Temps m_temps; ///< Cached camera temperature values used for INDI and telemetry updates.
101
102 bool m_cameraCropEnabled{ false }; ///< Tracks whether this controller has enabled camera-side cropping.
103 int m_roiSettleCounter{ 0 }; ///< Number of main-loop cycles to skip serial status polling after ROI changes.
104
105 std::recursive_mutex m_cameraMutex; ///< Protects serial command traffic and EDT reconfiguration.
106 ///@}
107
108 /** \name INDI - Data
109 * @{
110 */
111 pcf::IndiProperty m_indiP_temps; ///< Property reporting the detailed C-RED 2 temperature channels.
112 pcf::IndiProperty m_indiP_fpsLimits; ///< Property reporting the current C-RED 2 minimum and maximum FPS.
113
114 ///@}
115
116 public:
117 /// Default c'tor.
118 cred2Ctrl();
119
120 /// D'tor, declared and defined for noexcept.
122
123 /// Setup the configuration system.
124 virtual void setupConfig();
125
126 /// Load the configuration system results.
127 virtual void loadConfig();
128
129 /// Implementation of loadConfig logic with standard helper-macro error handling.
130 int loadConfigImpl( mx::app::appConfigurator &config /**< [in] application configurator with loaded values */ );
131
132 /// Startup function.
133 virtual int appStartup();
134
135 /// Main FSM logic.
136 virtual int appLogic();
137
138 /// Actions required when the camera power turns off.
139 virtual int onPowerOff();
140
141 /// Actions required while the camera remains powered off.
143
144 /// Shutdown function.
145 virtual int appShutdown();
146
147 /// Query and update the camera temperature channels.
148 int getTemps();
149
150 /// Query and update the current camera frame rate.
151 int getFPS();
152
153 /// Query and update the current camera FPS limits.
154 int updateFPSLimits();
155
156 /// Query and update the current fan-control state.
157 int getFanSpeed();
158
159 /// Query and update the current analog-gain state.
160 int getAnalogGain();
161
162 /// Query and update the current LED state.
163 int getLEDState();
164
165 /// Query the camera for its current ROI and synchronize local state.
166 int syncROIFromCamera();
167
168 /** \name stdCamera Interface
169 * @{
170 */
171
172 /// Set defaults for a power-on state.
173 int powerOnDefaults();
174
175 /// Implement the C-RED 2 temperature-controller toggle semantics.
176 int setTempControl();
177
178 /// Send the current target detector temperature setpoint to the camera.
179 int setTempSetPt();
180
181 /// Send the requested frame rate to the camera.
182 int setFPS();
183
184 /// Send the requested fan-control mode to the camera.
185 int setFanSpeed();
186
187 /// Send the requested analog-gain mode to the camera.
188 int setAnalogGain();
189
190 /// Send the requested LED state to the camera.
191 int setLED();
192
193 /// Required by `stdCamera`, but unused for C-RED 2.
194 int setExpTime();
195
196 /// Validate and normalize the requested ROI.
197 int checkNextROI();
198
199 /// Request that the next valid ROI be applied through reconfiguration.
200 int setNextROI();
201
202 ///@}
203
204 /** \name Framegrabber Interface
205 * @{
206 */
207
208 /// Write the temporary EDT configuration file for the pending ROI.
209 int writeConfig();
210
211 /// Configure camera-side ROI settings before acquisition starts.
213
214 /// Return the currently measured frame rate.
215 float fps();
216
217 /// Start frame acquisition on the EDT board.
218 int startAcquisition();
219
220 /// Wait for and validate the next acquired image.
222
223 /// Copy the current EDT image into the output stream.
224 int loadImageIntoStream( void *dest /**< [in] destination frame buffer */ );
225
226 /// Reconfigure the EDT board for the pending ROI.
227 int reconfig();
228
229 ///@}
230
231 /** \name Telemeter Interface
232 * @{
233 */
234
235 /// Check the telemetry record timers.
236 int checkRecordTimes();
237
238 /// Record the detailed C-RED 2 temperature telemetry.
239 int recordTelem( const cred2_temps * /**< [in] type-dispatch tag */ );
240
241 /// Record standard camera telemetry.
242 int recordTelem( const telem_stdcam * /**< [in] type-dispatch tag */ );
243
244 /// Record framegrabber timing telemetry.
245 int recordTelem( const telem_fgtimings * /**< [in] type-dispatch tag */ );
246
247 /// Record the detailed C-RED 2 temperature telemetry when values change.
248 int recordTemps( bool force = false /**< [in] force a telemetry record even if the cached values match */ );
249
250 ///@}
251
252 protected:
253 /// Apply and verify the configured Camera Link serial baud rate.
254 int setSerialBaud();
255
256 /// Send a command over Camera Link serial and clean the response.
257 int sendCommand( std::string &response, ///< [out] cleaned command response
258 const std::string &command, /**< [in] CLI command to send */
259 bool logFailure = true /**< [in] log transport failures when true */
260 );
261
262 /// Send a command that should return a success acknowledgement.
263 int issueCommand( const std::string &command, /**< [in] CLI command to send */
264 bool allowNoResponse = false /**< [in] treat a missing response as acceptable */
265 );
266};
267
269{
270
271/// Normalize a C-RED 2 text response for tolerant string parsing.
272inline std::string cred2LowerResponse( const std::string &response /**< [in] raw or cleaned CLI response */ )
273{
274 std::string clean = cred2CleanResponse( response );
275 std::transform( clean.begin(),
276 clean.end(),
277 clean.begin(),
278 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
279
280 return clean;
281}
282
283/// Convert a C-RED 2 fan percentage into the nearest exposed preset name.
284inline std::string cred2FanPresetName( float fanPercent /**< [in] current or requested fan percentage */ )
285{
286 if( fanPercent <= 0.5f )
287 {
288 return "off";
289 }
290
291 if( fanPercent < 37.5f )
292 {
293 return "p25";
294 }
295
296 if( fanPercent < 62.5f )
297 {
298 return "p50";
299 }
300
301 if( fanPercent < 87.5f )
302 {
303 return "p75";
304 }
305
306 return "p100";
307}
308
309/// Convert an exposed fan preset name into the corresponding manual fan percentage.
310inline int cred2FanPresetPercent( int &fanPercent, ///< [out] mapped manual fan percentage
311 const std::string &fanPreset /**< [in] exposed fan preset name */
312)
313{
314 if( fanPreset == "off" )
315 {
316 fanPercent = 0;
317 return 0;
318 }
319
320 if( fanPreset == "p25" )
321 {
322 fanPercent = 25;
323 return 0;
324 }
325
326 if( fanPreset == "p50" )
327 {
328 fanPercent = 50;
329 return 0;
330 }
331
332 if( fanPreset == "p75" )
333 {
334 fanPercent = 75;
335 return 0;
336 }
337
338 if( fanPreset == "p100" )
339 {
340 fanPercent = 100;
341 return 0;
342 }
343
344 return -1;
345}
346
347/// Parse a C-RED 2 sensibility response into the exposed analog-gain preset name.
348inline int cred2AnalogGainName( std::string &gainName, ///< [out] exposed analog-gain preset name
349 const std::string &response /**< [in] raw or cleaned sensibility response */
350)
351{
352 std::string clean = cred2LowerResponse( response );
353
354 if( clean.find( "medium" ) != std::string::npos || clean == "med" )
355 {
356 gainName = "med";
357 return 0;
358 }
359
360 if( clean.find( "high" ) != std::string::npos )
361 {
362 gainName = "high";
363 return 0;
364 }
365
366 if( clean.find( "low" ) != std::string::npos )
367 {
368 gainName = "low";
369 return 0;
370 }
371
372 return -1;
373}
374
375/// Convert an exposed analog-gain preset name into the C-RED 2 command argument.
376inline int cred2AnalogGainCommand( std::string &commandGain, ///< [out] C-RED 2 sensibility command argument
377 const std::string &gainName /**< [in] exposed analog-gain preset name */
378)
379{
380 if( gainName == "low" )
381 {
382 commandGain = "low";
383 return 0;
384 }
385
386 if( gainName == "med" )
387 {
388 commandGain = "medium";
389 return 0;
390 }
391
392 if( gainName == "high" )
393 {
394 commandGain = "high";
395 return 0;
396 }
397
398 return -1;
399}
400
401} // namespace
402
404{
405 m_powerMgtEnabled = true;
406
407 m_startupTemp = 20;
408 m_minTemp = -40;
409 m_maxTemp = 20;
410 m_stepTemp = 1;
411
412 m_stepFPS = 0.001;
413
414 m_full_x = 319.5;
415 m_full_y = 255.5;
416 m_full_w = 640;
417 m_full_h = 512;
418 m_full_bin_x = 1;
419 m_full_bin_y = 1;
420
427
432
433 m_minROIx = 0;
434 m_maxROIx = 639;
435 m_stepROIx = 0.5;
436
437 m_minROIy = 0;
438 m_maxROIy = 511;
439 m_stepROIy = 0.5;
440
441 m_minROIWidth = 32;
442 m_maxROIWidth = 640;
443 m_stepROIWidth = 32;
444
445 m_minROIHeight = 4;
446 m_maxROIHeight = 512;
447 m_stepROIHeight = 4;
448
452
456
457 m_fanSpeedNames = { "off", "p25", "p50", "p75", "p100", "auto" };
458 m_fanSpeedNameLabels = { "Off", "25", "50", "75", "100", "Auto" };
459 m_defaultFanSpeed = "auto";
461
462 m_analogGainNames = { "low", "med", "high" };
463 m_analogGainNameLabels = { "Low", "Med", "High" };
464 m_analogGainNameSet = "med";
465
466 m_defaultLEDState = true;
468
470}
471
472inline cred2Ctrl::~cred2Ctrl() noexcept
473{
474}
475
477{
478 STDCAMERA_SETUP_CONFIG( config );
479
481
483
484 TELEMETER_SETUP_CONFIG( config );
485
486 config.add( "camera.serialBaud",
487 "",
488 "camera.serialBaud",
489 argType::Required,
490 "camera",
491 "serialBaud",
492 false,
493 "int",
494 "The Camera Link serial baud rate for C-RED 2 CLI commands. Default is 115200." );
495}
496
497inline int cred2Ctrl::loadConfigImpl( mx::app::appConfigurator &config )
498{
499 STDCAMERA_LOAD_CONFIG( config );
500
501 config( m_serialBaud, "camera.serialBaud" );
502
503 m_configFile = "/tmp/cred2_" + configName() + ".cfg";
504
506 "",
507 static_cast<unsigned>( m_nextROI.x ),
508 static_cast<unsigned>( m_nextROI.y ),
509 static_cast<unsigned>( m_nextROI.w ),
510 static_cast<unsigned>( m_nextROI.h ),
511 static_cast<unsigned>( m_nextROI.bin_x ),
512 static_cast<unsigned>( m_nextROI.bin_y ),
513 1,
514 1,
515 0 } );
516 m_startupMode = "runtime";
517
518 if( writeConfig() < 0 )
519 {
520 return log<software_critical, -1>( { __FILE__, __LINE__, "could not write initial C-RED 2 EDT config" } );
521 }
522
524
525 FRAMEGRABBER_LOAD_CONFIG( config );
526
527 TELEMETER_LOAD_CONFIG( config );
528
529 return 0;
530}
531
533{
534 if( loadConfigImpl( config ) < 0 )
535 {
536 log<software_critical>( { __FILE__, __LINE__, "error loading config" } );
537 m_shutdown = true;
538 }
539}
540
542{
543 REG_INDI_NEWPROP_NOCB( m_indiP_temps, "temps", pcf::IndiProperty::Number );
544 m_indiP_temps.add( pcf::IndiElement( "motherboard" ) );
545 m_indiP_temps["motherboard"].set( 0 );
546 m_indiP_temps.add( pcf::IndiElement( "frontend" ) );
547 m_indiP_temps["frontend"].set( 0 );
548 m_indiP_temps.add( pcf::IndiElement( "powerboard" ) );
549 m_indiP_temps["powerboard"].set( 0 );
550 m_indiP_temps.add( pcf::IndiElement( "snake" ) );
551 m_indiP_temps["snake"].set( 0 );
552 m_indiP_temps.add( pcf::IndiElement( "setpoint" ) );
553 m_indiP_temps["setpoint"].set( 0 );
554 m_indiP_temps.add( pcf::IndiElement( "peltier" ) );
555 m_indiP_temps["peltier"].set( 0 );
556 m_indiP_temps.add( pcf::IndiElement( "heatsink" ) );
557 m_indiP_temps["heatsink"].set( 0 );
558
559 createROIndiNumber( m_indiP_fpsLimits, "fps_limits" );
560 m_indiP_fpsLimits.add( pcf::IndiElement( "min" ) );
561 m_indiP_fpsLimits["min"].set( m_minFPS );
562 m_indiP_fpsLimits["min"].setFormat( "%0.6f" );
563 m_indiP_fpsLimits.add( pcf::IndiElement( "max" ) );
564 m_indiP_fpsLimits["max"].set( m_maxFPS );
565 m_indiP_fpsLimits["max"].setFormat( "%0.6f" );
566
568 {
569 return log<software_critical, -1>( { __FILE__, __LINE__ } );
570 }
571
573
575 {
576 return log<software_critical, -1>( { __FILE__, __LINE__ } );
577 }
578
579 if( setSerialBaud() < 0 )
580 {
581 return log<software_critical, -1>( { __FILE__, __LINE__ } );
582 }
583
585
587
588 return 0;
589}
590
592{
594
596 {
597 return log<software_error, -1>( { __FILE__, __LINE__ } );
598 }
599
601
602 if( state() == stateCodes::POWERON )
603 {
604 return 0;
605 }
606
608 {
609 if( powerState() == 0 )
610 {
611 return 0;
612 }
613
614 std::string response;
615 if( sendCommand( response, "fps raw" ) == 0 )
616 {
617 float fpsValue = 0;
618 if( cred2ParseFloat( fpsValue, response ) == 0 )
619 {
621 }
622 else
623 {
625 sleep( 1 );
626 return 0;
627 }
628 }
629 else
630 {
632 sleep( 1 );
633 return 0;
634 }
635 }
636
638 {
639 std::unique_lock<std::mutex> lock( m_indiMutex );
640
641 if( syncROIFromCamera() < 0 )
642 {
643 if( powerState() != 1 || powerStateTarget() != 1 )
644 {
645 return 0;
646 }
647
649 return 0;
650 }
651
652 if( updateFPSLimits() < 0 || getTemps() < 0 || getFPS() < 0 || getFanSpeed() < 0 || getAnalogGain() < 0 ||
653 getLEDState() < 0 )
654 {
655 if( powerState() != 1 || powerStateTarget() != 1 )
656 {
657 return 0;
658 }
659
661 return 0;
662 }
663
665
668 {
669 if( setFanSpeed() < 0 )
670 {
671 if( powerState() != 1 || powerStateTarget() != 1 )
672 {
673 return 0;
674 }
675
677 }
678 }
679
682 {
683 if( setLED() < 0 )
684 {
685 if( powerState() != 1 || powerStateTarget() != 1 )
686 {
687 return 0;
688 }
689
691 }
692 }
693
694 if( m_ccdTempSetpt > -999 )
695 {
696 if( setTempSetPt() < 0 )
697 {
698 if( powerState() != 1 || powerStateTarget() != 1 )
699 {
700 return 0;
701 }
702
704 }
705 }
706 }
707
709 {
710 std::unique_lock<std::mutex> lock( m_indiMutex, std::try_to_lock );
711 if( !lock.owns_lock() )
712 {
713 return 0;
714 }
715
716 if( m_roiSettleCounter > 0 )
717 {
719 }
720 else
721 {
722 if( updateFPSLimits() < 0 )
723 {
724 if( powerState() != 1 || powerStateTarget() != 1 )
725 {
726 return 0;
727 }
728
730 return 0;
731 }
732
733 if( getTemps() < 0 )
734 {
735 if( powerState() != 1 || powerStateTarget() != 1 )
736 {
737 return 0;
738 }
739
741 return 0;
742 }
743
744 if( getFPS() < 0 )
745 {
746 if( powerState() != 1 || powerStateTarget() != 1 )
747 {
748 return 0;
749 }
750
752 return 0;
753 }
754
755 if( getFanSpeed() < 0 )
756 {
757 if( powerState() != 1 || powerStateTarget() != 1 )
758 {
759 return 0;
760 }
761
763 return 0;
764 }
765
766 if( getAnalogGain() < 0 )
767 {
768 if( powerState() != 1 || powerStateTarget() != 1 )
769 {
770 return 0;
771 }
772
774 return 0;
775 }
776
777 if( getLEDState() < 0 )
778 {
779 if( powerState() != 1 || powerStateTarget() != 1 )
780 {
781 return 0;
782 }
783
785 return 0;
786 }
787 }
788
790 {
793 return 0;
794 }
795
797 {
800 return 0;
801 }
802
804 {
807 return 0;
808 }
809
811 {
813 return 0;
814 }
815 }
816
817 return 0;
818}
819
821{
823
824 std::lock_guard<std::mutex> lock( m_indiMutex );
825
827 m_ccdTemp = -999;
828 m_tempControlStatus = false;
829 m_tempControlOnTarget = false;
830 m_tempControlStatusStr = "UNKNOWN";
831
839
841 {
843 }
844
846 {
848 }
849
851 {
853 }
854
855 return 0;
856}
857
859{
860 std::lock_guard<std::mutex> lock( m_indiMutex );
861
863 {
865 }
866
868 {
870 }
871
872 return 0;
873}
874
887
888inline int cred2Ctrl::sendCommand( std::string &response, const std::string &command, bool logFailure )
889{
890 std::string rawResponse;
891
892 response.clear();
893
894 { // mutex scope
895 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
897 {
898 if( powerState() != 1 || powerStateTarget() != 1 )
899 {
900 return -1;
901 }
902
903 if( !logFailure )
904 {
905 return -1;
906 }
907
908 return log<software_error, -1>( { __FILE__, __LINE__, "error sending C-RED 2 command: " + command } );
909 }
910 }
911
912 response = cred2CleanResponse( rawResponse );
913
914 return 0;
915}
916
917inline int cred2Ctrl::issueCommand( const std::string &command, bool allowNoResponse )
918{
919 std::string response;
920 if( sendCommand( response, command, !allowNoResponse ) < 0 )
921 {
922 if( allowNoResponse )
923 {
924 return 0;
925 }
926
927 return -1;
928 }
929
930 if( !cred2ResponseOK( response ) )
931 {
932 return log<text_log, -1>( "C-RED 2 rejected command '" + command + "' with response: " + response,
934 }
935
936 return 0;
937}
938
940{
941 std::string response;
942 bool cropEnabled = false;
943 int startColumn = 0;
944 int endColumn = 0;
945 int startRow = 0;
946 int endRow = 0;
947
948 if( sendCommand( response, "cropping raw", false ) < 0 ||
949 cred2ParseCropState( cropEnabled, startColumn, endColumn, startRow, endRow, response ) < 0 )
950 {
951 return log<software_error, -1>( { __FILE__, __LINE__, "failed to query current cropping mode: " + response } );
952 }
953
954 if( !cropEnabled )
955 {
956 m_cameraCropEnabled = false;
963 }
964 else
965 {
967
968 if( startColumn == 0 && endColumn == 0 && startRow == 0 && endRow == 0 )
969 {
970 if( sendCommand( response, "cropping columns raw", false ) < 0 ||
971 cred2ParseRange( cameraROI.startColumn, cameraROI.endColumn, response ) < 0 )
972 {
973 return log<software_error, -1>(
974 { __FILE__, __LINE__, "failed to query current cropping columns: " + response } );
975 }
976
977 if( sendCommand( response, "cropping rows raw", false ) < 0 ||
978 cred2ParseRange( cameraROI.startRow, cameraROI.endRow, response ) < 0 )
979 {
980 return log<software_error, -1>(
981 { __FILE__, __LINE__, "failed to query current cropping rows: " + response } );
982 }
983 }
984 else
985 {
986 cameraROI.startColumn = startColumn;
987 cameraROI.endColumn = endColumn;
988 cameraROI.startRow = startRow;
989 cameraROI.endRow = endRow;
990 }
991
992 cameraROI.fullFrame = false;
993
996 {
997 return log<software_error, -1>( { __FILE__, __LINE__, "camera reported an invalid ROI" } );
998 }
999
1000 m_currentROI.bin_x = 1;
1001 m_currentROI.bin_y = 1;
1002 m_cameraCropEnabled = true;
1003 }
1004
1009
1016
1023
1025 {
1026 if( writeConfig() < 0 )
1027 {
1028 return log<software_error, -1>( { __FILE__, __LINE__ } );
1029 }
1030
1032
1034 {
1035 return log<software_error, -1>( { __FILE__, __LINE__ } );
1036 }
1037
1038 if( setSerialBaud() < 0 )
1039 {
1040 return log<software_error, -1>( { __FILE__, __LINE__ } );
1041 }
1042 }
1043
1044 return 0;
1045}
1046
1048{
1049 typedef int ( *setBaudFnT )( PdvDev *, int );
1050 typedef int ( *getBaudFnT )( PdvDev * );
1051
1052 if( m_pdv == nullptr )
1053 {
1054 return log<software_error, -1>( { __FILE__, __LINE__, "cannot set serial baud with null PDV handle" } );
1055 }
1056
1057 static setBaudFnT setBaudFn = reinterpret_cast<setBaudFnT>( dlsym( RTLD_DEFAULT, "pdv_serial_set_baud" ) );
1058 static getBaudFnT getBaudFn = reinterpret_cast<getBaudFnT>( dlsym( RTLD_DEFAULT, "pdv_serial_get_baud" ) );
1059
1060 if( setBaudFn == nullptr || getBaudFn == nullptr )
1061 {
1062 return 0;
1063 }
1064
1065 if( setBaudFn( m_pdv, m_serialBaud ) < 0 )
1066 {
1067 return log<software_error, -1>(
1068 { __FILE__, __LINE__, "failed to set C-RED 2 serial baud to " + std::to_string( m_serialBaud ) } );
1069 }
1070
1071 int actualBaud = getBaudFn( m_pdv );
1072 if( actualBaud != m_serialBaud )
1073 {
1074 return log<software_error, -1>( { __FILE__,
1075 __LINE__,
1076 "EDT serial baud verification failed: expected " +
1077 std::to_string( m_serialBaud ) + ", got " +
1078 std::to_string( actualBaud ) } );
1079 }
1080
1081 return 0;
1082}
1083
1085{
1086 cred2Temps temps;
1087 std::string response;
1088 std::vector<float> bundledTemps;
1089 const double diffLimit = 1.0;
1090 const std::string bundledCommand( "temperatures raw" );
1091 const std::string setpointCommand( "temperatures snake setpoint raw" );
1092 const auto keepLastTemps = [this]( const std::string &detail )
1093 {
1094 return log<text_log, 0>( "transient C-RED 2 temperature refresh failure; keeping previous cached values: " +
1095 detail,
1097 };
1098
1099 if( sendCommand( response, bundledCommand, false ) < 0 )
1100 {
1101 return keepLastTemps( bundledCommand );
1102 }
1103
1104 if( cred2ParseFloatVector( bundledTemps, response, 6 ) < 0 )
1105 {
1106 return keepLastTemps( bundledCommand + " -> " + response );
1107 }
1108
1109 temps.motherboard = bundledTemps[0];
1110 temps.frontend = bundledTemps[1];
1111 temps.powerboard = bundledTemps[2];
1112 temps.snake = bundledTemps[3];
1113 temps.peltier = bundledTemps[4];
1114 temps.heatsink = bundledTemps[5];
1115
1116 if( sendCommand( response, setpointCommand, false ) < 0 )
1117 {
1119 }
1120
1121 if( cred2ParseFloat( temps.setpoint, response ) < 0 )
1122 {
1123 return keepLastTemps( setpointCommand + " -> " + response );
1124 }
1125
1126 m_temps = temps;
1127 m_ccdTemp = temps.snake;
1128 m_ccdTempSetpt = temps.setpoint;
1129
1130 if( m_ccdTempSetpt < 19.5 )
1131 {
1132 m_tempControlStatus = true;
1133 if( std::fabs( m_ccdTemp - m_ccdTempSetpt ) < diffLimit )
1134 {
1135 m_tempControlStatusStr = "ON TARGET";
1136 m_tempControlOnTarget = true;
1137 }
1138 else
1139 {
1140 m_tempControlStatusStr = "OFF TARGET";
1141 m_tempControlOnTarget = false;
1142 }
1143 }
1144 else
1145 {
1146 m_tempControlStatus = false;
1147 m_tempControlOnTarget = false;
1148 if( std::fabs( m_ccdTemp - m_ccdTempSetpt ) < diffLimit )
1149 {
1150 m_tempControlStatusStr = "TEMP OFF";
1151 }
1152 else
1153 {
1154 m_tempControlStatusStr = "WARMING";
1155 }
1156 }
1157
1165
1166 recordTemps();
1167 recordCamera();
1168
1169 return 0;
1170}
1171
1173{
1174 std::string response;
1175 float fpsValue = 0;
1176
1177 if( sendCommand( response, "fps raw" ) < 0 )
1178 {
1179 return -1;
1180 }
1181
1182 if( cred2ParseFloat( fpsValue, response ) < 0 )
1183 {
1184 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse fps response: " + response } );
1185 }
1186
1187 m_fps = fpsValue;
1188 recordCamera();
1189
1190 return 0;
1191}
1192
1194{
1195 std::string response;
1196 std::string fanMode;
1197 float fanPercent = 0;
1198
1199 if( sendCommand( response, "fan mode raw" ) < 0 )
1200 {
1201 return -1;
1202 }
1203
1204 fanMode = cred2LowerResponse( response );
1205 if( fanMode.find( "auto" ) == std::string::npos && fanMode.find( "manual" ) == std::string::npos )
1206 {
1207 if( sendCommand( response, "fan mode" ) < 0 )
1208 {
1209 return -1;
1210 }
1211
1212 fanMode = cred2LowerResponse( response );
1213 }
1214
1215 if( fanMode.find( "auto" ) != std::string::npos )
1216 {
1217 m_fanSpeedName = "auto";
1219 m_fanSpeedValid = true;
1220 return 0;
1221 }
1222
1223 if( fanMode.find( "manual" ) == std::string::npos )
1224 {
1225 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse fan mode response: " + response } );
1226 }
1227
1228 if( sendCommand( response, "fan speed raw" ) < 0 )
1229 {
1230 return -1;
1231 }
1232
1233 if( cred2ParseFloat( fanPercent, response ) < 0 )
1234 {
1235 if( sendCommand( response, "fan speed" ) < 0 || cred2ParseFloat( fanPercent, response ) < 0 )
1236 {
1237 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse fan speed response: " + response } );
1238 }
1239 }
1240
1243 m_fanSpeedValid = true;
1244 recordCamera();
1245
1246 return 0;
1247}
1248
1250{
1251 std::string response;
1252 std::string analogGain;
1253
1254 if( sendCommand( response, "sensibility" ) < 0 )
1255 {
1256 return -1;
1257 }
1258
1259 if( cred2AnalogGainName( analogGain, response ) < 0 )
1260 {
1261 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse sensibility response: " + response } );
1262 }
1263
1266 m_analogGainValid = true;
1267 recordCamera();
1268
1269 return 0;
1270}
1271
1273{
1274 std::string response;
1275 bool ledState = false;
1276
1277 if( sendCommand( response, "led raw" ) < 0 )
1278 {
1279 if( sendCommand( response, "led" ) < 0 )
1280 {
1281 return -1;
1282 }
1283 }
1284
1285 if( cred2ParseBool( ledState, response ) < 0 )
1286 {
1287 std::string clean = cred2LowerResponse( response );
1288
1289 if( clean.find( "off" ) != std::string::npos )
1290 {
1291 ledState = false;
1292 }
1293 else if( clean.find( "on" ) != std::string::npos )
1294 {
1295 ledState = true;
1296 }
1297 else
1298 {
1299 if( sendCommand( response, "led" ) < 0 )
1300 {
1301 return -1;
1302 }
1303
1304 clean = cred2LowerResponse( response );
1305 if( clean.find( "off" ) != std::string::npos )
1306 {
1307 ledState = false;
1308 }
1309 else if( clean.find( "on" ) != std::string::npos )
1310 {
1311 ledState = true;
1312 }
1313 else
1314 {
1315 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse led response: " + response } );
1316 }
1317 }
1318 }
1319
1322 m_ledStateValid = true;
1323 recordCamera();
1324
1325 return 0;
1326}
1327
1329{
1330 std::string response;
1331 float minFPS = 0;
1332 float maxFPS = 0;
1333
1334 if( sendCommand( response, "minfps raw" ) < 0 || cred2ParseFloat( minFPS, response ) < 0 )
1335 {
1336 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse minfps response: " + response } );
1337 }
1338
1339 if( sendCommand( response, "maxfps raw" ) < 0 || cred2ParseFloat( maxFPS, response ) < 0 )
1340 {
1341 return log<software_error, -1>( { __FILE__, __LINE__, "failed to parse maxfps response: " + response } );
1342 }
1343
1344 m_minFPS = minFPS;
1345 m_maxFPS = maxFPS;
1346 m_fpsSet = std::clamp( m_fpsSet, m_minFPS, m_maxFPS );
1347
1350
1351 recordCamera();
1352
1353 return 0;
1354}
1355
1357{
1358 m_tempControlStatus = false;
1359 m_tempControlStatusSet = false;
1360 m_tempControlStatusStr = "TEMP OFF";
1361 m_tempControlOnTarget = false;
1362 m_cameraCropEnabled = false;
1369
1370 m_fanSpeedValid = false;
1371 m_analogGainValid = false;
1372 m_ledStateValid = false;
1374 m_analogGainNameSet = "med";
1376
1378
1379 return 0;
1380}
1381
1383{
1385 {
1386 if( m_ccdTempSetpt >= 19.5 )
1387 {
1388 return log<text_log, 0>(
1389 "temperature control is setpoint-driven for C-RED 2; choose a target below 20 C to cool",
1391 }
1392
1393 return setTempSetPt();
1394 }
1395
1396 m_ccdTempSetpt = 20;
1397 return setTempSetPt();
1398}
1399
1401{
1403 {
1404 return log<text_log, -1>( "attempt to set temperature outside valid range: " + std::to_string( m_ccdTempSetpt ),
1406 }
1407
1408 std::ostringstream command;
1409 command << "set temperatures snake " << m_ccdTempSetpt;
1410
1411 if( issueCommand( command.str() ) < 0 )
1412 {
1413 return -1;
1414 }
1415
1418 m_tempControlOnTarget = false;
1419 m_tempControlStatusStr = m_tempControlStatusSet ? "OFF TARGET" : "WARMING";
1420
1421 recordCamera();
1422
1423 return 0;
1424}
1425
1427{
1429 {
1430 return log<text_log, -1>( "attempt to set fps outside valid range: " + std::to_string( m_fpsSet ),
1432 }
1433
1434 std::ostringstream command;
1435 command << "set fps " << m_fpsSet;
1436
1437 if( issueCommand( command.str() ) < 0 )
1438 {
1439 return -1;
1440 }
1441
1442 log<text_log>( "set fps: " + std::to_string( m_fpsSet ) );
1443
1444 return getFPS();
1445}
1446
1448{
1449 if( m_fanSpeedNameSet == "auto" )
1450 {
1451 if( issueCommand( "set fan mode automatic" ) < 0 )
1452 {
1453 return -1;
1454 }
1455 }
1456 else
1457 {
1458 int fanPercent = 0;
1460 {
1461 return log<software_error, -1>( { __FILE__, __LINE__, "unknown fan speed preset: " + m_fanSpeedNameSet } );
1462 }
1463
1464 if( issueCommand( "set fan mode manual" ) < 0 )
1465 {
1466 return -1;
1467 }
1468
1469 if( issueCommand( "set fan speed " + std::to_string( fanPercent ) ) < 0 )
1470 {
1471 return -1;
1472 }
1473 }
1474
1475 return getFanSpeed();
1476}
1477
1479{
1480 std::string commandGain;
1481
1483 {
1484 return log<software_error, -1>( { __FILE__, __LINE__, "unknown analog gain preset: " + m_analogGainNameSet } );
1485 }
1486
1487 if( issueCommand( "set sensibility " + commandGain ) < 0 )
1488 {
1489 return -1;
1490 }
1491
1492 return getAnalogGain();
1493}
1494
1496{
1497 if( m_ledStateSet )
1498 {
1499 if( issueCommand( "set led on" ) < 0 )
1500 {
1501 return -1;
1502 }
1503 }
1504 else
1505 {
1506 if( issueCommand( "set led off" ) < 0 )
1507 {
1508 return -1;
1509 }
1510 }
1511
1512 return getLEDState();
1513}
1514
1516{
1517 return 0;
1518}
1519
1521{
1522 auto roundToStep = []( int value, int step )
1523 { return static_cast<int>( std::lround( static_cast<double>( value ) / static_cast<double>( step ) ) ) * step; };
1524
1525 m_nextROI.bin_x = 1;
1526 m_nextROI.bin_y = 1;
1527
1528 int width = roundToStep( m_nextROI.w, 32 );
1529 width = std::clamp( width, 32, m_full_w );
1530
1531 int height = roundToStep( m_nextROI.h, 4 );
1532 height = std::clamp( height, 4, m_full_h );
1533
1534 int startColumn = static_cast<int>( std::lround( m_nextROI.x - 0.5f * ( static_cast<float>( width ) - 1.0f ) ) );
1535 int startRow = static_cast<int>( std::lround( m_nextROI.y - 0.5f * ( static_cast<float>( height ) - 1.0f ) ) );
1536
1537 startColumn = roundToStep( startColumn, 32 );
1538 startRow = roundToStep( startRow, 4 );
1539
1540 startColumn = std::clamp( startColumn, 0, m_full_w - width );
1541 startRow = std::clamp( startRow, 0, m_full_h - height );
1542
1543 m_nextROI.w = width;
1544 m_nextROI.h = height;
1545 m_nextROI.x = startColumn + 0.5f * ( static_cast<float>( width ) - 1.0f );
1546 m_nextROI.y = startRow + 0.5f * ( static_cast<float>( height ) - 1.0f );
1547
1554
1555 return 0;
1556}
1557
1559{
1560 if( checkNextROI() < 0 )
1561 {
1562 return -1;
1563 }
1564
1565 recordCamera( true );
1567
1569 m_reconfig = true;
1570
1571 updateSwitchIfChanged( m_indiP_roi_set, "request", pcf::IndiElement::Off, INDI_IDLE );
1572 updateSwitchIfChanged( m_indiP_roi_full, "request", pcf::IndiElement::Off, INDI_IDLE );
1573 updateSwitchIfChanged( m_indiP_roi_last, "request", pcf::IndiElement::Off, INDI_IDLE );
1574 updateSwitchIfChanged( m_indiP_roi_default, "request", pcf::IndiElement::Off, INDI_IDLE );
1575
1576 return 0;
1577}
1578
1580{
1581 std::ofstream fout( m_configFile );
1582 if( fout.fail() )
1583 {
1584 return log<software_error, -1>( { __FILE__, __LINE__, "error opening C-RED 2 config file for writing" } );
1585 }
1586
1587 const int width = m_nextROI.w / m_nextROI.bin_x;
1588 const int height = m_nextROI.h / m_nextROI.bin_y;
1589
1590 fout << "camera_class: \"FirstLightImaging\"\n";
1591 fout << "camera_model: \"C-RED 2\"\n";
1592 fout << "camera_info: \"" << width << "x" << height << " (4-tap, freerun)\"\n";
1593 fout << "width: " << width << "\n";
1594 fout << "height: " << height << "\n";
1595 fout << "depth: 16\n";
1596 fout << "extdepth: 16\n";
1597 fout << "rbtfile: aiagcl.bit\n";
1598 fout << "CL_DATA_PATH_NORM: 3f # four tap\n";
1599 fout << "CL_CFG_NORM: 02\n";
1600 fout << "CL_CFG2_NORM: 40\n";
1601 fout << "method_framesync: EMULATE_TIMEOUT\n";
1602 fout << "htaps: 4\n";
1603 fout << "serial_baud: " << m_serialBaud << "\n";
1604 fout << "serial_term: <0A>\n";
1605 fout << "serial_waitc: 0D\n";
1606
1607 fout.close();
1608
1609 return 0;
1610}
1611
1613{
1614 std::unique_lock<std::mutex> lock( m_indiMutex );
1615 std::lock_guard<std::recursive_mutex> cameraGuard( m_cameraMutex );
1616
1617 cred2Roi roi;
1619 {
1621 return log<software_error, -1>( { __FILE__, __LINE__, "invalid ROI specified for C-RED 2 configure" } );
1622 }
1623
1624 if( roi.fullFrame )
1625 {
1626 if( m_cameraCropEnabled && issueCommand( "set cropping off", true ) < 0 )
1627 {
1629 return -1;
1630 }
1631
1632 m_cameraCropEnabled = false;
1633 }
1634 else
1635 {
1636 if( issueCommand( "set cropping columns " + cred2ColumnsSpec( roi ), true ) < 0 ||
1637 issueCommand( "set cropping rows " + cred2RowsSpec( roi ), true ) < 0 ||
1638 issueCommand( "set cropping on", true ) < 0 )
1639 {
1641 return -1;
1642 }
1643
1644 m_cameraCropEnabled = true;
1645 }
1646
1648
1655
1657
1664
1668
1669 // Use the current FPS target while the camera settles so the framegrabber
1670 // does not keep reconfiguring latency buffers on a stale pre-ROI value.
1671 if( m_fpsSet > 0 )
1672 {
1673 m_fps = m_fpsSet;
1674 }
1675
1676 // Give the camera a few app-logic cycles to settle after crop changes
1677 // before resuming serial status polls such as fps, temperatures, and
1678 // refreshed FPS limits.
1680
1681 recordCamera( true );
1683
1684 return 0;
1685}
1686
1687inline float cred2Ctrl::fps()
1688{
1689 return m_fps;
1690}
1691
1698
1703
1704inline int cred2Ctrl::loadImageIntoStream( void *dest )
1705{
1707 {
1708 return -1;
1709 }
1710
1711 return 0;
1712}
1713
1715{
1716 recordCamera( true );
1718
1719 if( writeConfig() < 0 )
1720 {
1721 return -1;
1722 }
1723
1724 std::lock_guard<std::recursive_mutex> guard( m_cameraMutex );
1726 if( rv < 0 )
1727 {
1728 return rv;
1729 }
1730
1731 if( setSerialBaud() < 0 )
1732 {
1733 return -1;
1734 }
1735
1738
1739 return 0;
1740}
1741
1746
1748{
1749 return recordTemps( true );
1750}
1751
1753{
1754 return recordCamera( true );
1755}
1756
1758{
1759 return recordFGTimings( true );
1760}
1761
1762inline int cred2Ctrl::recordTemps( bool force )
1763{
1764 static cred2Temps lastTemps;
1765
1766 if( !( lastTemps == m_temps ) || force )
1767 {
1771 m_temps.snake,
1774 m_temps.heatsink } );
1776 }
1777
1778 return 0;
1779}
1780
1781} // namespace app
1782} // namespace MagAOX
1783
1784#endif // cred2Ctrl_hpp
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.
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.
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.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
std::string configName()
Get the config name.
MagAO-X application to control the C-RED 2 camera.
Definition cred2Ctrl.hpp:51
int checkNextROI()
Validate and normalize the requested ROI.
std::recursive_mutex m_cameraMutex
Protects serial command traffic and EDT reconfiguration.
int getFanSpeed()
Query and update the current fan-control state.
float fps()
Return the currently measured frame rate.
virtual int appStartup()
Startup function.
int setTempControl()
Implement the C-RED 2 temperature-controller toggle semantics.
std::string m_configFile
Absolute path to the temporary EDT configuration file.
Definition cred2Ctrl.hpp:92
int setTempSetPt()
Send the current target detector temperature setpoint to the camera.
int checkRecordTimes()
Check the telemetry record timers.
virtual int onPowerOff()
Actions required when the camera power turns off.
dev::stdCamera< cred2Ctrl > stdCameraT
Definition cred2Ctrl.hpp:58
int loadImageIntoStream(void *dest)
Copy the current EDT image into the output stream.
dev::frameGrabber< cred2Ctrl > frameGrabberT
Definition cred2Ctrl.hpp:59
int reconfig()
Reconfigure the EDT board for the pending ROI.
int syncROIFromCamera()
Query the camera for its current ROI and synchronize local state.
int configureAcquisition()
Configure camera-side ROI settings before acquisition starts.
static constexpr bool c_frameGrabber_flippable
Expose image flip controls through the framegrabber.
Definition cred2Ctrl.hpp:84
int getAnalogGain()
Query and update the current analog-gain state.
static constexpr bool c_stdCamera_fps
Expose FPS status.
Definition cred2Ctrl.hpp:73
virtual void loadConfig()
Load the configuration system results.
int recordTemps(bool force=false)
Record the detailed C-RED 2 temperature telemetry when values change.
static constexpr bool c_edtCamera_relativeConfigPath
Use an absolute temporary EDT config path.
Definition cred2Ctrl.hpp:83
static constexpr bool c_stdCamera_tempControl
Expose temperature setpoint control.
Definition cred2Ctrl.hpp:66
int setLED()
Send the requested LED state to the camera.
bool m_cameraCropEnabled
Tracks whether this controller has enabled camera-side cropping.
pcf::IndiProperty m_indiP_temps
Property reporting the detailed C-RED 2 temperature channels.
static constexpr bool c_stdCamera_cropMode
Do not expose crop-mode controls separately.
Definition cred2Ctrl.hpp:80
int powerOnDefaults()
Set defaults for a power-on state.
virtual void setupConfig()
Setup the configuration system.
static constexpr bool c_stdCamera_analogGain
Expose discrete analog-gain controls.
Definition cred2Ctrl.hpp:75
int updateFPSLimits()
Query and update the current camera FPS limits.
int getLEDState()
Query and update the current LED state.
int loadConfigImpl(mx::app::appConfigurator &config)
Implementation of loadConfig logic with standard helper-macro error handling.
static constexpr bool c_stdCamera_usesROI
Expose ROI controls.
Definition cred2Ctrl.hpp:79
static constexpr bool c_stdCamera_readoutSpeed
Do not expose readout-speed controls.
Definition cred2Ctrl.hpp:68
int setAnalogGain()
Send the requested analog-gain mode to the camera.
virtual int appShutdown()
Shutdown function.
static constexpr bool c_stdCamera_usesStateString
Do not expose a dark-management state string.
Definition cred2Ctrl.hpp:82
pcf::IndiProperty m_indiP_fpsLimits
Property reporting the current C-RED 2 minimum and maximum FPS.
static constexpr bool c_stdCamera_emGain
Do not expose EM-gain controls.
Definition cred2Ctrl.hpp:70
int setFPS()
Send the requested frame rate to the camera.
int setExpTime()
Required by stdCamera, but unused for C-RED 2.
int acquireAndCheckValid()
Wait for and validate the next acquired image.
static constexpr bool c_stdCamera_synchro
Do not expose synchro controls in the first pass.
Definition cred2Ctrl.hpp:77
static constexpr bool c_stdCamera_temp
Expose detector temperature status.
Definition cred2Ctrl.hpp:67
int setNextROI()
Request that the next valid ROI be applied through reconfiguration.
virtual int appLogic()
Main FSM logic.
int startAcquisition()
Start frame acquisition on the EDT board.
static constexpr bool c_stdCamera_fpsCtrl
Expose FPS controls.
Definition cred2Ctrl.hpp:72
int getTemps()
Query and update the camera temperature channels.
static constexpr bool c_stdCamera_fanSpeed
Expose fan-speed controls.
Definition cred2Ctrl.hpp:74
int m_roiSettleCounter
Number of main-loop cycles to skip serial status polling after ROI changes.
int writeConfig()
Write the temporary EDT configuration file for the pending ROI.
int getFPS()
Query and update the current camera frame rate.
cred2Ctrl()
Default c'tor.
int setSerialBaud()
Apply and verify the configured Camera Link serial baud rate.
int recordTelem(const cred2_temps *)
Record the detailed C-RED 2 temperature telemetry.
dev::telemeter< cred2Ctrl > telemeterT
Definition cred2Ctrl.hpp:60
~cred2Ctrl() noexcept
D'tor, declared and defined for noexcept.
int issueCommand(const std::string &command, bool allowNoResponse=false)
Send a command that should return a success acknowledgement.
int sendCommand(std::string &response, const std::string &command, bool logFailure=true)
Send a command over Camera Link serial and clean the response.
static constexpr bool c_stdCamera_vShiftSpeed
Do not expose vertical-shift controls.
Definition cred2Ctrl.hpp:69
int setFanSpeed()
Send the requested fan-control mode to the camera.
static constexpr bool c_stdCamera_led
Expose status LED controls.
Definition cred2Ctrl.hpp:76
cred2Temps m_temps
Cached camera temperature values used for INDI and telemetry updates.
virtual int whilePowerOff()
Actions required while the camera remains powered off.
static constexpr bool c_stdCamera_exptimeCtrl
Do not expose exposure-time controls.
Definition cred2Ctrl.hpp:71
static constexpr bool c_stdCamera_usesModes
Use one synthetic runtime mode rather than INDI modes.
Definition cred2Ctrl.hpp:78
int m_serialBaud
Camera Link serial baud rate used for C-RED 2 CLI access.
Definition cred2Ctrl.hpp:94
static constexpr bool c_stdCamera_hasShutter
Do not expose shutter controls.
Definition cred2Ctrl.hpp:81
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
PdvDev * m_pdv
The EDT PDV device handle.
Definition edtCamera.hpp:73
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 m_raw_width
The width of the frame, according to the framegrabber.
Definition edtCamera.hpp:82
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.
size_t m_typeSize
The size of the type, in bytes. Result of sizeof.
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.
float m_fpsSet
The commanded fps, as set by user.
pcf::IndiProperty m_indiP_roi_y
Property used to set the ROI x center coordinate.
int m_full_currbin_w
The current-binning full ROI width.
std::vector< std::string > m_analogGainNames
Valid analog-gain option names for the INDI selection switch.
float m_default_x
Power-on ROI center x coordinate.
std::string m_tempControlStatusStr
Camera specific description of temperature control status.
int m_full_bin_x
The x-binning in the full ROI.
std::vector< std::string > m_fanSpeedNames
Valid fan-control option names for the INDI selection switch.
std::string m_analogGainNameSet
Requested analog-gain option name.
float m_full_currbin_x
The current-binning full ROI center x coordinate.
std::string m_nextMode
The mode to be set by the next reconfiguration.
int m_default_bin_x
Power-on ROI x binning.
bool m_ledStateSet
Requested status LED state.
float m_stepFPS
The FPS step size, used for INDI attributes.
pcf::IndiProperty m_indiP_roi_last
Property used to trigger setting the last ROI.
pcf::IndiProperty m_indiP_roi_h
Property used to set the ROI height.
std::string m_fanSpeedNameSet
Requested fan-control option name.
bool m_ledStateValid
True once the current LED state is known.
std::string m_analogGainName
Current analog-gain option name.
int m_full_bin_y
The y-binning in the full ROI.
float m_full_y
The full ROI center y coordinate.
float m_maxFPS
The maximum FPS, used for INDI attributes.
float m_ccdTempSetpt
The desired temperature, in C.
bool m_tempControlStatus
Whether or not temperature control is active.
bool m_defaultLEDState
The default LED state to apply after power on.
pcf::IndiProperty m_indiP_roi_w
Property used to set the ROI width.
pcf::IndiProperty m_indiP_roi_default
Property used to trigger setting the default and startup ROI.
std::string m_modeName
The current mode name.
pcf::IndiProperty m_indiP_roi_bin_x
Property used to set the ROI x binning.
std::string m_startupMode
The camera mode to load during first init after a power-on.
std::string m_fanSpeedName
Current fan-control option name.
float m_full_x
The full ROI center x coordinate.
float m_startupTemp
The temperature to set after a power-on. Set to <= -999 to not use [default].
int m_full_currbin_h
The current-binning full ROI height.
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.
cameraConfigMap m_cameraModes
Map holding the possible camera mode configurations.
float m_full_currbin_y
The current-binning full ROI center y coordinate.
bool m_analogGainValid
True once the current analog-gain state is known.
pcf::IndiProperty m_indiP_roi_full
Property used to trigger setting the full ROI.
std::vector< std::string > m_analogGainNameLabels
Optional GUI labels for the analog-gain options.
pcf::IndiProperty m_indiP_roi_set
Property used to trigger setting the ROI.
std::vector< std::string > m_fanSpeedNameLabels
Optional GUI labels for the fan-control options.
bool m_ledState
Current status LED state.
float m_default_y
Power-on ROI center y coordinate.
pcf::IndiProperty m_indiP_roi_bin_y
Property used to set the ROI y binning.
pcf::IndiProperty m_indiP_roi_x
Property used to set the ROI x center coordinate.
int m_default_bin_y
Power-on ROI y binning.
bool m_tempControlStatusSet
Desired state of temperature control.
float m_minFPS
The minimum FPS, used for INDI attributes.
#define protected
Utilities for the C-RED 2 camera controller.
Stub EDT camera handle type used by unit tests.
Definition edtinc.h:20
#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_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
bool fullFrame
True when the ROI spans the full detector.
C-RED 2 ROI expressed as 0-based inclusive column and row limits.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ CONFIGURING
The application is configuring the device.
@ 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.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_OK
Definition indiUtils.hpp:28
A camera configuration.
Definition stdCamera.hpp:34
std::string cred2ColumnsSpec(const cred2Roi &roi)
Format the column command payload for set cropping columns.
std::string cred2CleanResponse(const std::string &response)
Strip an optional prompt and surrounding whitespace from a C-RED 2 CLI response.
int cred2ParseRange(int &firstValue, int &secondValue, const std::string &response)
Parse a raw range response such as 0-639.
int cred2RoiToCenter(float &centerX, float &centerY, int &width, int &height, const cred2Roi &roi, int fullWidth, int fullHeight)
Convert C-RED 2 ROI corners into a MagAO-X ROI center/size description.
int cred2ParseCropState(bool &enabled, int &startColumn, int &endColumn, int &startRow, int &endRow, const std::string &response)
Parse a raw cropping status response such as on or on:192-447:128-383.
int cred2RoiFromCenter(cred2Roi &roi, float centerX, float centerY, int width, int height, int fullWidth, int fullHeight)
Convert a MagAO-X ROI center/size description into C-RED 2 corners.
int cred2ParseFloatVector(std::vector< float > &values, const std::string &response, size_t expectedValues)
Parse a delimited list of raw numeric responses into a float vector.
bool cred2ResponseOK(const std::string &response)
Check whether a command response looks successful.
std::string cred2RowsSpec(const cred2Roi &roi)
Format the row command payload for set cropping rows.
int cred2ParseFloat(float &value, const std::string &response)
Parse a raw numeric response into a float.
int cred2ParseBool(bool &value, const std::string &response)
Parse a raw on/off response into a boolean.
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.
#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_APP_SHUTDOWN
Call stdCameraT::appShutdown with error checking for stdCamera.
Structure holding the temperature values reported by the C-RED 2.
float powerboard
Power-board temperature [C].
float setpoint
Detector temperature setpoint [C].
float peltier
External TEC temperature [C].
float motherboard
Motherboard temperature [C].
int setInvalid()
Mark all temperature values invalid.
float snake
Detector temperature [C].
float frontend
Front-end temperature [C].
float heatsink
Heatsink temperature [C].
A device base class which saves telemetry.
Definition telemeter.hpp:75
Log entry recording the C-RED 2 detailed temperature channels.
Software CRITICAL log entry.
Software ERR 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
#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.