API
 
Loading...
Searching...
No Matches
stdCamera.hpp
Go to the documentation of this file.
1/** \file stdCamera.hpp
2 * \brief Standard camera interface
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup app_files
7 */
8
9#ifndef stdCamera_hpp
10#define stdCamera_hpp
11
12#include <string>
13#include <unordered_map>
14
15#include <mx/app/application.hpp>
16
17#include "../MagAOXApp.hpp"
18
19namespace MagAOX
20{
21namespace app
22{
23namespace dev
24{
25
26#define CAMCTRL_E_NOCONFIGS ( -10 )
27
28/// A camera configuration
29/** a.k.a. a mode
30 */
32{
33 std::string m_configFile; ///< The file to use for this mode, e.g. an EDT configuration file.
34 std::string m_serialCommand; ///< The command to send to the camera to place it in this mode.
35 unsigned m_centerX{ 0 };
36 unsigned m_centerY{ 0 };
37 unsigned m_sizeX{ 0 };
38 unsigned m_sizeY{ 0 };
39 unsigned m_binningX{ 0 };
40 unsigned m_binningY{ 0 };
41
42 unsigned m_digitalBinX{ 0 };
43 unsigned m_digitalBinY{ 0 };
44
45 float m_maxFPS{ 0 };
46};
47
48typedef std::unordered_map<std::string, cameraConfig> cameraConfigMap;
49
50/// Load the camera configurations contained in the app configuration into a map
51int loadCameraConfig( cameraConfigMap &ccmap, ///< [out] the map in which to place the configurations found in config
52 mx::app::appConfigurator &config ///< [in] the application configuration structure
53);
54
55/// MagAO-X standard camera interface
56/** Implements the standard interface to a MagAO-X camera. The derived class `derivedT` must
57 * meet the following requirements:
58 *
59 * - The derived class `derivedT` must be a `MagAOXApp<true>`
60 *
61 * - Must declare this class a friend like so:
62 * \code
63 * friend class dev::stdCamera<DERIVEDNAME>; //replace DERIVEDNAME with derivedT class name
64 * \endcode
65 *
66 * - Must declare the following typedef:
67 * \code
68 * typedef dev::stdCamera<DERIVEDNAME> stdCameraT; //replace DERIVEDNAME with derivedT class name
69 * \endcode
70 *
71 * - Must declare a series of `static constexpr` flags to manage static compile-time configuration. Each of these
72 * flags must be defined in derivedT to be either true or false.
73 *
74 * - Temperature Control and Status:
75 *
76 * - A static configuration variable must be defined in derivedT as
77 * \code
78 * static constexpr bool c_stdCamera_tempControl = true; //or: false
79 * \endcode
80 * which determines whether or not temperature controls are exposed.
81 *
82 * - If `(c_stdCamera_tempControl == true)` then the derived class must implement the following interfaces
83 * \code
84 * int setTempControl(); // set temp control status according to m_tempControlStatusSet
85 * int setTempSetPt(); // set the temperature set point accordin to m_ccdTempSetpt
86 * \endcode
87 *
88 * - A static configuration variable must be defined in derivedT as
89 * \code
90 * static constexpr bool c_stdCamera_temp = true; //or: false
91 * \endcode
92 * which determines whether or not temperature reporting is exposed. Note that if
93 * `(c_stdCamera_tempControl == true)`, then the behavior is as if `c_stdCamera_temp == true`,
94 * but thus constexpr must still be defined.
95 *
96 * - If either `(c_stdCamera_tempControl == true)` or `c_stdCamera_temp == true` then the INDI property
97 * "temp_ccd" will be updated from the value of \ref m_ccdTemp.
98 *
99 * - Readout Speed:
100 *
101 * - A static configuration variable must be defined in derivedT as
102 * \code
103 * static constexpr bool c_stdCamera_readoutSpeed = true; //or: false
104 * \endcode
105 * which determines whether or not readout speed controls are exposed. If true, then the implementation should
106 * populate
107 * \ref m_readoutSpeedNames and \ref m_readoutSpeedNameLabels (vectors of strings) on construction to the
108 * allowed values. This facility is normally used to control both amplifier and readout/adc speed with names like
109 * "ccd_1MHz" and "emccd_17MHz".
110 *
111 * - If used (and true) then the following interface must be implemented:
112 * \code
113 * int setReadoutSpeed(); // configures camera using m_readoutSpeedNameSet
114 * \endcode
115 * This configures the camera according to \ref m_readoutSpeedNameSet.
116 * The implementation must also manage \ref m_readoutSpeedName, keeping it up to date with the current setting.
117 *
118 * - If true, the configuration setting "camera.defaultReadoutSpeed"
119 * is also exposed, and \ref m_defaultReadoutSpeed will be set according to it. The implementation can
120 * set a sensible default on construction.
121 *
122 * - Vertical Shift Speed:
123 *
124 * - A static configuration variable must be defined in derivedT as
125 * \code
126 * static constexpr bool c_stdCamera_vShiftSpeed = true; //or: false
127 * \endcode
128 * which determines whether or not vertical shift speed controls are exposed.
129 *
130 * - If true, then the implementation should populate \ref m_vShiftSpeedNames and \ref m_vShiftSpeedLabels
131 * (vectors of strings) on construction to the allowed values. This
132 * facility is normally used with names like "0_3us" and "1_3us".
133 *
134 * - If true then the following interface must be defined:
135 * \code
136 * int setVShiftSpeed(); // configures camera according to m_vShiftSpeedNameSet
137 * \endcode
138 * function must be defined which sets the camera according to \ref m_vShiftSpeedNameSet.
139 * The implementation must also manage m_vShiftSpeedName, keeping it up to date.
140 *
141 * - The configuration setting "camera.defaultVShiftSpeed"
142 * is also exposed, and \ref m_defaultVShiftSpeed will be set accordingly. derivedT can set a sensible default
143 * on constuction.
144 *
145 * - Exposure Time:
146 * - A static configuration variable must be defined in derivedT as
147 * \code
148 * static constexpr bool c_stdCamera_exptimeCtrl = true; //or: false
149 * \endcode
150 * - If true, the following interface must be implemented:
151 * \code
152 * int setExpTime(); // set camera exposure time according to m_expTimeSet.
153 * \endcode
154 * to configure the camera according to \ref m_expTimeSet. derivedT must also keep \ref m_expTime up to date.
155 *
156 * - Frames per Second (FPS) Control and Status:
157 * - A static configuration variable must be defined in derivedT as
158 * \code
159 * static constexpr bool c_stdCamera_fpsCtrl = true; //or: false
160 * \endcode
161 *
162 * - If that is set to true the derivedT must implement
163 * \code
164 * int setFPS(); // set camera FS according to m_fps
165 * \endcode
166 * to configure the camera according to \ref m_fpsSet.
167 *
168 * - A static configuration variable must be defined in derivedT as
169 * \code
170 * static constexpr bool c_stdCamera_fps = true; //or: false
171 * \endcode
172 * Note that the value of c_stdCamera_fps does not matter if c_stdCamera_fpsCtrl == true.
173 *
174 * - If either `c_stdCamera_fpsCtrl == true` or `c_stdCamera_fps == true` then derivedT must also
175 * keep \ref m_fps up to date.
176 *
177 * - Synchro Control:
178 *
179 * - A static configuration variable must be defined in derivedT as
180 * \code
181 * static constexpr bool c_stdCamera_synchro = true; //or: false
182 * \endcode
183 * - If that is set to true the derivedT must implement
184 * \code
185 * int setSynchro(); // configure the camera based m_synchroSet.
186 * \endcode
187 * to configure the camera based on \ref m_synchroSet. The implementation should also keep
188 * \ref m_synchro up to date.
189 *
190 * - EM Gain:
191 * - A static configuration variable must be defined in derivedT as
192 * \code
193 * static constexpr bool c_stdCamera_emGain = true; //or: false
194 * \endcode
195 * which determines whether or not EM gain controls are exposed.
196 *
197 * - If the camera uses EM Gain, then a function
198 * \code
199 * int setEMGain(); // set EM gain based on m_emGainSet.
200 * \endcode
201 * must be defined which sets the camera EM Gain to \ref m_emGainSet.
202 *
203 * - If true the implementation must keep \ref m_emGain up to date.
204 *
205 * - If true the value of \ref m_maxEMGain should be set by the implementation and managed
206 * as needed. Additionally the configuration setting "camera.maxEMGain" is exposed.
207 *
208 * - Camera Modes:
209 *
210 * - A static configuration variable must be defined in derivedT as
211 * \code
212 * static constexpr bool c_stdCamera_usesModes= true; //or: false
213 * \endcode
214 *
215 * - If true, then modes are read from the configuration file. See \ref loadCameraConfig()
216 *
217 * - If true, then the configuration setting "camera.startupMode" is exposed, which sets the mode at startup by
218 * its name.
219 *
220 * - Regions of Interest
221 *
222 * - A static configuration variable must be defined in derivedT as
223 * \code
224 * static constexpr bool c_stdCamera_usesROI = true; //or: false
225 * \endcode
226 *
227 * - The default values of m_full_x/y/w/h must be set before calling stdCamera::appStartup(). These
228 * are configured by stdCamera::loadConfig(), but only if set in the config file.
229 *
230 * - The derived class must implement:
231 * \code
232 * int checkNextROI(); // verifies m_nextROI values and modifies to closest valid values if needed
233 * int setNextROI(); // sets the ROI to the new target values.
234 * \endcode
235 *
236 * - Crop Mode ROIs:
237 *
238 * - A static configuration variable must be defined in derivedT as
239 * \code
240 * static constexpr bool c_stdCamera_cropMode = true; //or: false
241 * \endcode
242 *
243 * - If true the derived class must implement
244 * \code
245 * int setCropMode(); // set crop mode according to m_cropModeSet
246 * \endcode
247 * which changes the crop mode according to \ref m_cropModeSet.
248 *
249 * - `derivedT` must also maintain the value of \ref m_cropMode.
250 *
251 * - Shutters:
252 *
253 * - A static configuration variable must be defined in derivedT as
254 * \code
255 * static constexpr bool c_stdCamera_hasShutter = true; //or: false
256 * \endcode
257 *
258 * - If true the following interface must be implemented:
259 * \code
260 * int setShutter(int); // shut the shutter if 0, open the shutter otherwise.
261 * \endcode
262 * which shuts the shutter if the argument is 0, opens it otherwise.
263 *
264 * - State:
265 *
266 * - A static configuration variable must be defined in derivedT as
267 * \code
268 * static constexpr bool c_stdCamera_usesStateString = true; //or: false
269 * \endcode
270 * which determines whether the class provides a state string for dark management.
271 *
272 * - If true, the following functions must be defined in derivedT:
273 * \code
274 * std::string stateString(); //String capturing the current state. Must not include "__T".
275 * bool stateStringValid(); //Whether or not the current state string is valid, i.e. not changing.
276 * \endcode
277 *
278 *
279 * - The derived class must implement:
280 * \code
281 * int powerOnDefaults(); // called on power-on after powerOnWaitElapsed has occurred.
282 * \endcode
283 *
284 * - Calls to this class's setupConfig(), loadConfig(), appStartup(), appLogic(), appShutdown()
285 * onPowerOff(), and whilePowerOff(), must be placed in the derived class's functions of the same name.
286 *
287 * \ingroup appdev
288 */
289template <class derivedT>
291{
292 protected:
293 /** \name Configurable Parameters
294 * @{
295 */
296
297 cameraConfigMap m_cameraModes; ///< Map holding the possible camera mode configurations
298
299 std::string m_startupMode; ///< The camera mode to load during first init after a power-on.
300
301 float m_startupTemp{ -999 }; ///< The temperature to set after a power-on. Set to <= -999 to not use [default].
302
303 std::string m_defaultReadoutSpeed; ///< The default readout speed of the camera.
304 std::string m_defaultVShiftSpeed; ///< The default readout speed of the camera.
305
306 ///@}
307
308 /** \name Temperature Control Interface
309 * @{
310 */
311
312 float m_minTemp{ -60 };
313 float m_maxTemp{ 30 };
314 float m_stepTemp{ 0 };
315
316 float m_ccdTemp{ -999 }; ///< The current temperature, in C
317
318 float m_ccdTempSetpt{ -999 }; ///< The desired temperature, in C
319
320 bool m_tempControlStatus{ false }; ///< Whether or not temperature control is active
321 bool m_tempControlStatusSet{ false }; ///< Desired state of temperature control
322
323 bool m_tempControlOnTarget{ false }; ///< Whether or not the temperature control system is on its target temperature
324
325 std::string m_tempControlStatusStr; ///< Camera specific description of temperature control status.
326
327 pcf::IndiProperty m_indiP_temp;
328 pcf::IndiProperty m_indiP_tempcont;
329 pcf::IndiProperty m_indiP_tempstat;
330
331 ///@}
332
333 /** \name Readout Control
334 * @{
335 */
336
337 std::vector<std::string> m_readoutSpeedNames;
338 std::vector<std::string> m_readoutSpeedNameLabels;
339
340 std::string m_readoutSpeedName; ///< The current readout speed name
341 std::string m_readoutSpeedNameSet; ///< The user requested readout speed name, to be set by derived()
342
343 std::vector<std::string> m_vShiftSpeedNames;
344 std::vector<std::string> m_vShiftSpeedNameLabels;
345
346 std::string m_vShiftSpeedName; ///< The current vshift speed name
347 std::string m_vShiftSpeedNameSet; ///< The user requested vshift speed name, to be set by derived()
348
349 float m_adcSpeed{ 0 };
350 float m_vshiftSpeed{ 0 };
351
352 float m_emGain{ 1 }; ///< The camera's current EM gain (if available).
353 float m_emGainSet{ 1 }; ///< The camera's EM gain, as set by the user.
354 float m_maxEMGain{ 1 }; ///< The configurable maximum EM gain. To be enforced in derivedT.
355
356 pcf::IndiProperty m_indiP_readoutSpeed;
357 pcf::IndiProperty m_indiP_vShiftSpeed;
358
359 pcf::IndiProperty m_indiP_emGain;
360
361 ///@}
362
363 /** \name Exposure Control
364 * @{
365 */
366 float m_minExpTime{ 0 }; ///< The minimum exposure time, used for INDI attributes
367 float m_maxExpTime{ std::numeric_limits<float>::max() }; ///< The maximum exposure time, used for INDI attributes
368 float m_stepExpTime{ 0 }; ///< The maximum exposure time stepsize, used for INDI attributes
369
370 float m_expTime{ 0 }; ///< The current exposure time, in seconds.
371 float m_expTimeSet{ 0 }; ///< The exposure time, in seconds, as set by user.
372
373 float m_minFPS{ 0 }; ///< The minimum FPS, used for INDI attributes
374 float m_maxFPS{ std::numeric_limits<float>::max() }; ///< The maximum FPS, used for INDI attributes
375 float m_stepFPS{ 0 }; ///< The FPS step size, used for INDI attributes
376
377 float m_fps{ 0 }; ///< The current FPS.
378 float m_fpsSet{ 0 }; ///< The commanded fps, as set by user.
379
380 pcf::IndiProperty m_indiP_exptime;
381
382 pcf::IndiProperty m_indiP_fps;
383
384 ///@}
385
386 /** \name External Synchronization
387 * @{
388 */
389 bool m_synchroSet{ false }; ///< Target status of m_synchro
390
391 bool m_synchro{ false }; ///< Status of synchronization, true is on, false is off.
392
393 pcf::IndiProperty m_indiP_synchro;
394
395 ///@}
396
397 /** \name Modes
398 *
399 * @{
400 */
401 std::string m_modeName; ///< The current mode name
402
403 std::string m_nextMode; ///< The mode to be set by the next reconfiguration
404
405 pcf::IndiProperty m_indiP_mode; ///< Property used to report the current mode
406
407 pcf::IndiProperty
408 m_indiP_reconfig; ///< Request switch which forces the framegrabber to go through the reconfigure process.
409
410 ///@}
411
412 /** \name ROIs
413 * ROI controls are exposed if derivedT::c_stdCamera_usesROI==true
414 * @{
415 */
416 struct roi
417 {
418 float x{ 0 };
419 float y{ 0 };
420 int w{ 0 };
421 int h{ 0 };
422 int bin_x{ 0 };
423 int bin_y{ 0 };
424 };
425
429
430 float m_minROIx{ 0 };
431 float m_maxROIx{ 1023 };
432 float m_stepROIx{ 0 };
433
434 float m_minROIy{ 0 };
435 float m_maxROIy{ 1023 };
436 float m_stepROIy{ 0 };
437
439 int m_maxROIWidth{ 1024 };
441
443 int m_maxROIHeight{ 1024 };
445
449
453
454 float m_default_x{ 0 }; ///< Power-on ROI center x coordinate.
455 float m_default_y{ 0 }; ///< Power-on ROI center y coordinate.
456 int m_default_w{ 0 }; ///< Power-on ROI width.
457 int m_default_h{ 0 }; ///< Power-on ROI height.
458 int m_default_bin_x{ 1 }; ///< Power-on ROI x binning.
459 int m_default_bin_y{ 1 }; ///< Power-on ROI y binning.
460
461 float m_full_x{ 0 }; ///< The full ROI center x coordinate.
462 float m_full_y{ 0 }; ///< The full ROI center y coordinate.
463 int m_full_w{ 0 }; ///< The full ROI width.
464 int m_full_h{ 0 }; ///< The full ROI height.
465 int m_full_bin_x{ 1 }; ///< The x-binning in the full ROI.
466 int m_full_bin_y{ 1 }; ///< The y-binning in the full ROI.
467
468 float m_full_currbin_x{ 0 }; ///< The current-binning full ROI center x coordinate.
469 float m_full_currbin_y{ 0 }; ///< The current-binning full ROI center y coordinate.
470 int m_full_currbin_w{ 0 }; ///< The current-binning full ROI width.
471 int m_full_currbin_h{ 0 }; ///< The current-binning full ROI height.
472
473 pcf::IndiProperty m_indiP_roi_x; ///< Property used to set the ROI x center coordinate
474 pcf::IndiProperty m_indiP_roi_y; ///< Property used to set the ROI x center coordinate
475 pcf::IndiProperty m_indiP_roi_w; ///< Property used to set the ROI width
476 pcf::IndiProperty m_indiP_roi_h; ///< Property used to set the ROI height
477 pcf::IndiProperty m_indiP_roi_bin_x; ///< Property used to set the ROI x binning
478 pcf::IndiProperty m_indiP_roi_bin_y; ///< Property used to set the ROI y binning
479
480 pcf::IndiProperty m_indiP_fullROI; ///< Property used to preset the full ROI dimensions.
481
482 pcf::IndiProperty m_indiP_roi_check; ///< Property used to trigger checking the target ROI
483
484 pcf::IndiProperty m_indiP_roi_set; ///< Property used to trigger setting the ROI
485
486 pcf::IndiProperty m_indiP_roi_full; ///< Property used to trigger setting the full ROI.
487 pcf::IndiProperty m_indiP_roi_fullbin; ///< Property used to trigger setting the full in current binning ROI.
488 pcf::IndiProperty m_indiP_roi_loadlast; ///< Property used to trigger loading the last ROI as the target.
489 pcf::IndiProperty m_indiP_roi_last; ///< Property used to trigger setting the last ROI.
490 pcf::IndiProperty m_indiP_roi_default; ///< Property used to trigger setting the default and startup ROI.
491
492 ///@}
493
494 /** \name Crop Mode
495 * Crop mode controls are exposed if derivedT::c_stdCamera_cropMode==true
496 * @{
497 */
498 bool m_cropMode{ false }; ///< Status of crop mode ROIs, if enabled for this camera.
499 bool m_cropModeSet{ false }; ///< Desired status of crop mode ROIs, if enabled for this camera.
500
501 pcf::IndiProperty m_indiP_cropMode; ///< Property used to toggle crop mode on and off.
502 ///@}
503
504 /** \name Shutter Control
505 * Shutter controls are exposed if derivedT::c_stdCamera_hasShutter == true.
506 * @{
507 */
508 std::string m_shutterStatus{ "UNKNOWN" };
509 int m_shutterState{ -1 }; /// State of the shutter. 0 = shut, 1 = open, -1 = unknown.
510
511 pcf::IndiProperty m_indiP_shutterStatus; ///< Property to report shutter status
512 pcf::IndiProperty m_indiP_shutter; ///< Property used to control the shutter, a switch.
513
514 ///@}
515
516 /** \name State String
517 * The State string is exposed if derivedT::c_stdCamera_usesStateString is true.
518 * @{
519 */
520 pcf::IndiProperty m_indiP_stateString;
521 ///@}
522
523 public:
524 /// Destructor.
525 ~stdCamera() noexcept;
526
527 /// Setup the configuration system
528 /**
529 * This should be called in `derivedT::setupConfig` as
530 * \code
531 stdCamera<derivedT>::setupConfig(config);
532 \endcode
533 * with appropriate error checking.
534 */
535 int setupConfig( mx::app::appConfigurator &config /**< [out] the derived classes configurator*/ );
536
537 /// load the configuration system results
538 /**
539 * This should be called in `derivedT::loadConfig` as
540 * \code
541 stdCamera<derivedT>::loadConfig(config);
542 \endcode
543 * with appropriate error checking.
544 */
545 int loadConfig( mx::app::appConfigurator &config /**< [in] the derived classes configurator*/ );
546
547 protected:
548 // workers to create indi variables if needed
549 int createReadoutSpeed( const mx::meta::trueFalseT<true> &t );
550
551 int createReadoutSpeed( const mx::meta::trueFalseT<false> &f );
552
553 int createVShiftSpeed( const mx::meta::trueFalseT<true> &t );
554
555 int createVShiftSpeed( const mx::meta::trueFalseT<false> &f );
556
557 public:
558 /// Startup function
559 /**
560 * This should be called in `derivedT::appStartup` as
561 * \code
562 stdCamera<derivedT>::appStartup();
563 \endcode
564 * with appropriate error checking.
565 *
566 * You should set the default/startup values of m_currentROI as well as the min/max/step values for the ROI
567 parameters
568 * before calling this function.
569 *
570 * \returns 0 on success
571 * \returns -1 on error, which is logged.
572 */
574
575 /// Application logic
576 /** Checks the stdCamera thread
577 *
578 * This should be called from the derived's appLogic() as in
579 * \code
580 stdCamera<derivedT>::appLogic();
581 \endcode
582 * with appropriate error checking.
583 *
584 * \returns 0 on success
585 * \returns -1 on error, which is logged.
586 */
587 int appLogic();
588
589 /// Actions on power off
590 /**
591 * This should be called from the derived's onPowerOff() as in
592 * \code
593 stdCamera<derivedT>::onPowerOff();
594 \endcode
595 * with appropriate error checking.
596 *
597 * The INDI mutex should be locked before calling.
598 *
599 * \returns 0 on success
600 * \returns -1 on error, which is logged.
601 */
603
604 /// Actions while powered off
605 /**
606 * This should be called from the derived's whilePowerOff() as in
607 * \code
608 stdCamera<derivedT>::whilePowerOff();
609 \endcode
610 * with appropriate error checking.
611 *
612 * \returns 0 on success
613 * \returns -1 on error, which is logged.
614 */
616
617 /// Application shutdown
618 /** Shuts down the stdCamera thread
619 *
620 * \code
621 stdCamera<derivedT>::appShutdown();
622 \endcode
623 * with appropriate error checking.
624 *
625 * \returns 0 on success
626 * \returns -1 on error, which is logged.
627 */
629
630 protected:
631 /** \name INDI
632 *
633 *@{
634 */
635 public:
636 /// The static callback function to be registered for stdCamera properties
637 /** Calls newCallback_stdCamera
638 *
639 * \returns 0 on success.
640 * \returns -1 on error.
641 */
643 void *app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
644 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
645 );
646
647 /// The callback function for stdCamera properties
648 /** Dispatches to the relevant handler
649 *
650 * \returns 0 on success.
651 * \returns -1 on error.
652 */
654 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
655
656 /// Interface to setTempSetPt when the derivedT has temperature control
657 /** Tag-dispatch resolution of c_stdCamera_tempControl==true will call this function.
658 * Calls derivedT::setTempSetPt.
659 */
660 int setTempSetPt( const mx::meta::trueFalseT<true> &t );
661
662 /// Interface to setTempSetPt when the derivedT does not have temperature control
663 /** Tag-dispatch resolution of c_stdCamera_tempControl==false will call this function.
664 * Prevents requiring derivedT::setTempSetPt.
665 */
666 int setTempSetPt( const mx::meta::trueFalseT<false> &f );
667
668 /// Callback to process a NEW CCD temp request
669 /**
670 * \returns 0 on success.
671 * \returns -1 on error.
672 */
674 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
675
676 /// Interface to setTempControl when the derivedT has temperature control
677 /** Tag-dispatch resolution of c_stdCamera_tempControl==true will call this function.
678 * Calls derivedT::setTempControl.
679 */
680 int setTempControl( const mx::meta::trueFalseT<true> &t );
681
682 /// Interface to setTempControl when the derivedT does not have temperature control
683 /** Tag-dispatch resolution of c_stdCamera_tempControl==false will call this function.
684 * Prevents requiring derivedT::setTempControl.
685 */
686 int setTempControl( const mx::meta::trueFalseT<false> &f );
687
688 /// Callback to process a NEW CCD temp control request
689 /**
690 * \returns 0 on success.
691 * \returns -1 on error.
692 */
694 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
695
696 /// Interface to setReadoutSpeed when the derivedT has readout speed control
697 /** Tag-dispatch resolution of c_stdCamera_readoutSpeed==true will call this function.
698 * Calls derivedT::setReadoutSpeed.
699 */
700 int setReadoutSpeed( const mx::meta::trueFalseT<true> &t );
701
702 /// Interface to setReadoutSpeed when the derivedT does not have readout speed control
703 /** Tag-dispatch resolution of c_stdCamera_readoutSpeed==false will call this function.
704 * Just returns 0.
705 */
706 int setReadoutSpeed( const mx::meta::trueFalseT<false> &f );
707
708 /// Callback to process a NEW readout speed request
709 /**
710 * \returns 0 on success.
711 * \returns -1 on error.
712 */
714 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
715
716 /// Interface to setVShiftSpeed when the derivedT has vshift speed control
717 /** Tag-dispatch resolution of c_stdCamera_vShiftSpeed==true will call this function.
718 * Calls derivedT::setVShiftSpeed.
719 */
720 int setVShiftSpeed( const mx::meta::trueFalseT<true> &t );
721
722 /// Interface to setVShiftSpeed when the derivedT does not have vshift speed control
723 /** Tag-dispatch resolution of c_stdCamera_vShiftSpeed==false will call this function.
724 * Just returns 0.
725 */
726 int setVShiftSpeed( const mx::meta::trueFalseT<false> &f );
727
728 /// Callback to process a NEW vshift speed request
729 /**
730 * \returns 0 on success.
731 * \returns -1 on error.
732 */
734 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
735
736 /// Interface to setEMGain when the derivedT has EM Gain
737 /** Tag-dispatch resolution of c_stdCamera_emGain==true will call this function.
738 * Calls derivedT::setEMGain.
739 */
740 int setEMGain( const mx::meta::trueFalseT<true> &t );
741
742 /// Interface to setEMGain when the derivedT does not have EM Gain
743 /** Tag-dispatch resolution of c_stdCamera_emGain==false will call this function.
744 * This prevents requiring derivedT to have its own setEMGain().
745 */
746 int setEMGain( const mx::meta::trueFalseT<false> &f );
747
748 /// Callback to process a NEW EM gain request
749 /**
750 * \returns 0 on success.
751 * \returns -1 on error.
752 */
754 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
755
756 /// Interface to setExpTime when the derivedT uses exposure time controls
757 /** Tag-dispatch resolution of c_stdCamera_exptimeCtrl==true will call this function.
758 * Calls derivedT::setExpTime.
759 */
760 int setExpTime( const mx::meta::trueFalseT<true> &t );
761
762 /// Interface to setExptime when the derivedT does not use exposure time controls.
763 /** Tag-dispatch resolution of c_stdCamera_exptimeCtrl==false will call this function.
764 * This prevents requiring derivedT to have its own setExpTime().
765 */
766 int setExpTime( const mx::meta::trueFalseT<false> &f );
767
768 /// Callback to process a NEW exposure time request
769 /**
770 * \returns 0 on success.
771 * \returns -1 on error.
772 */
774 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
775
776 /// Interface to setFPS when the derivedT uses FPS controls
777 /** Tag-dispatch resolution of c_stdCamera_fpsCtrl==true will call this function.
778 * Calls derivedT::setFPS.
779 */
780 int setFPS( const mx::meta::trueFalseT<true> &t );
781
782 /// Interface to setFPS when the derivedT does not use FPS controls.
783 /** Tag-dispatch resolution of c_stdCamera_hasFPS==false will call this function.
784 * This prevents requiring derivedT to have its own setFPS().
785 */
786 int setFPS( const mx::meta::trueFalseT<false> &f );
787
788 /// Callback to process a NEW fps request
789 /**
790 * \returns 0 on success.
791 * \returns -1 on error.
792 */
794 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
795
796 /// Interface to setSynchro when the derivedT has synchronization
797 /** Tag-dispatch resolution of c_stdCamera_synchro==true will call this function.
798 * Calls derivedT::setSynchro.
799 */
800 int setSynchro( const mx::meta::trueFalseT<true> &t );
801
802 /// Interface to setSynchro when the derivedT does not have synchronization
803 /** Tag-dispatch resolution of c_stdCamera_ynchro==false will call this function.
804 * This prevents requiring derivedT to have its own setSynchro().
805 */
806 int setSynchro( const mx::meta::trueFalseT<false> &f );
807
808 /// Callback to process a NEW synchro request
809 /**
810 * \returns 0 on success.
811 * \returns -1 on error.
812 */
814 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
815
816 /// Callback to process a NEW mode request
817 /**
818 * \returns 0 on success.
819 * \returns -1 on error.
820 */
822 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
823
824 /// Callback to process a NEW reconfigure request
825 /**
826 * \returns 0 on success.
827 * \returns -1 on error.
828 */
830 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
831
832 /// Interface to setCropMode when the derivedT has crop mode
833 /** Tag-dispatch resolution of c_stdCamera_cropMode==true will call this function.
834 * Calls derivedT::setCropMode.
835 */
836 int setCropMode( const mx::meta::trueFalseT<true> &t );
837
838 /// Interface to setCropMode when the derivedT does not have crop mode
839 /** Tag-dispatch resolution of c_stdCamera_cropMode==false will call this function.
840 * This prevents requiring derivedT to have its own setCropMode().
841 */
842 int setCropMode( const mx::meta::trueFalseT<false> &f );
843
844 /// Callback to process a NEW cropMode request
845 /**
846 * \returns 0 on success.
847 * \returns -1 on error.
848 */
850 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
851
852 /// Callback to process a NEW roi_x request
853 /**
854 * \returns 0 on success.
855 * \returns -1 on error.
856 */
858 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
859
860 /// Callback to process a NEW roi_y request
861 /**
862 * \returns 0 on success.
863 * \returns -1 on error.
864 */
866 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
867
868 /// Callback to process a NEW roi_w request
869 /**
870 * \returns 0 on success.
871 * \returns -1 on error.
872 */
874 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
875
876 /// Callback to process a NEW roi_h request
877 /**
878 * \returns 0 on success.
879 * \returns -1 on error.
880 */
882 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
883
884 /// Callback to process a NEW bin_x request
885 /**
886 * \returns 0 on success.
887 * \returns -1 on error.
888 */
890 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
891
892 /// Callback to process a NEW bin_y request
893 /**
894 * \returns 0 on success.
895 * \returns -1 on error.
896 */
898 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
899
900 /// Interface to checkNextROI when the derivedT uses ROIs
901 /** Tag-dispatch resolution of c_stdCamera_usesROI==true will call this function.
902 * Calls derivedT::checkNextROI.
903 */
904 int checkNextROI( const mx::meta::trueFalseT<true> &t );
905
906 /// Interface to checkNextROI when the derivedT does not use ROIs.
907 /** Tag-dispatch resolution of c_stdCamera_usesROI==false will call this function.
908 * This prevents requiring derivedT to have its own checkNextROI().
909 */
910 int checkNextROI( const mx::meta::trueFalseT<false> &f );
911
912 /// Callback to process a NEW roi_check request
913 /**
914 * \returns 0 on success.
915 * \returns -1 on error.
916 */
918 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
919
920 /// Interface to setNextROI when the derivedT uses ROIs
921 /** Tag-dispatch resolution of c_stdCamera_usesROI==true will call this function.
922 * Calls derivedT::setNextROI.
923 */
924 int setNextROI( const mx::meta::trueFalseT<true> &t );
925
926 /// Interface to setNextROI when the derivedT does not use ROIs.
927 /** Tag-dispatch resolution of c_stdCamera_usesROI==false will call this function.
928 * This prevents requiring derivedT to have its own setNextROI().
929 */
930 int setNextROI( const mx::meta::trueFalseT<false> &f );
931
932 /// Callback to process a NEW roi_set request
933 /**
934 * \returns 0 on success.
935 * \returns -1 on error.
936 */
938 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
939
940 /// Callback to process a NEW roi_full request
941 /**
942 * \returns 0 on success.
943 * \returns -1 on error.
944 */
946 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
947
948 /// Callback to process a NEW roi_fullbin request
949 /**
950 * \returns 0 on success.
951 * \returns -1 on error.
952 */
954 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
955
956 /// Callback to process a NEW roi_loadlast request
957 /**
958 * \returns 0 on success.
959 * \returns -1 on error.
960 */
962 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
963
964 /// Callback to process a NEW roi_last request
965 /**
966 * \returns 0 on success.
967 * \returns -1 on error.
968 */
970 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
971
972 /// Callback to process a NEW roi_default request
973 /**
974 * \returns 0 on success.
975 * \returns -1 on error.
976 */
978 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
979
980 /// Interface to setShutter when the derivedT has a shutter
981 /** Tag-dispatch resolution of c_stdCamera_hasShutter==true will call this function.
982 * Calls derivedT::setShutter.
983 */
984 int setShutter( int ss, const mx::meta::trueFalseT<true> &t );
985
986 /// Interface to setShutter when the derivedT does not have a shutter.
987 /** Tag-dispatch resolution of c_stdCamera_hasShutter==false will call this function.
988 * This prevents requiring derivedT to have its own setShutter().
989 */
990 int setShutter( int ss, const mx::meta::trueFalseT<false> &f );
991
992 /// Callback to process a NEW shutter request
993 /**
994 * \returns 0 on success.
995 * \returns -1 on error.
996 */
998 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
999
1000 /// Interface to stateString when the derivedT provides it
1001 /** Tag-dispatch resolution of c_stdCamera_usesStateString==true will call this function.
1002 * Calls derivedT::stateString.
1003 */
1004 std::string stateString( const mx::meta::trueFalseT<true> &t );
1005
1006 /// Interface to stateString when the derivedT does not provide it
1007 /** Tag-dispatch resolution of c_stdCamera_usesStateString==false will call this function.
1008 * returns "".
1009 */
1010 std::string stateString( const mx::meta::trueFalseT<false> &f );
1011
1012 /// Interface to stateStringValid when the derivedT provides it
1013 /** Tag-dispatch resolution of c_stdCamera_usesStateString==true will call this function.
1014 * Calls derivedT::stateStringValid.
1015 */
1016 bool stateStringValid( const mx::meta::trueFalseT<true> &t );
1017
1018 /// Interface to stateStringValid when the derivedT does not provide it
1019 /** Tag-dispatch resolution of c_stdCamera_usesStateString==false will call this function.
1020 * returns false.
1021 */
1022 bool stateStringValid( const mx::meta::trueFalseT<false> &f );
1023
1024 /// Update the INDI properties for this device controller
1025 /** You should call this once per main loop.
1026 * It is not called automatically.
1027 *
1028 * \returns 0 on success.
1029 * \returns -1 on error.
1030 */
1032
1033 ///@}
1034
1035 /** \name Telemeter Interface
1036 * @{
1037 */
1038
1039 int recordCamera( bool force = false );
1040
1041 ///@}
1042
1043 private:
1044 derivedT &derived()
1045 {
1046 return *static_cast<derivedT *>( this );
1047 }
1048};
1049
1050template <class derivedT>
1052{
1053 return;
1054}
1055
1056template <class derivedT>
1057int stdCamera<derivedT>::setupConfig( mx::app::appConfigurator &config )
1058{
1059 if( derivedT::c_stdCamera_tempControl )
1060 {
1061 config.add( "camera.startupTemp",
1062 "",
1063 "camera.startupTemp",
1064 argType::Required,
1065 "camera",
1066 "startupTemp",
1067 false,
1068 "float",
1069 "The temperature setpoint to set after a power-on [C]. Default is 20 C." );
1070 }
1071
1072 if( derivedT::c_stdCamera_readoutSpeed )
1073 {
1074 config.add( "camera.defaultReadoutSpeed",
1075 "",
1076 "camera.defaultReadoutSpeed",
1077 argType::Required,
1078 "camera",
1079 "defaultReadoutSpeed",
1080 false,
1081 "string",
1082 "The default amplifier and readout speed." );
1083 }
1084
1085 if( derivedT::c_stdCamera_vShiftSpeed )
1086 {
1087 config.add( "camera.defaultVShiftSpeed",
1088 "",
1089 "camera.defaultVShiftSpeed",
1090 argType::Required,
1091 "camera",
1092 "defaultVShiftSpeed",
1093 false,
1094 "string",
1095 "The default vertical shift speed." );
1096 }
1097
1098 if( derivedT::c_stdCamera_emGain )
1099 {
1100 config.add( "camera.maxEMGain",
1101 "",
1102 "camera.maxEMGain",
1103 argType::Required,
1104 "camera",
1105 "maxEMGain",
1106 false,
1107 "unsigned",
1108 "The maximum EM gain which can be set by the user." );
1109 }
1110
1111 if( derivedT::c_stdCamera_usesModes )
1112 {
1113 config.add( "camera.startupMode",
1114 "",
1115 "camera.startupMode",
1116 argType::Required,
1117 "camera",
1118 "startupMode",
1119 false,
1120 "string",
1121 "The mode to set upon power on or application startup." );
1122 }
1123
1124 if( derivedT::c_stdCamera_usesROI )
1125 {
1126 config.add( "camera.default_x",
1127 "",
1128 "camera.default_x",
1129 argType::Required,
1130 "camera",
1131 "default_x",
1132 false,
1133 "float",
1134 "The default ROI x position." );
1135
1136 config.add( "camera.default_y",
1137 "",
1138 "camera.default_y",
1139 argType::Required,
1140 "camera",
1141 "default_y",
1142 false,
1143 "float",
1144 "The default ROI y position." );
1145
1146 config.add( "camera.default_w",
1147 "",
1148 "camera.default_w",
1149 argType::Required,
1150 "camera",
1151 "default_w",
1152 false,
1153 "int",
1154 "The default ROI width." );
1155
1156 config.add( "camera.default_h",
1157 "",
1158 "camera.default_h",
1159 argType::Required,
1160 "camera",
1161 "default_h",
1162 false,
1163 "int",
1164 "The default ROI height." );
1165
1166 config.add( "camera.default_bin_x",
1167 "",
1168 "camera.default_bin_x",
1169 argType::Required,
1170 "camera",
1171 "default_bin_x",
1172 false,
1173 "int",
1174 "The default ROI x binning." );
1175
1176 config.add( "camera.default_bin_y",
1177 "",
1178 "camera.default_bin_y",
1179 argType::Required,
1180 "camera",
1181 "default_bin_y",
1182 false,
1183 "int",
1184 "The default ROI y binning." );
1185 }
1186
1187 return 0;
1188}
1189
1190template <class derivedT>
1191int stdCamera<derivedT>::loadConfig( mx::app::appConfigurator &config )
1192{
1193 if( derivedT::c_stdCamera_tempControl )
1194 {
1195 config( m_startupTemp, "camera.startupTemp" );
1196 }
1197
1198 if( derivedT::c_stdCamera_readoutSpeed )
1199 {
1200 config( m_defaultReadoutSpeed, "camera.defaultReadoutSpeed" );
1201 }
1202
1203 if( derivedT::c_stdCamera_vShiftSpeed )
1204 {
1205 config( m_defaultVShiftSpeed, "camera.defaultVShiftSpeed" );
1206 }
1207
1208 if( derivedT::c_stdCamera_emGain )
1209 {
1210 config( m_maxEMGain, "camera.maxEMGain" );
1211 }
1212
1213 if( derivedT::c_stdCamera_usesModes )
1214 {
1215 int rv = loadCameraConfig( m_cameraModes, config );
1216
1217 if( rv < 0 )
1218 {
1219 if( rv == CAMCTRL_E_NOCONFIGS )
1220 {
1221 derivedT::template log<text_log>( "No camera configurations found.", logPrio::LOG_CRITICAL );
1222 }
1223 }
1224
1225 config( m_startupMode, "camera.startupMode" );
1226 }
1227
1228 if( derivedT::c_stdCamera_usesROI )
1229 {
1230 config( m_full_x, "camera.full_x" );
1231 config( m_full_y, "camera.full_y" );
1232 config( m_full_w, "camera.full_w" );
1233 config( m_full_h, "camera.full_h" );
1234 config( m_full_bin_x, "camera.full_bin_x" );
1235 config( m_full_bin_y, "camera.full_bin_y" );
1236
1237 if( m_full_x == 0 )
1238 {
1239 return derivedT::template log<software_critical, -1>(
1240 { __FILE__, __LINE__, "full ROI x (camera.full_x) not set" } );
1241 }
1242
1243 if( m_full_y == 0 )
1244 {
1245 return derivedT::template log<software_critical, -1>(
1246 { __FILE__, __LINE__, "full ROI y (camera.full_y) not set" } );
1247 }
1248
1249 if( m_full_w == 0 )
1250 {
1251 return derivedT::template log<software_critical, -1>(
1252 { __FILE__, __LINE__, "full ROI w (camera.full_w) not set" } );
1253 }
1254
1255 if( m_full_h == 0 )
1256 {
1257 return derivedT::template log<software_critical, -1>(
1258 { __FILE__, __LINE__, "full ROI h (camera.full_h) not set" } );
1259 }
1260
1261 if( m_full_bin_x < 1 )
1262 {
1263 return derivedT::template log<software_critical, -1>(
1264 { __FILE__, __LINE__, "full ROI bin-x (camera.full_bin_x) not set" } );
1265 }
1266
1267 if( m_full_bin_y < 1 )
1268 {
1269 return derivedT::template log<software_critical, -1>(
1270 { __FILE__, __LINE__, "full ROI bin-y (camera.full_bin_y) not set" } );
1271 }
1272
1273 config( m_default_x, "camera.default_x" );
1274 config( m_default_y, "camera.default_y" );
1275 config( m_default_w, "camera.default_w" );
1276 config( m_default_h, "camera.default_h" );
1277 config( m_default_bin_x, "camera.default_bin_x" );
1278 config( m_default_bin_y, "camera.default_bin_y" );
1279
1280 // If default is not setup properly, it defaults to full
1281 if( m_default_x == 0 || m_default_y == 0 || m_default_w == 0 || m_default_h == 0 || m_default_bin_x < 1 ||
1282 m_default_bin_y < 1 )
1283 {
1284 m_default_x = m_full_x;
1285 m_default_y = m_full_y;
1286 m_default_w = m_full_w;
1287 m_default_h = m_full_h;
1288 m_default_bin_x = m_default_bin_x;
1289 m_default_bin_y = m_default_bin_y;
1290 }
1291
1292 // now always start with current and next set to default
1293
1294 m_currentROI.x = m_default_x;
1295 m_currentROI.y = m_default_y;
1296 m_currentROI.w = m_default_w;
1297 m_currentROI.h = m_default_h;
1298 m_currentROI.bin_x = m_default_bin_x;
1299 m_currentROI.bin_y = m_default_bin_y;
1300
1301 m_nextROI.x = m_default_x;
1302 m_nextROI.y = m_default_y;
1303 m_nextROI.w = m_default_w;
1304 m_nextROI.h = m_default_h;
1305 m_nextROI.bin_x = m_default_bin_x;
1306 m_nextROI.bin_y = m_default_bin_y;
1307 }
1308
1309 return 0;
1310}
1311
1312template <class derivedT>
1313int stdCamera<derivedT>::createReadoutSpeed( const mx::meta::trueFalseT<true> &t )
1314{
1315 static_cast<void>( t );
1316
1317 derived().createStandardIndiSelectionSw(
1318 m_indiP_readoutSpeed, "readout_speed", m_readoutSpeedNames, "Readout Speed" );
1319
1320 // Set the labes if provided
1321 if( m_readoutSpeedNameLabels.size() == m_readoutSpeedNames.size() )
1322 {
1323 for( size_t n = 0; n < m_readoutSpeedNames.size(); ++n )
1324 m_indiP_readoutSpeed[m_readoutSpeedNames[n]].setLabel( m_readoutSpeedNameLabels[n] );
1325 }
1326
1327 derived().registerIndiPropertyNew( m_indiP_readoutSpeed, st_newCallBack_stdCamera );
1328
1329 return 0;
1330}
1331
1332template <class derivedT>
1333int stdCamera<derivedT>::createReadoutSpeed( const mx::meta::trueFalseT<0> &f )
1334{
1335 static_cast<void>( f );
1336
1337 return 0;
1338}
1339
1340template <class derivedT>
1341int stdCamera<derivedT>::createVShiftSpeed( const mx::meta::trueFalseT<true> &t )
1342{
1343 static_cast<void>( t );
1344
1345 derived().createStandardIndiSelectionSw(
1346 m_indiP_vShiftSpeed, "vshift_speed", m_vShiftSpeedNames, "Vert. Shift Speed" );
1347
1348 if( m_vShiftSpeedNameLabels.size() == m_vShiftSpeedNames.size() )
1349 {
1350 for( size_t n = 0; n < m_vShiftSpeedNames.size(); ++n )
1351 m_indiP_vShiftSpeed[m_vShiftSpeedNames[n]].setLabel( m_vShiftSpeedNameLabels[n] );
1352 }
1353
1354 derived().registerIndiPropertyNew( m_indiP_vShiftSpeed, st_newCallBack_stdCamera );
1355
1356 return 0;
1357}
1358
1359template <class derivedT>
1360int stdCamera<derivedT>::createVShiftSpeed( const mx::meta::trueFalseT<0> &f )
1361{
1362 static_cast<void>( f );
1363
1364 return 0;
1365}
1366
1367template <class derivedT>
1369{
1370
1371 if( derivedT::c_stdCamera_tempControl )
1372 {
1373 // The min/max/step values should be set in derivedT before this is called.
1374 derived().createStandardIndiNumber(
1375 m_indiP_temp, "temp_ccd", m_minTemp, m_maxTemp, m_stepTemp, "%0.1f", "CCD Temperature", "CCD Temperature" );
1376 m_indiP_temp["current"].set( m_ccdTemp );
1377 m_indiP_temp["target"].set( m_ccdTempSetpt );
1378 if( derived().registerIndiPropertyNew( m_indiP_temp, st_newCallBack_stdCamera ) < 0 )
1379 {
1380#ifndef STDCAMERA_TEST_NOLOG
1381 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1382#endif
1383 return -1;
1384 }
1385
1386 derived().createStandardIndiToggleSw(
1387 m_indiP_tempcont, "temp_controller", "CCD Temperature", "Control On/Off" );
1388 m_indiP_tempcont["toggle"].set( pcf::IndiElement::Off );
1389 if( derived().registerIndiPropertyNew( m_indiP_tempcont, st_newCallBack_stdCamera ) < 0 )
1390 {
1391#ifndef STDCAMERA_TEST_NOLOG
1392 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1393#endif
1394 return -1;
1395 }
1396
1397 derived().createROIndiText(
1398 m_indiP_tempstat, "temp_control", "status", "CCD Temperature", "", "CCD Temperature" );
1399 if( derived().registerIndiPropertyReadOnly( m_indiP_tempstat ) < 0 )
1400 {
1401#ifndef STDCAMERA_TEST_NOLOG
1402 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1403#endif
1404 return -1;
1405 }
1406 }
1407 else if( derivedT::c_stdCamera_temp )
1408 {
1409 derived().createROIndiNumber( m_indiP_temp, "temp_ccd", "CCD Temperature", "CCD Temperature" );
1410 m_indiP_temp.add( pcf::IndiElement( "current" ) );
1411 m_indiP_temp["current"].set( m_ccdTemp );
1412 if( derived().registerIndiPropertyReadOnly( m_indiP_temp ) < 0 )
1413 {
1414#ifndef STDCAMERA_TEST_NOLOG
1415 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1416#endif
1417 return -1;
1418 }
1419 }
1420
1421 if( derivedT::c_stdCamera_readoutSpeed )
1422 {
1423 mx::meta::trueFalseT<derivedT::c_stdCamera_readoutSpeed> tf;
1424 if( createReadoutSpeed( tf ) < 0 )
1425 {
1426#ifndef STDCAMERA_TEST_NOLOG
1427 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1428#endif
1429 return -1;
1430 }
1431 }
1432
1433 if( derivedT::c_stdCamera_vShiftSpeed )
1434 {
1435 mx::meta::trueFalseT<derivedT::c_stdCamera_vShiftSpeed> tf;
1436 if( createVShiftSpeed( tf ) < 0 )
1437 {
1438#ifndef STDCAMERA_TEST_NOLOG
1439 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1440#endif
1441 return -1;
1442 }
1443 }
1444
1445 if( derivedT::c_stdCamera_emGain )
1446 {
1447 derived().createStandardIndiNumber( m_indiP_emGain, "emgain", 0, 1000, 1, "%0.3f" );
1448 if( derived().registerIndiPropertyNew( m_indiP_emGain, st_newCallBack_stdCamera ) < 0 )
1449 {
1450#ifndef STDCAMERA_TEST_NOLOG
1451 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1452#endif
1453 return -1;
1454 }
1455 }
1456
1457 if( derivedT::c_stdCamera_exptimeCtrl )
1458 {
1459 derived().createStandardIndiNumber(
1460 m_indiP_exptime, "exptime", m_minExpTime, m_maxExpTime, m_stepExpTime, "%0.3f" );
1461 if( derived().registerIndiPropertyNew( m_indiP_exptime, st_newCallBack_stdCamera ) < 0 )
1462 {
1463#ifndef STDCAMERA_TEST_NOLOG
1464 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1465#endif
1466 return -1;
1467 }
1468 }
1469
1470 if( derivedT::c_stdCamera_fpsCtrl )
1471 {
1472 derived().createStandardIndiNumber( m_indiP_fps, "fps", m_minFPS, m_maxFPS, m_stepFPS, "%0.2f" );
1473 if( derived().registerIndiPropertyNew( m_indiP_fps, st_newCallBack_stdCamera ) < 0 )
1474 {
1475#ifndef STDCAMERA_TEST_NOLOG
1476 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1477#endif
1478 return -1;
1479 }
1480 }
1481 else if( derivedT::c_stdCamera_fps )
1482 {
1483 derived().createROIndiNumber( m_indiP_fps, "fps" );
1484 m_indiP_fps.add( pcf::IndiElement( "current" ) );
1485 m_indiP_fps["current"].setMin( m_minFPS );
1486 m_indiP_fps["current"].setMax( m_maxFPS );
1487 m_indiP_fps["current"].setStep( m_stepFPS );
1488 m_indiP_fps["current"].setFormat( "%0.2f" );
1489
1490 if( derived().registerIndiPropertyReadOnly( m_indiP_fps ) < 0 )
1491 {
1492#ifndef STDCAMERA_TEST_NOLOG
1493 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1494#endif
1495 return -1;
1496 }
1497 }
1498
1499 if( derivedT::c_stdCamera_synchro )
1500 {
1501 derived().createStandardIndiToggleSw( m_indiP_synchro, "synchro", "Synchronization", "Synchronization" );
1502 if( derived().registerIndiPropertyNew( m_indiP_synchro, st_newCallBack_stdCamera ) < 0 )
1503 {
1504#ifndef STDCAMERA_TEST_NOLOG
1505 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1506#endif
1507 return -1;
1508 }
1509 }
1510
1511 if( derivedT::c_stdCamera_usesModes )
1512 {
1513 std::vector<std::string> modeNames;
1514 for( auto it = m_cameraModes.begin(); it != m_cameraModes.end(); ++it )
1515 {
1516 modeNames.push_back( it->first );
1517 }
1518
1519 if( derived().createStandardIndiSelectionSw( m_indiP_mode, "mode", modeNames ) < 0 )
1520 {
1521 derivedT::template log<software_critical>( { __FILE__, __LINE__ } );
1522 return -1;
1523 }
1524 if( derived().registerIndiPropertyNew( m_indiP_mode, st_newCallBack_stdCamera ) < 0 )
1525 {
1526#ifndef STDCAMERA_TEST_NOLOG
1527 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1528#endif
1529 return -1;
1530 }
1531 }
1532
1533 derived().createStandardIndiRequestSw( m_indiP_reconfig, "reconfigure" );
1534 if( derived().registerIndiPropertyNew( m_indiP_reconfig, st_newCallBack_stdCamera ) < 0 )
1535 {
1536#ifndef STDCAMERA_TEST_NOLOG
1537 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1538#endif
1539 return -1;
1540 }
1541
1542 if( derivedT::c_stdCamera_usesROI )
1543 {
1544 // The min/max/step values should be set in derivedT before this is called.
1545 derived().createStandardIndiNumber( m_indiP_roi_x, "roi_region_x", m_minROIx, m_maxROIx, m_stepROIx, "%0.1f" );
1546 if( derived().registerIndiPropertyNew( m_indiP_roi_x, st_newCallBack_stdCamera ) < 0 )
1547 {
1548#ifndef STDCAMERA_TEST_NOLOG
1549 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1550#endif
1551 return -1;
1552 }
1553
1554 derived().createStandardIndiNumber( m_indiP_roi_y, "roi_region_y", m_minROIy, m_maxROIy, m_stepROIy, "%0.1f" );
1555 if( derived().registerIndiPropertyNew( m_indiP_roi_y, st_newCallBack_stdCamera ) < 0 )
1556 {
1557#ifndef STDCAMERA_TEST_NOLOG
1558 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1559#endif
1560 return -1;
1561 }
1562
1563 derived().createStandardIndiNumber(
1564 m_indiP_roi_w, "roi_region_w", m_minROIWidth, m_maxROIWidth, m_stepROIWidth, "%d" );
1565 if( derived().registerIndiPropertyNew( m_indiP_roi_w, st_newCallBack_stdCamera ) < 0 )
1566 {
1567#ifndef STDCAMERA_TEST_NOLOG
1568 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1569#endif
1570 return -1;
1571 }
1572
1573 derived().createStandardIndiNumber(
1574 m_indiP_roi_h, "roi_region_h", m_minROIHeight, m_maxROIHeight, m_stepROIHeight, "%d" );
1575 if( derived().registerIndiPropertyNew( m_indiP_roi_h, st_newCallBack_stdCamera ) < 0 )
1576 {
1577#ifndef STDCAMERA_TEST_NOLOG
1578 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1579#endif
1580 return -1;
1581 }
1582
1583 derived().createStandardIndiNumber(
1584 m_indiP_roi_bin_x, "roi_region_bin_x", m_minROIBinning_x, m_maxROIBinning_x, m_stepROIBinning_x, "%f" );
1585 if( derived().registerIndiPropertyNew( m_indiP_roi_bin_x, st_newCallBack_stdCamera ) < 0 )
1586 {
1587#ifndef STDCAMERA_TEST_NOLOG
1588 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1589#endif
1590 return -1;
1591 }
1592
1593 derived().createStandardIndiNumber(
1594 m_indiP_roi_bin_y, "roi_region_bin_y", m_minROIBinning_y, m_maxROIBinning_y, m_stepROIBinning_y, "%f" );
1595 if( derived().registerIndiPropertyNew( m_indiP_roi_bin_y, st_newCallBack_stdCamera ) < 0 )
1596 {
1597#ifndef STDCAMERA_TEST_NOLOG
1598 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1599#endif
1600 return -1;
1601 }
1602
1603 derived().createROIndiNumber( m_indiP_fullROI, "roi_full_region" );
1604 m_indiP_fullROI.add( pcf::IndiElement( "x" ) );
1605 m_indiP_fullROI["x"] = 0;
1606 m_indiP_fullROI.add( pcf::IndiElement( "y" ) );
1607 m_indiP_fullROI["y"] = 0;
1608 m_indiP_fullROI.add( pcf::IndiElement( "w" ) );
1609 m_indiP_fullROI["w"] = 0;
1610 m_indiP_fullROI.add( pcf::IndiElement( "h" ) );
1611 m_indiP_fullROI["h"] = 0;
1612 if( derived().registerIndiPropertyReadOnly( m_indiP_fullROI ) < 0 )
1613 {
1614#ifndef STDCAMERA_TEST_NOLOG
1615 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1616#endif
1617 return -1;
1618 }
1619
1620 derived().createStandardIndiRequestSw( m_indiP_roi_check, "roi_region_check" );
1621 if( derived().registerIndiPropertyNew( m_indiP_roi_check, st_newCallBack_stdCamera ) < 0 )
1622 {
1623#ifndef STDCAMERA_TEST_NOLOG
1624 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1625#endif
1626 return -1;
1627 }
1628
1629 derived().createStandardIndiRequestSw( m_indiP_roi_set, "roi_set" );
1630 if( derived().registerIndiPropertyNew( m_indiP_roi_set, st_newCallBack_stdCamera ) < 0 )
1631 {
1632#ifndef STDCAMERA_TEST_NOLOG
1633 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1634#endif
1635 return -1;
1636 }
1637
1638 derived().createStandardIndiRequestSw( m_indiP_roi_full, "roi_set_full" );
1639 if( derived().registerIndiPropertyNew( m_indiP_roi_full, st_newCallBack_stdCamera ) < 0 )
1640 {
1641#ifndef STDCAMERA_TEST_NOLOG
1642 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1643#endif
1644 return -1;
1645 }
1646
1647 derived().createStandardIndiRequestSw( m_indiP_roi_fullbin, "roi_set_full_bin" );
1648 if( derived().registerIndiPropertyNew( m_indiP_roi_fullbin, st_newCallBack_stdCamera ) < 0 )
1649 {
1650#ifndef STDCAMERA_TEST_NOLOG
1651 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1652#endif
1653 return -1;
1654 }
1655
1656 derived().createStandardIndiRequestSw( m_indiP_roi_loadlast, "roi_load_last" );
1657 if( derived().registerIndiPropertyNew( m_indiP_roi_loadlast, st_newCallBack_stdCamera ) < 0 )
1658 {
1659#ifndef STDCAMERA_TEST_NOLOG
1660 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1661#endif
1662 return -1;
1663 }
1664
1665 derived().createStandardIndiRequestSw( m_indiP_roi_last, "roi_set_last" );
1666 if( derived().registerIndiPropertyNew( m_indiP_roi_last, st_newCallBack_stdCamera ) < 0 )
1667 {
1668#ifndef STDCAMERA_TEST_NOLOG
1669 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1670#endif
1671 return -1;
1672 }
1673
1674 derived().createStandardIndiRequestSw( m_indiP_roi_default, "roi_set_default" );
1675 if( derived().registerIndiPropertyNew( m_indiP_roi_default, st_newCallBack_stdCamera ) < 0 )
1676 {
1677#ifndef STDCAMERA_TEST_NOLOG
1678 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1679#endif
1680 return -1;
1681 }
1682 }
1683
1684 if( derivedT::c_stdCamera_cropMode )
1685 {
1686 derived().createStandardIndiToggleSw( m_indiP_cropMode, "roi_crop_mode", "Crop Mode", "Crop Mode" );
1687 if( derived().registerIndiPropertyNew( m_indiP_cropMode, st_newCallBack_stdCamera ) < 0 )
1688 {
1689#ifndef STDCAMERA_TEST_NOLOG
1690 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1691#endif
1692 return -1;
1693 }
1694 }
1695
1696 // Set up INDI for shutter
1697 if( derivedT::c_stdCamera_hasShutter )
1698 {
1699 derived().createROIndiText(
1700 m_indiP_shutterStatus, "shutter_status", "status", "Shutter Status", "Shutter", "Status" );
1701 m_indiP_shutterStatus["status"] = m_shutterStatus;
1702 if( derived().registerIndiPropertyReadOnly( m_indiP_shutterStatus ) < 0 )
1703 {
1704#ifndef STDCAMERA_TEST_NOLOG
1705 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1706#endif
1707 return -1;
1708 }
1709
1710 derived().createStandardIndiToggleSw( m_indiP_shutter, "shutter", "Shutter", "Shutter" );
1711 if( derived().registerIndiPropertyNew( m_indiP_shutter, st_newCallBack_stdCamera ) < 0 )
1712 {
1713#ifndef STDCAMERA_TEST_NOLOG
1714 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1715#endif
1716 return -1;
1717 }
1718 }
1719
1720 if( derivedT::c_stdCamera_usesStateString )
1721 {
1722 derived().createROIndiText( m_indiP_stateString, "state_string", "current", "State String", "State", "String" );
1723 m_indiP_stateString.add( pcf::IndiElement( "valid" ) );
1724 m_indiP_stateString["valid"] = "no";
1725 if( derived().registerIndiPropertyReadOnly( m_indiP_stateString ) < 0 )
1726 {
1727#ifndef STDCAMERA_TEST_NOLOG
1728 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
1729#endif
1730 return -1;
1731 }
1732 }
1733
1734 return 0;
1735} // int stdCamera<derivedT>::appStartup()
1736
1737template <class derivedT>
1739{
1740 try
1741 {
1742
1743 if( derived().state() == stateCodes::POWERON )
1744 {
1745 if( derived().powerOnWaitElapsed() )
1746 {
1747 derived().state( stateCodes::NOTCONNECTED );
1748
1749 m_currentROI.x = m_default_x;
1750 m_currentROI.y = m_default_y;
1751 m_currentROI.w = m_default_w;
1752 m_currentROI.h = m_default_h;
1753 m_currentROI.bin_x = m_default_bin_x;
1754 m_currentROI.bin_y = m_default_bin_y;
1755
1756 m_nextROI.x = m_default_x;
1757 m_nextROI.y = m_default_y;
1758 m_nextROI.w = m_default_w;
1759 m_nextROI.h = m_default_h;
1760 m_nextROI.bin_x = m_default_bin_x;
1761 m_nextROI.bin_y = m_default_bin_y;
1762
1763 // Set power-on defaults
1764 derived().powerOnDefaults();
1765
1766 if( derivedT::c_stdCamera_tempControl )
1767 {
1768 // then set startupTemp if configured
1769 if( m_startupTemp > -999 )
1770 m_ccdTempSetpt = m_startupTemp;
1771 derived().updateIfChanged( m_indiP_temp, "target", m_ccdTempSetpt, INDI_IDLE );
1772 }
1773
1774 if( derivedT::c_stdCamera_usesROI )
1775 {
1776 // m_currentROI should be set to default/startup values in derivedT::powerOnDefaults
1777 m_nextROI.x = m_currentROI.x;
1778 m_nextROI.y = m_currentROI.y;
1779 m_nextROI.w = m_currentROI.w;
1780 m_nextROI.h = m_currentROI.h;
1781 m_nextROI.bin_x = m_currentROI.bin_x;
1782 m_nextROI.bin_y = m_currentROI.bin_y;
1783
1784 derived().updateIfChanged( m_indiP_roi_x, "current", m_currentROI.x, INDI_IDLE );
1785 derived().updateIfChanged( m_indiP_roi_x, "target", m_nextROI.x, INDI_IDLE );
1786
1787 derived().updateIfChanged( m_indiP_roi_y, "current", m_currentROI.y, INDI_IDLE );
1788 derived().updateIfChanged( m_indiP_roi_y, "target", m_nextROI.y, INDI_IDLE );
1789
1790 derived().updateIfChanged( m_indiP_roi_w, "current", m_currentROI.w, INDI_IDLE );
1791 derived().updateIfChanged( m_indiP_roi_w, "target", m_nextROI.w, INDI_IDLE );
1792
1793 derived().updateIfChanged( m_indiP_roi_h, "current", m_currentROI.h, INDI_IDLE );
1794 derived().updateIfChanged( m_indiP_roi_h, "target", m_nextROI.h, INDI_IDLE );
1795
1796 derived().updateIfChanged( m_indiP_roi_bin_x, "current", m_currentROI.bin_x, INDI_IDLE );
1797 derived().updateIfChanged( m_indiP_roi_bin_x, "target", m_nextROI.bin_x, INDI_IDLE );
1798
1799 derived().updateIfChanged( m_indiP_roi_bin_y, "current", m_currentROI.bin_y, INDI_IDLE );
1800 derived().updateIfChanged( m_indiP_roi_bin_y, "target", m_nextROI.bin_y, INDI_IDLE );
1801 }
1802
1803 if( derivedT::c_stdCamera_hasShutter )
1804 {
1805 if( m_shutterStatus == "OPERATING" )
1806 {
1807 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_BUSY );
1808 }
1809 if( m_shutterStatus == "POWERON" || m_shutterStatus == "READY" )
1810 {
1811 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_OK );
1812 }
1813 else
1814 {
1815 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_IDLE );
1816 }
1817
1818 if( m_shutterState == 1 )
1819 {
1820 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::On, INDI_OK );
1821 }
1822 else
1823 {
1824 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1825 }
1826 }
1827
1828 return 0;
1829 }
1830 else
1831 {
1832 return 0;
1833 }
1834 }
1835 else if( derived().state() == stateCodes::READY || derived().state() == stateCodes::OPERATING )
1836 {
1837 if( derivedT::c_stdCamera_usesROI )
1838 {
1839 derived().updateIfChanged( m_indiP_roi_x, "current", m_currentROI.x, INDI_IDLE );
1840 derived().updateIfChanged( m_indiP_roi_x, "target", m_nextROI.x, INDI_IDLE );
1841
1842 derived().updateIfChanged( m_indiP_roi_y, "current", m_currentROI.y, INDI_IDLE );
1843 derived().updateIfChanged( m_indiP_roi_y, "target", m_nextROI.y, INDI_IDLE );
1844
1845 derived().updateIfChanged( m_indiP_roi_w, "current", m_currentROI.w, INDI_IDLE );
1846 derived().updateIfChanged( m_indiP_roi_w, "target", m_nextROI.w, INDI_IDLE );
1847
1848 derived().updateIfChanged( m_indiP_roi_h, "current", m_currentROI.h, INDI_IDLE );
1849 derived().updateIfChanged( m_indiP_roi_h, "target", m_nextROI.h, INDI_IDLE );
1850
1851 derived().updateIfChanged( m_indiP_roi_bin_x, "current", m_currentROI.bin_x, INDI_IDLE );
1852 derived().updateIfChanged( m_indiP_roi_bin_x, "target", m_nextROI.bin_x, INDI_IDLE );
1853
1854 derived().updateIfChanged( m_indiP_roi_bin_y, "current", m_currentROI.bin_y, INDI_IDLE );
1855 derived().updateIfChanged( m_indiP_roi_bin_y, "target", m_nextROI.bin_y, INDI_IDLE );
1856 }
1857 }
1858
1859 return 0;
1860 }
1861 catch( const std::exception &e )
1862 {
1863 return derivedT::template log<software_error, -1>(
1864 { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
1865 }
1866}
1867
1868template <class derivedT>
1870{
1871 if( !derived().m_indiDriver )
1872 return 0;
1873
1874 if( derivedT::c_stdCamera_usesModes )
1875 {
1876 for( auto it = m_cameraModes.begin(); it != m_cameraModes.end(); ++it )
1877 {
1878 derived().updateSwitchIfChanged( m_indiP_mode, it->first, pcf::IndiElement::Off, INDI_IDLE );
1879 }
1880 }
1881
1882 if( derivedT::c_stdCamera_usesROI )
1883 {
1884 // Blank these values
1885 indi::updateIfChanged( m_indiP_roi_x, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1886 indi::updateIfChanged( m_indiP_roi_x, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1887
1888 indi::updateIfChanged( m_indiP_roi_y, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1889 indi::updateIfChanged( m_indiP_roi_y, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1890
1891 indi::updateIfChanged( m_indiP_roi_w, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1892 indi::updateIfChanged( m_indiP_roi_w, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1893
1894 indi::updateIfChanged( m_indiP_roi_h, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1895 indi::updateIfChanged( m_indiP_roi_h, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1896
1897 indi::updateIfChanged( m_indiP_roi_bin_x, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1898 indi::updateIfChanged( m_indiP_roi_bin_x, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1899
1900 indi::updateIfChanged( m_indiP_roi_bin_y, "current", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1901 indi::updateIfChanged( m_indiP_roi_bin_y, "target", std::string( "" ), derived().m_indiDriver, INDI_IDLE );
1902
1903 // But we also set these to their defaults so that when we power up it's all good
1904 m_currentROI.x = m_default_x;
1905 m_currentROI.y = m_default_y;
1906 m_currentROI.w = m_default_w;
1907 m_currentROI.h = m_default_h;
1908 m_currentROI.bin_x = m_default_bin_x;
1909 m_currentROI.bin_y = m_default_bin_y;
1910
1911 m_nextROI.x = m_default_x;
1912 m_nextROI.y = m_default_y;
1913 m_nextROI.w = m_default_w;
1914 m_nextROI.h = m_default_h;
1915 m_nextROI.bin_x = m_default_bin_x;
1916 m_nextROI.bin_y = m_default_bin_y;
1917 }
1918
1919 // Shutters can be independent pieces of hardware . . .
1920 if( derivedT::c_stdCamera_hasShutter )
1921 {
1922 if( m_shutterStatus == "OPERATING" )
1923 {
1924 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_BUSY );
1925 }
1926 if( m_shutterStatus == "POWERON" || m_shutterStatus == "READY" )
1927 {
1928 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_OK );
1929 }
1930 else
1931 {
1932 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_IDLE );
1933 }
1934
1935 if( m_shutterState == 0 )
1936 {
1937 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::On, INDI_OK );
1938 }
1939 else
1940 {
1941 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1942 }
1943 }
1944
1945 return 0;
1946}
1947
1948template <class derivedT>
1950{
1951 // Shutters can be independent pieces of hardware . . .
1952 if( derivedT::c_stdCamera_hasShutter )
1953 {
1954 if( m_shutterStatus == "OPERATING" )
1955 {
1956 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_BUSY );
1957 }
1958 if( m_shutterStatus == "POWERON" || m_shutterStatus == "READY" )
1959 {
1960 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_OK );
1961 }
1962 else
1963 {
1964 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_IDLE );
1965 }
1966
1967 if( m_shutterState == 0 )
1968 {
1969 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::On, INDI_OK );
1970 }
1971 else
1972 {
1973 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1974 }
1975 }
1976
1977 return 0;
1978}
1979
1980template <class derivedT>
1982{
1983 return 0;
1984}
1985
1986template <class derivedT>
1987int stdCamera<derivedT>::st_newCallBack_stdCamera( void *app, const pcf::IndiProperty &ipRecv )
1988{
1989 derivedT *_app = static_cast<derivedT *>( app );
1990 return _app->newCallBack_stdCamera( ipRecv );
1991}
1992
1993template <class derivedT>
1995{
1996
1997 if( ipRecv.getDevice() != derived().configName() )
1998 {
1999#ifndef XWCTEST_INDI_CALLBACK_VALIDATION
2000 derivedT::template log<software_error>( { __FILE__, __LINE__, "unknown INDI property" } );
2001#endif
2002
2003 return -1;
2004 }
2005
2006 std::string name = ipRecv.getName();
2007
2008 if( name == "reconfigure" )
2009 return newCallBack_reconfigure( ipRecv );
2010 else if( derivedT::c_stdCamera_temp && name == "temp_ccd" )
2011 return newCallBack_temp( ipRecv );
2012 else if( derivedT::c_stdCamera_tempControl && name == "temp_ccd" )
2013 return newCallBack_temp( ipRecv );
2014 else if( derivedT::c_stdCamera_tempControl && name == "temp_controller" )
2015 return newCallBack_temp_controller( ipRecv );
2016 else if( derivedT::c_stdCamera_readoutSpeed && name == "readout_speed" )
2017 return newCallBack_readoutSpeed( ipRecv );
2018 else if( derivedT::c_stdCamera_vShiftSpeed && name == "vshift_speed" )
2019 return newCallBack_vShiftSpeed( ipRecv );
2020 else if( derivedT::c_stdCamera_emGain && name == "emgain" )
2021 return newCallBack_emgain( ipRecv );
2022 else if( derivedT::c_stdCamera_exptimeCtrl && name == "exptime" )
2023 return newCallBack_exptime( ipRecv );
2024 else if( derivedT::c_stdCamera_fpsCtrl && name == "fps" )
2025 return newCallBack_fps( ipRecv );
2026 else if( derivedT::c_stdCamera_synchro && name == "synchro" )
2027 return newCallBack_synchro( ipRecv );
2028 else if( derivedT::c_stdCamera_usesModes && name == "mode" )
2029 return newCallBack_mode( ipRecv );
2030 else if( derivedT::c_stdCamera_cropMode && name == "roi_crop_mode" )
2031 return newCallBack_cropMode( ipRecv );
2032 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_x" )
2033 return newCallBack_roi_x( ipRecv );
2034 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_y" )
2035 return newCallBack_roi_y( ipRecv );
2036 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_w" )
2037 return newCallBack_roi_w( ipRecv );
2038 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_h" )
2039 return newCallBack_roi_h( ipRecv );
2040 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_bin_x" )
2041 return newCallBack_roi_bin_x( ipRecv );
2042 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_bin_y" )
2043 return newCallBack_roi_bin_y( ipRecv );
2044 else if( derivedT::c_stdCamera_usesROI && name == "roi_region_check" )
2045 return newCallBack_roi_check( ipRecv );
2046 else if( derivedT::c_stdCamera_usesROI && name == "roi_set" )
2047 return newCallBack_roi_set( ipRecv );
2048 else if( derivedT::c_stdCamera_usesROI && name == "roi_set_full" )
2049 return newCallBack_roi_full( ipRecv );
2050 else if( derivedT::c_stdCamera_usesROI && name == "roi_set_full_bin" )
2051 return newCallBack_roi_fullbin( ipRecv );
2052 else if( derivedT::c_stdCamera_usesROI && name == "roi_load_last" )
2053 return newCallBack_roi_loadlast( ipRecv );
2054 else if( derivedT::c_stdCamera_usesROI && name == "roi_set_last" )
2055 return newCallBack_roi_last( ipRecv );
2056 else if( derivedT::c_stdCamera_usesROI && name == "roi_set_default" )
2057 return newCallBack_roi_default( ipRecv );
2058 else if( derivedT::c_stdCamera_hasShutter && name == "shutter" )
2059 return newCallBack_shutter( ipRecv );
2060
2061#ifndef XWCTEST_INDI_CALLBACK_VALIDATION
2062 derivedT::template log<software_error>( { __FILE__, __LINE__, "unknown INDI property" } );
2063#endif
2064
2065 return -1;
2066}
2067
2068template <class derivedT>
2069int stdCamera<derivedT>::setTempSetPt( const mx::meta::trueFalseT<true> &t )
2070{
2071 static_cast<void>( t );
2072 return derived().setTempSetPt();
2073}
2074
2075template <class derivedT>
2076int stdCamera<derivedT>::setTempSetPt( const mx::meta::trueFalseT<false> &f )
2077{
2078 static_cast<void>( f );
2079 return 0;
2080}
2081
2082template <class derivedT>
2083int stdCamera<derivedT>::newCallBack_temp( const pcf::IndiProperty &ipRecv )
2084{
2085 if( derivedT::c_stdCamera_tempControl )
2086 {
2087#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2088 return 0;
2089#endif
2090
2091 float target;
2092
2093 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2094
2095 if( derived().indiTargetUpdate( m_indiP_temp, target, ipRecv, true ) < 0 )
2096 {
2097 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2098 return -1;
2099 }
2100
2101 m_ccdTempSetpt = target;
2102
2103 mx::meta::trueFalseT<derivedT::c_stdCamera_tempControl> tf;
2104 return setTempSetPt( tf );
2105 }
2106 else
2107 {
2108 return 0;
2109 }
2110}
2111
2112template <class derivedT>
2113int stdCamera<derivedT>::setTempControl( const mx::meta::trueFalseT<true> &t )
2114{
2115 static_cast<void>( t );
2116 return derived().setTempControl();
2117}
2118
2119template <class derivedT>
2120int stdCamera<derivedT>::setTempControl( const mx::meta::trueFalseT<false> &f )
2121{
2122 static_cast<void>( f );
2123 return 0;
2124}
2125
2126template <class derivedT>
2128{
2129 if( derivedT::c_stdCamera_tempControl )
2130 {
2131#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2132 return 0;
2133#endif
2134
2135 if( !ipRecv.find( "toggle" ) )
2136 return 0;
2137
2138 m_tempControlStatusSet = false;
2139
2140 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2141
2142 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
2143 {
2144 m_tempControlStatusSet = true;
2145 derived().updateSwitchIfChanged( m_indiP_tempcont, "toggle", pcf::IndiElement::On, INDI_BUSY );
2146 }
2147 else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
2148 {
2149 m_tempControlStatusSet = false;
2150 derived().updateSwitchIfChanged( m_indiP_tempcont, "toggle", pcf::IndiElement::Off, INDI_BUSY );
2151 }
2152
2153 mx::meta::trueFalseT<derivedT::c_stdCamera_emGain> tf;
2154 return setTempControl( tf );
2155 }
2156 else
2157 {
2158 return 0;
2159 }
2160}
2161
2162template <class derivedT>
2163int stdCamera<derivedT>::setReadoutSpeed( const mx::meta::trueFalseT<true> &t )
2164{
2165 static_cast<void>( t );
2166 return derived().setReadoutSpeed();
2167}
2168
2169template <class derivedT>
2170int stdCamera<derivedT>::setReadoutSpeed( const mx::meta::trueFalseT<false> &f )
2171{
2172 static_cast<void>( f );
2173 return 0;
2174}
2175
2176template <class derivedT>
2178{
2179 if( derivedT::c_stdCamera_readoutSpeed )
2180 {
2181#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2182 return 0;
2183#endif
2184
2185 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2186
2187 std::string newspeed;
2188
2189 for( size_t i = 0; i < m_readoutSpeedNames.size(); ++i )
2190 {
2191 if( !ipRecv.find( m_readoutSpeedNames[i] ) )
2192 continue;
2193
2194 if( ipRecv[m_readoutSpeedNames[i]].getSwitchState() == pcf::IndiElement::On )
2195 {
2196 if( newspeed != "" )
2197 {
2198 derivedT::template log<text_log>( "More than one readout speed selected", logPrio::LOG_ERROR );
2199 return -1;
2200 }
2201
2202 newspeed = m_readoutSpeedNames[i];
2203 }
2204 }
2205
2206 if( newspeed == "" )
2207 {
2208 // We do a reset
2209 m_readoutSpeedNameSet = m_readoutSpeedName;
2210 }
2211 else
2212 {
2213 m_readoutSpeedNameSet = newspeed;
2214 }
2215
2216 mx::meta::trueFalseT<derivedT::c_stdCamera_readoutSpeed> tf;
2217 return setReadoutSpeed( tf );
2218 }
2219
2220 return 0;
2221}
2222
2223template <class derivedT>
2224int stdCamera<derivedT>::setVShiftSpeed( const mx::meta::trueFalseT<true> &t )
2225{
2226 static_cast<void>( t );
2227 return derived().setVShiftSpeed();
2228}
2229
2230template <class derivedT>
2231int stdCamera<derivedT>::setVShiftSpeed( const mx::meta::trueFalseT<false> &f )
2232{
2233 static_cast<void>( f );
2234 return 0;
2235}
2236
2237template <class derivedT>
2239{
2240 if( derivedT::c_stdCamera_vShiftSpeed )
2241 {
2242#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2243 return 0;
2244#endif
2245
2246 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2247
2248 std::string newspeed;
2249
2250 for( size_t i = 0; i < m_vShiftSpeedNames.size(); ++i )
2251 {
2252 if( !ipRecv.find( m_vShiftSpeedNames[i] ) )
2253 continue;
2254
2255 if( ipRecv[m_vShiftSpeedNames[i]].getSwitchState() == pcf::IndiElement::On )
2256 {
2257 if( newspeed != "" )
2258 {
2259 derivedT::template log<text_log>( "More than one vShift speed selected", logPrio::LOG_ERROR );
2260 return -1;
2261 }
2262
2263 newspeed = m_vShiftSpeedNames[i];
2264 }
2265 }
2266
2267 if( newspeed == "" )
2268 {
2269 // We do a reset
2270 m_vShiftSpeedNameSet = m_vShiftSpeedName;
2271 }
2272 else
2273 {
2274 m_vShiftSpeedNameSet = newspeed;
2275 }
2276
2277 mx::meta::trueFalseT<derivedT::c_stdCamera_vShiftSpeed> tf;
2278 return setVShiftSpeed( tf );
2279 }
2280
2281 return 0;
2282}
2283
2284template <class derivedT>
2285int stdCamera<derivedT>::setEMGain( const mx::meta::trueFalseT<true> &t )
2286{
2287 static_cast<void>( t );
2288 return derived().setEMGain();
2289}
2290
2291template <class derivedT>
2292int stdCamera<derivedT>::setEMGain( const mx::meta::trueFalseT<false> &f )
2293{
2294 static_cast<void>( f );
2295 return 0;
2296}
2297
2298template <class derivedT>
2300{
2301 if( derivedT::c_stdCamera_emGain )
2302 {
2303#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2304 return 0;
2305#endif
2306
2307 float target;
2308
2309 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2310
2311 if( derived().indiTargetUpdate( m_indiP_emGain, target, ipRecv, true ) < 0 )
2312 {
2313 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2314 return -1;
2315 }
2316
2317 m_emGainSet = target;
2318
2319 mx::meta::trueFalseT<derivedT::c_stdCamera_emGain> tf;
2320 return setEMGain( tf );
2321 }
2322
2323 return 0;
2324}
2325
2326template <class derivedT>
2327int stdCamera<derivedT>::setExpTime( const mx::meta::trueFalseT<true> &t )
2328{
2329 static_cast<void>( t );
2330 return derived().setExpTime();
2331}
2332
2333template <class derivedT>
2334int stdCamera<derivedT>::setExpTime( const mx::meta::trueFalseT<false> &f )
2335{
2336 static_cast<void>( f );
2337 return 0;
2338}
2339
2340template <class derivedT>
2342{
2343 if( derivedT::c_stdCamera_exptimeCtrl )
2344 {
2345#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2346 return 0;
2347#endif
2348
2349 float target;
2350
2351 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2352
2353 if( derived().indiTargetUpdate( m_indiP_exptime, target, ipRecv, true ) < 0 )
2354 {
2355 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2356 return -1;
2357 }
2358
2359 m_expTimeSet = target;
2360
2361 mx::meta::trueFalseT<derivedT::c_stdCamera_exptimeCtrl> tf;
2362 return setExpTime( tf );
2363 }
2364
2365 return 0;
2366}
2367
2368template <class derivedT>
2369int stdCamera<derivedT>::setFPS( const mx::meta::trueFalseT<true> &t )
2370{
2371 static_cast<void>( t );
2372 return derived().setFPS();
2373}
2374
2375template <class derivedT>
2376int stdCamera<derivedT>::setFPS( const mx::meta::trueFalseT<false> &f )
2377{
2378 static_cast<void>( f );
2379 return 0;
2380}
2381
2382template <class derivedT>
2383int stdCamera<derivedT>::newCallBack_fps( const pcf::IndiProperty &ipRecv )
2384{
2385 if( derivedT::c_stdCamera_fpsCtrl )
2386 {
2387#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2388 return 0;
2389#endif
2390
2391 float target;
2392
2393 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2394
2395 if( derived().indiTargetUpdate( m_indiP_fps, target, ipRecv, true ) < 0 )
2396 {
2397 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2398 return -1;
2399 }
2400
2401 m_fpsSet = target;
2402
2403 mx::meta::trueFalseT<derivedT::c_stdCamera_fpsCtrl> tf;
2404 return setFPS( tf );
2405 }
2406
2407 return 0;
2408}
2409
2410template <class derivedT>
2411int stdCamera<derivedT>::setSynchro( const mx::meta::trueFalseT<true> &t )
2412{
2413 static_cast<void>( t );
2414 return derived().setSynchro();
2415}
2416
2417template <class derivedT>
2418int stdCamera<derivedT>::setSynchro( const mx::meta::trueFalseT<false> &f )
2419{
2420 static_cast<void>( f );
2421 return 0;
2422}
2423
2424template <class derivedT>
2426{
2427 if( derivedT::c_stdCamera_synchro )
2428 {
2429#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2430 return 0;
2431#endif
2432
2433 if( !ipRecv.find( "toggle" ) )
2434 return 0;
2435
2436 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
2437 {
2438 m_synchroSet = false;
2439 }
2440
2441 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
2442 {
2443 m_synchroSet = true;
2444 }
2445
2446 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2447
2448 mx::meta::trueFalseT<derivedT::c_stdCamera_synchro> tf;
2449 return setSynchro( tf );
2450 }
2451
2452 return 0;
2453}
2454
2455template <class derivedT>
2456int stdCamera<derivedT>::newCallBack_mode( const pcf::IndiProperty &ipRecv )
2457{
2458 if( derivedT::c_stdCamera_usesModes )
2459 {
2460#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2461 return 0;
2462#endif
2463
2464 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2465
2466 if( ipRecv.getName() != m_indiP_mode.getName() )
2467 {
2468 derivedT::template log<software_error>( { __FILE__, __LINE__, "invalid indi property received" } );
2469 return -1;
2470 }
2471
2472 // look for selected mode switch which matches a known mode. Make sure only one is selected.
2473 std::string newName = "";
2474 for( auto it = m_cameraModes.begin(); it != m_cameraModes.end(); ++it )
2475 {
2476 if( !ipRecv.find( it->first ) )
2477 continue;
2478
2479 if( ipRecv[it->first].getSwitchState() == pcf::IndiElement::On )
2480 {
2481 if( newName != "" )
2482 {
2483 derivedT::template log<text_log>( "More than one camera mode selected", logPrio::LOG_ERROR );
2484 return -1;
2485 }
2486
2487 newName = it->first;
2488 }
2489 }
2490
2491 if( newName == "" )
2492 {
2493 return 0;
2494 }
2495
2496 // Now signal the f.g. thread to reconfigure
2497 m_nextMode = newName;
2498 derived().m_reconfig = true;
2499
2500 return 0;
2501 }
2502 else
2503 {
2504 return 0;
2505 }
2506}
2507
2508template <class derivedT>
2510{
2511#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2512 return 0;
2513#endif
2514
2515 if( !ipRecv.find( "request" ) )
2516 return 0;
2517
2518 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2519 {
2520 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2521
2523 m_indiP_reconfig, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2524
2525 m_nextMode = m_modeName;
2526 derived().m_reconfig = true;
2527 return 0;
2528 }
2529
2530 return 0;
2531}
2532
2533template <class derivedT>
2534int stdCamera<derivedT>::setCropMode( const mx::meta::trueFalseT<true> &t )
2535{
2536 static_cast<void>( t );
2537 return derived().setCropMode();
2538}
2539
2540template <class derivedT>
2541int stdCamera<derivedT>::setCropMode( const mx::meta::trueFalseT<false> &f )
2542{
2543 static_cast<void>( f );
2544 return 0;
2545}
2546
2547template <class derivedT>
2549{
2550 if( derivedT::c_stdCamera_cropMode )
2551 {
2552#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2553 return 0;
2554#endif
2555
2556 if( !ipRecv.find( "toggle" ) )
2557 return 0;
2558
2559 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
2560 {
2561 m_cropModeSet = false;
2562 }
2563
2564 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
2565 {
2566 m_cropModeSet = true;
2567 }
2568
2569 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2570
2571 mx::meta::trueFalseT<derivedT::c_stdCamera_cropMode> tf;
2572 return setCropMode( tf );
2573 }
2574
2575 return 0;
2576}
2577
2578///\todo why don't these check if usesROI is true?
2579template <class derivedT>
2580int stdCamera<derivedT>::newCallBack_roi_x( const pcf::IndiProperty &ipRecv )
2581{
2582#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2583 return 0;
2584#endif
2585
2586 float target;
2587
2588 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2589
2590 if( derived().indiTargetUpdate( m_indiP_roi_x, target, ipRecv, false ) < 0 )
2591 {
2592 m_nextROI.x = m_currentROI.x;
2593 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2594 return -1;
2595 }
2596
2597 m_nextROI.x = target;
2598
2599 return 0;
2600}
2601
2602template <class derivedT>
2603int stdCamera<derivedT>::newCallBack_roi_y( const pcf::IndiProperty &ipRecv )
2604{
2605#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2606 return 0;
2607#endif
2608
2609 float target;
2610
2611 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2612
2613 if( derived().indiTargetUpdate( m_indiP_roi_y, target, ipRecv, false ) < 0 )
2614 {
2615 m_nextROI.y = m_currentROI.y;
2616 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2617 return -1;
2618 }
2619
2620 m_nextROI.y = target;
2621
2622 return 0;
2623}
2624
2625template <class derivedT>
2626int stdCamera<derivedT>::newCallBack_roi_w( const pcf::IndiProperty &ipRecv )
2627{
2628#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2629 return 0;
2630#endif
2631
2632 int target;
2633
2634 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2635
2636 if( derived().indiTargetUpdate( m_indiP_roi_w, target, ipRecv, false ) < 0 )
2637 {
2638 m_nextROI.w = m_currentROI.w;
2639 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2640 return -1;
2641 }
2642
2643 m_nextROI.w = target;
2644
2645 return 0;
2646}
2647
2648template <class derivedT>
2649int stdCamera<derivedT>::newCallBack_roi_h( const pcf::IndiProperty &ipRecv )
2650{
2651#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2652 return 0;
2653#endif
2654
2655 int target;
2656
2657 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2658
2659 if( derived().indiTargetUpdate( m_indiP_roi_h, target, ipRecv, false ) < 0 )
2660 {
2661 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2662 m_nextROI.h = m_currentROI.h;
2663 return -1;
2664 }
2665
2666 m_nextROI.h = target;
2667
2668 return 0;
2669}
2670
2671template <class derivedT>
2673{
2674#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2675 return 0;
2676#endif
2677
2678 int target;
2679
2680 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2681
2682 if( derived().indiTargetUpdate( m_indiP_roi_bin_x, target, ipRecv, false ) < 0 )
2683 {
2684 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2685 m_nextROI.bin_x = m_currentROI.bin_x;
2686 return -1;
2687 }
2688
2689 m_nextROI.bin_x = target;
2690
2691 return 0;
2692}
2693
2694template <class derivedT>
2696{
2697#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2698 return 0;
2699#endif
2700
2701 int target;
2702
2703 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2704
2705 if( derived().indiTargetUpdate( m_indiP_roi_bin_y, target, ipRecv, false ) < 0 )
2706 {
2707 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
2708 m_nextROI.bin_y = m_currentROI.bin_y;
2709 return -1;
2710 }
2711
2712 m_nextROI.bin_y = target;
2713
2714 return 0;
2715}
2716
2717template <class derivedT>
2718int stdCamera<derivedT>::checkNextROI( const mx::meta::trueFalseT<true> &t )
2719{
2720 static_cast<void>( t );
2721 return derived().checkNextROI();
2722}
2723
2724template <class derivedT>
2725int stdCamera<derivedT>::checkNextROI( const mx::meta::trueFalseT<false> &f )
2726{
2727 static_cast<void>( f );
2728 return 0;
2729}
2730
2731template <class derivedT>
2733{
2734 if( derivedT::c_stdCamera_usesROI )
2735 {
2736#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2737 return 0;
2738#endif
2739
2740 if( !ipRecv.find( "request" ) )
2741 return 0;
2742
2743 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2744 {
2745 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2746
2748 m_indiP_roi_check, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2749
2750 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2751 return checkNextROI( tf );
2752 }
2753
2754 return 0;
2755 }
2756
2757 return 0;
2758}
2759
2760template <class derivedT>
2761int stdCamera<derivedT>::setNextROI( const mx::meta::trueFalseT<true> &t )
2762{
2763 static_cast<void>( t );
2764 return derived().setNextROI();
2765}
2766
2767template <class derivedT>
2768int stdCamera<derivedT>::setNextROI( const mx::meta::trueFalseT<false> &f )
2769{
2770 static_cast<void>( f );
2771 return 0;
2772}
2773
2774template <class derivedT>
2776{
2777 if( derivedT::c_stdCamera_usesROI )
2778 {
2779#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2780 return 0;
2781#endif
2782
2783 if( !ipRecv.find( "request" ) )
2784 return 0;
2785
2786 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2787 {
2788 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2789
2791 m_indiP_roi_set, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2792
2793 m_lastROI = m_currentROI;
2794
2795 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2796 return setNextROI( tf );
2797 }
2798
2799 return 0;
2800 }
2801
2802 return 0;
2803}
2804
2805template <class derivedT>
2807{
2808 if( derivedT::c_stdCamera_usesROI )
2809 {
2810#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2811 return 0;
2812#endif
2813
2814 if( !ipRecv.find( "request" ) )
2815 return 0;
2816
2817 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2818 {
2819 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2820
2822 m_indiP_roi_full, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2823
2824 m_nextROI.x = m_full_x;
2825 m_nextROI.y = m_full_y;
2826 m_nextROI.w = m_full_w;
2827 m_nextROI.h = m_full_h;
2828 m_nextROI.bin_x = m_full_bin_x;
2829 m_nextROI.bin_y = m_full_bin_y;
2830 m_lastROI = m_currentROI;
2831 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2832 return setNextROI( tf );
2833 }
2834
2835 return 0;
2836 }
2837
2838 return 0;
2839}
2840
2841template <class derivedT>
2843{
2844 if( derivedT::c_stdCamera_usesROI )
2845 {
2846#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2847 return 0;
2848#endif
2849
2850 if( !ipRecv.find( "request" ) )
2851 return 0;
2852
2853 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2854 {
2855 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2856
2858 m_indiP_roi_fullbin, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2859
2860 bool reset = false;
2861
2862 if( m_full_currbin_x == 0 ) // still defaulted
2863 {
2864 derivedT::template log<text_log>( "current-binning full ROI not implemented for this camera",
2866 m_full_currbin_x = m_full_x;
2867 m_full_currbin_y = m_full_y;
2868 m_full_currbin_w = m_full_w;
2869 m_full_currbin_h = m_full_h;
2870 reset = true;
2871 }
2872
2873 m_nextROI.x = m_full_currbin_x;
2874 m_nextROI.y = m_full_currbin_y;
2875 m_nextROI.w = m_full_currbin_w;
2876 m_nextROI.h = m_full_currbin_h;
2877 if( reset )
2878 {
2879 // Use full binning
2880 m_nextROI.bin_x = m_full_bin_x;
2881 m_nextROI.bin_y = m_full_bin_y;
2882
2883 // restore defaults for next time
2884 m_full_currbin_x = 0;
2885 m_full_currbin_y = 0;
2886 m_full_currbin_w = 0;
2887 m_full_currbin_h = 0;
2888 }
2889 else
2890 {
2891 m_nextROI.bin_x = m_currentROI.bin_x;
2892 m_nextROI.bin_y = m_currentROI.bin_y;
2893 }
2894
2895 m_lastROI = m_currentROI;
2896 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2897 return setNextROI( tf );
2898 }
2899
2900 return 0;
2901 }
2902
2903 return 0;
2904}
2905
2906template <class derivedT>
2908{
2909 if( derivedT::c_stdCamera_usesROI )
2910 {
2911#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2912 return 0;
2913#endif
2914
2915 if( !ipRecv.find( "request" ) )
2916 return 0;
2917
2918 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2919 {
2920 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2921
2923 m_indiP_roi_loadlast, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2924
2925 m_nextROI = m_lastROI;
2926 return 0;
2927 }
2928
2929 return 0;
2930 }
2931
2932 return 0;
2933}
2934
2935template <class derivedT>
2937{
2938 if( derivedT::c_stdCamera_usesROI )
2939 {
2940#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2941 return 0;
2942#endif
2943 if( !ipRecv.find( "request" ) )
2944 return 0;
2945
2946 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2947 {
2948 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2949
2951 m_indiP_roi_last, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2952
2953 m_nextROI = m_lastROI;
2954 m_lastROI = m_currentROI;
2955 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2956 return setNextROI( tf );
2957 }
2958
2959 return 0;
2960 }
2961
2962 return 0;
2963}
2964
2965template <class derivedT>
2967{
2968 if( derivedT::c_stdCamera_usesROI )
2969 {
2970#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
2971 return 0;
2972#endif
2973
2974 if( !ipRecv.find( "request" ) )
2975 return 0;
2976
2977 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
2978 {
2979 std::unique_lock<std::mutex> lock( derived().m_indiMutex );
2980
2982 m_indiP_roi_default, "request", pcf::IndiElement::Off, derived().m_indiDriver, INDI_IDLE );
2983
2984 m_nextROI.x = m_default_x;
2985 m_nextROI.y = m_default_y;
2986 m_nextROI.w = m_default_w;
2987 m_nextROI.h = m_default_h;
2988 m_nextROI.bin_x = m_default_bin_x;
2989 m_nextROI.bin_y = m_default_bin_y;
2990 m_lastROI = m_currentROI;
2991 mx::meta::trueFalseT<derivedT::c_stdCamera_usesROI> tf;
2992 return setNextROI( tf );
2993 }
2994
2995 return 0;
2996 }
2997
2998 return 0;
2999}
3000
3001template <class derivedT>
3002int stdCamera<derivedT>::setShutter( int ss, const mx::meta::trueFalseT<true> &t )
3003{
3004 static_cast<void>( t );
3005 return derived().setShutter( ss );
3006}
3007
3008template <class derivedT>
3009int stdCamera<derivedT>::setShutter( int ss, const mx::meta::trueFalseT<false> &f )
3010{
3011 static_cast<void>( ss );
3012 static_cast<void>( f );
3013 return 0;
3014}
3015
3016template <class derivedT>
3018{
3019 if( derivedT::c_stdCamera_hasShutter )
3020 {
3021#ifdef XWCTEST_INDI_CALLBACK_VALIDATION
3022 return 0;
3023#endif
3024
3025 if( !ipRecv.find( "toggle" ) )
3026 return 0;
3027
3028 mx::meta::trueFalseT<derivedT::c_stdCamera_hasShutter> tf;
3029
3030 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
3031 {
3032 setShutter( 1, tf );
3033 }
3034
3035 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
3036 {
3037 setShutter( 0, tf );
3038 }
3039
3040 return 0;
3041 }
3042 return 0;
3043}
3044
3045template <class derivedT>
3046std::string stdCamera<derivedT>::stateString( const mx::meta::trueFalseT<true> &t )
3047{
3048 static_cast<void>( t );
3049 return derived().stateString();
3050}
3051
3052template <class derivedT>
3053std::string stdCamera<derivedT>::stateString( const mx::meta::trueFalseT<false> &f )
3054{
3055 static_cast<void>( f );
3056 return "";
3057}
3058
3059template <class derivedT>
3060bool stdCamera<derivedT>::stateStringValid( const mx::meta::trueFalseT<true> &t )
3061{
3062 static_cast<void>( t );
3063 return derived().stateStringValid();
3064}
3065
3066template <class derivedT>
3067bool stdCamera<derivedT>::stateStringValid( const mx::meta::trueFalseT<false> &f )
3068{
3069 static_cast<void>( f );
3070 return false;
3071}
3072
3073template <class derivedT>
3075{
3076 try
3077 {
3078 if( !derived().m_indiDriver )
3079 return 0;
3080
3081 if( derivedT::c_stdCamera_readoutSpeed )
3082 {
3084 m_indiP_readoutSpeed, m_readoutSpeedName, derived().m_indiDriver, INDI_OK );
3085 }
3086
3087 if( derivedT::c_stdCamera_vShiftSpeed )
3088 {
3090 m_indiP_vShiftSpeed, m_vShiftSpeedName, derived().m_indiDriver, INDI_OK );
3091 }
3092
3093 if( derivedT::c_stdCamera_emGain )
3094 {
3095 derived().updateIfChanged( m_indiP_emGain, "current", m_emGain, INDI_IDLE );
3096 derived().updateIfChanged( m_indiP_emGain, "target", m_emGainSet, INDI_IDLE );
3097 }
3098
3099 if( derivedT::c_stdCamera_exptimeCtrl )
3100 {
3101 derived().updateIfChanged( m_indiP_exptime, "current", m_expTime, INDI_IDLE );
3102 derived().updateIfChanged( m_indiP_exptime, "target", m_expTimeSet, INDI_IDLE );
3103 }
3104
3105 if( derivedT::c_stdCamera_fpsCtrl )
3106 {
3107 derived().updateIfChanged( m_indiP_fps, "current", m_fps, INDI_IDLE );
3108 derived().updateIfChanged( m_indiP_fps, "target", m_fpsSet, INDI_IDLE );
3109 }
3110 else if( derivedT::c_stdCamera_fps )
3111 {
3112 derived().updateIfChanged( m_indiP_fps, "current", m_fps, INDI_IDLE );
3113 }
3114
3115 if( derivedT::c_stdCamera_synchro )
3116 {
3117 if( m_synchro == false )
3118 {
3119 derived().updateSwitchIfChanged( m_indiP_synchro, "toggle", pcf::IndiElement::Off, INDI_IDLE );
3120 }
3121 else
3122 {
3123 derived().updateSwitchIfChanged( m_indiP_synchro, "toggle", pcf::IndiElement::On, INDI_OK );
3124 }
3125 }
3126
3127 if( derivedT::c_stdCamera_usesModes )
3128 {
3129 auto st = pcf::IndiProperty::Ok;
3130 if( m_nextMode != "" )
3131 st = pcf::IndiProperty::Busy;
3132
3133 for( auto it = m_cameraModes.begin(); it != m_cameraModes.end(); ++it )
3134 {
3135 if( it->first == m_modeName )
3136 derived().updateSwitchIfChanged( m_indiP_mode, it->first, pcf::IndiElement::On, st );
3137 else
3138 derived().updateSwitchIfChanged( m_indiP_mode, it->first, pcf::IndiElement::Off, st );
3139 }
3140 }
3141
3142 if( derivedT::c_stdCamera_cropMode )
3143 {
3144 if( m_cropMode == false )
3145 {
3146 derived().updateSwitchIfChanged( m_indiP_cropMode, "toggle", pcf::IndiElement::Off, INDI_IDLE );
3147 }
3148 else
3149 {
3150 derived().updateSwitchIfChanged( m_indiP_cropMode, "toggle", pcf::IndiElement::On, INDI_OK );
3151 }
3152 }
3153
3154 if( derivedT::c_stdCamera_usesROI )
3155 {
3156 // These can't change after initialization, but might not be discoverable until powered on and connected.
3157 // so we'll check every time I guess.
3158 derived().updateIfChanged( m_indiP_fullROI, "x", m_full_x, INDI_IDLE );
3159 derived().updateIfChanged( m_indiP_fullROI, "y", m_full_y, INDI_IDLE );
3160 derived().updateIfChanged( m_indiP_fullROI, "w", m_full_w, INDI_IDLE );
3161 derived().updateIfChanged( m_indiP_fullROI, "h", m_full_h, INDI_IDLE );
3162 }
3163
3164 if( derivedT::c_stdCamera_tempControl )
3165 {
3166 if( m_tempControlStatus == false )
3167 {
3168 derived().updateSwitchIfChanged( m_indiP_tempcont, "toggle", pcf::IndiElement::Off, INDI_IDLE );
3169 derived().updateIfChanged( m_indiP_temp, "current", m_ccdTemp, INDI_IDLE );
3170 derived().updateIfChanged( m_indiP_temp, "target", m_ccdTempSetpt, INDI_IDLE );
3171 derived().updateIfChanged( m_indiP_tempstat, "status", m_tempControlStatusStr, INDI_IDLE );
3172 }
3173 else
3174 {
3175 if( m_tempControlOnTarget )
3176 {
3177 derived().updateSwitchIfChanged( m_indiP_tempcont, "toggle", pcf::IndiElement::On, INDI_OK );
3178 derived().updateIfChanged( m_indiP_temp, "current", m_ccdTemp, INDI_OK );
3179 derived().updateIfChanged( m_indiP_temp, "target", m_ccdTempSetpt, INDI_OK );
3180 derived().updateIfChanged( m_indiP_tempstat, "status", m_tempControlStatusStr, INDI_OK );
3181 }
3182 else
3183 {
3184 derived().updateSwitchIfChanged( m_indiP_tempcont, "toggle", pcf::IndiElement::On, INDI_BUSY );
3185 derived().updateIfChanged( m_indiP_temp, "current", m_ccdTemp, INDI_BUSY );
3186 derived().updateIfChanged( m_indiP_temp, "target", m_ccdTempSetpt, INDI_BUSY );
3187 derived().updateIfChanged( m_indiP_tempstat, "status", m_tempControlStatusStr, INDI_BUSY );
3188 }
3189 }
3190 }
3191 else if( derivedT::c_stdCamera_temp )
3192 {
3193 derived().updateIfChanged( m_indiP_temp, "current", m_ccdTemp, INDI_IDLE );
3194 }
3195
3196 if( derivedT::c_stdCamera_hasShutter )
3197 {
3198 if( m_shutterStatus == "OPERATING" )
3199 {
3200 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_BUSY );
3201 }
3202 if( m_shutterStatus == "POWERON" || m_shutterStatus == "READY" )
3203 {
3204 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_IDLE );
3205 }
3206 else
3207 {
3208 derived().updateIfChanged( m_indiP_shutterStatus, "status", m_shutterStatus, INDI_IDLE );
3209 }
3210
3211 if( m_shutterState == 0 ) // 0 shut, 1 open
3212 {
3213 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::On, INDI_OK );
3214 }
3215 else
3216 {
3217 derived().updateSwitchIfChanged( m_indiP_shutter, "toggle", pcf::IndiElement::Off, INDI_IDLE );
3218 }
3219 }
3220
3221 if( derivedT::c_stdCamera_usesStateString )
3222 {
3223 mx::meta::trueFalseT<derivedT::c_stdCamera_usesStateString> tf;
3224 derived().updateIfChanged( m_indiP_stateString, "current", stateString( tf ), INDI_IDLE );
3225 if( stateStringValid( tf ) )
3226 {
3227 derived().updateIfChanged( m_indiP_stateString, "valid", "yes", INDI_IDLE );
3228 }
3229 else
3230 {
3231 derived().updateIfChanged( m_indiP_stateString, "valid", "no", INDI_IDLE );
3232 }
3233 }
3234 return 0;
3235 }
3236 catch( const std::exception &e )
3237 {
3238 return derivedT::template log<software_error, -1>(
3239 { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
3240 }
3241}
3242
3243template <class derivedT>
3245{
3246 static std::string last_mode;
3247 static roi last_roi;
3248 static float last_expTime = -1e30; // ensure first one goes
3249 static float last_fps = 0;
3250 static float last_adcSpeed = -1;
3251 static float last_emGain = -1;
3252 static float last_ccdTemp = 0;
3253 static float last_ccdTempSetpt = 0;
3254 static bool last_tempControlStatus = 0;
3255 static bool last_tempControlOnTarget = 0;
3256 static std::string last_tempControlStatusStr;
3257 static std::string last_shutterStatus;
3258 static int last_shutterState = false;
3259 static bool last_synchro = false;
3260 static float last_vshiftSpeed = -1;
3261 static bool last_cropMode = false;
3262 static std::string last_readoutSpeed;
3263
3264 if( force || m_modeName != last_mode || m_currentROI.x != last_roi.x || m_currentROI.y != last_roi.y ||
3265 m_currentROI.w != last_roi.w || m_currentROI.h != last_roi.h || m_currentROI.bin_x != last_roi.bin_x ||
3266 m_currentROI.bin_y != last_roi.bin_y || m_expTime != last_expTime || m_fps != last_fps ||
3267 m_emGain != last_emGain || m_adcSpeed != last_adcSpeed || m_ccdTemp != last_ccdTemp ||
3268 m_ccdTempSetpt != last_ccdTempSetpt || m_tempControlStatus != last_tempControlStatus ||
3269 m_tempControlOnTarget != last_tempControlOnTarget || m_tempControlStatusStr != last_tempControlStatusStr ||
3270 m_shutterStatus != last_shutterStatus || m_shutterState != last_shutterState || m_synchro != last_synchro ||
3271 m_vshiftSpeed != last_vshiftSpeed || m_cropMode != last_cropMode || m_readoutSpeedName != last_readoutSpeed)
3272 {
3273 derived().template telem<telem_stdcam>( { m_modeName,
3274 m_currentROI.x,
3275 m_currentROI.y,
3276 m_currentROI.w,
3277 m_currentROI.h,
3278 m_currentROI.bin_x,
3279 m_currentROI.bin_y,
3280 m_expTime,
3281 m_fps,
3282 m_emGain,
3283 m_adcSpeed,
3284 m_ccdTemp,
3285 m_ccdTempSetpt,
3286 (uint8_t)m_tempControlStatus,
3287 (uint8_t)m_tempControlOnTarget,
3288 m_tempControlStatusStr,
3289 m_shutterStatus,
3290 (int8_t)m_shutterState,
3291 (uint8_t)m_synchro,
3292 m_vshiftSpeed,
3293 (uint8_t)m_cropMode,
3294 m_readoutSpeedName } );
3295
3296 last_mode = m_modeName;
3297 last_roi = m_currentROI;
3298 last_expTime = m_expTime;
3299 last_fps = m_fps;
3300 last_emGain = m_emGain;
3301 last_adcSpeed = m_adcSpeed;
3302 last_ccdTemp = m_ccdTemp;
3303 last_ccdTempSetpt = m_ccdTempSetpt;
3304 last_tempControlStatus = m_tempControlStatus;
3305 last_tempControlOnTarget = m_tempControlOnTarget;
3306 last_tempControlStatusStr = m_tempControlStatusStr;
3307 last_shutterStatus = m_shutterStatus;
3308 last_shutterState = m_shutterState;
3309 last_synchro = m_synchro;
3310 last_vshiftSpeed = m_vshiftSpeed;
3311 last_cropMode = m_cropMode;
3312 last_readoutSpeed = m_readoutSpeedName;
3313 }
3314
3315 return 0;
3316}
3317
3318/// Call stdCameraT::setupConfig with error checking for stdCamera
3319/**
3320 * \param cfig the application configurator
3321 */
3322#define STDCAMERA_SETUP_CONFIG( cfig ) \
3323 if( stdCameraT::setupConfig( cfig ) < 0 ) \
3324 { \
3325 log<software_error>( { __FILE__, __LINE__, "Error from stdCameraT::setupConfig" } ); \
3326 m_shutdown = true; \
3327 return; \
3328 }
3329
3330/// Call stdCameraT::loadConfig with error checking for stdCamera
3331/** This must be inside a function that returns int, e.g. the standard loadConfigImpl.
3332 * \param cfig the application configurator
3333 */
3334#define STDCAMERA_LOAD_CONFIG( cfig ) \
3335 if( stdCameraT::loadConfig( cfig ) < 0 ) \
3336 { \
3337 return log<software_error, -1>( { __FILE__, __LINE__, "Error from stdCameraT::loadConfig" } ); \
3338 }
3339
3340/// Call stdCameraT::appStartup with error checking for stdCamera
3341#define STDCAMERA_APP_STARTUP \
3342 if( stdCameraT::appStartup() < 0 ) \
3343 { \
3344 return log<software_error, -1>( { __FILE__, __LINE__, "Error from stdCameraT::appStartup" } ); \
3345 }
3346
3347/// Call stdCameraT::appLogic with error checking for stdCamera
3348#define STDCAMERA_APP_LOGIC \
3349 if( stdCameraT::appLogic() < 0 ) \
3350 { \
3351 return log<software_error, -1>( { __FILE__, __LINE__, "Error from stdCameraT::appLogic" } ); \
3352 }
3353
3354/// Call stdCameraT::updateINDI with error checking for stdCamera
3355#define STDCAMERA_UPDATE_INDI \
3356 if( stdCameraT::updateINDI() < 0 ) \
3357 { \
3358 return log<software_error, -1>( { __FILE__, __LINE__, "Error from stdCameraT::updateINDI" } ); \
3359 }
3360
3361/// Call stdCameraT::appShutdown with error checking for stdCamera
3362#define STDCAMERA_APP_SHUTDOWN \
3363 if( stdCameraT::appShutdown() < 0 ) \
3364 { \
3365 return log<software_error, -1>( { __FILE__, __LINE__, "Error from stdCameraT::appShutdown" } ); \
3366 }
3367
3368} // namespace dev
3369} // namespace app
3370} // namespace MagAOX
3371
3372#endif // stdCamera_hpp
MagAO-X standard camera interface.
float m_maxEMGain
The configurable maximum EM gain. To be enforced in derivedT.
std::vector< std::string > m_readoutSpeedNames
float m_minExpTime
The minimum exposure time, used for INDI attributes.
pcf::IndiProperty m_indiP_roi_fullbin
Property used to trigger setting the full in current binning ROI.
float m_fpsSet
The commanded fps, as set by user.
int newCallBack_temp(const pcf::IndiProperty &ipRecv)
Callback to process a NEW CCD temp request.
int newCallBack_cropMode(const pcf::IndiProperty &ipRecv)
Callback to process a NEW cropMode request.
bool m_synchroSet
Target status of m_synchro.
pcf::IndiProperty m_indiP_roi_y
Property used to set the ROI x center coordinate.
int createReadoutSpeed(const mx::meta::trueFalseT< true > &t)
int m_full_currbin_w
The current-binning full ROI width.
int setShutter(int ss, const mx::meta::trueFalseT< true > &t)
Interface to setShutter when the derivedT has a shutter.
float m_default_x
Power-on ROI center x coordinate.
std::string m_tempControlStatusStr
Camera specific description of temperature control status.
float m_emGain
The camera's current EM gain (if available).
int m_full_bin_x
The x-binning in the full ROI.
int newCallBack_readoutSpeed(const pcf::IndiProperty &ipRecv)
Callback to process a NEW readout speed request.
std::vector< std::string > m_readoutSpeedNameLabels
float m_full_currbin_x
The current-binning full ROI center x coordinate.
int m_full_w
The full ROI width.
float m_emGainSet
The camera's EM gain, as set by the user.
std::string m_vShiftSpeedNameSet
The user requested vshift speed name, to be set by derived()
bool m_cropModeSet
Desired status of crop mode ROIs, if enabled for this camera.
int newCallBack_roi_bin_y(const pcf::IndiProperty &ipRecv)
Callback to process a NEW bin_y request.
std::string m_defaultReadoutSpeed
The default readout speed of the camera.
pcf::IndiProperty m_indiP_shutterStatus
State of the shutter. 0 = shut, 1 = open, -1 = unknown.
float m_expTime
The current exposure time, in seconds.
int setExpTime(const mx::meta::trueFalseT< true > &t)
Interface to setExpTime when the derivedT uses exposure time controls.
std::string m_nextMode
The mode to be set by the next reconfiguration.
pcf::IndiProperty m_indiP_tempstat
int m_default_bin_x
Power-on ROI x binning.
int m_default_w
Power-on ROI width.
int setTempControl(const mx::meta::trueFalseT< true > &t)
Interface to setTempControl when the derivedT has temperature control.
int newCallBack_roi_h(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_h request.
int recordCamera(bool force=false)
bool m_cropMode
Status of crop mode ROIs, if enabled for this camera.
float m_maxExpTime
The maximum exposure time, used for INDI attributes.
float m_stepFPS
The FPS step size, used for INDI attributes.
int newCallBack_mode(const pcf::IndiProperty &ipRecv)
Callback to process a NEW mode request.
int m_default_h
Power-on ROI height.
pcf::IndiProperty m_indiP_roi_last
Property used to trigger setting the last ROI.
pcf::IndiProperty m_indiP_temp
float m_expTimeSet
The exposure time, in seconds, as set by user.
pcf::IndiProperty m_indiP_roi_h
Property used to set the ROI height.
int m_full_h
The full ROI height.
pcf::IndiProperty m_indiP_synchro
int m_full_bin_y
The y-binning in the full ROI.
int checkNextROI(const mx::meta::trueFalseT< true > &t)
Interface to checkNextROI when the derivedT uses ROIs.
int setVShiftSpeed(const mx::meta::trueFalseT< true > &t)
Interface to setVShiftSpeed when the derivedT has vshift speed control.
float m_full_y
The full ROI center y coordinate.
static int st_newCallBack_stdCamera(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for stdCamera properties.
float m_maxFPS
The maximum FPS, used for INDI attributes.
std::string m_readoutSpeedName
The current readout speed name.
float m_ccdTempSetpt
The desired temperature, in C.
bool m_tempControlStatus
Whether or not temperature control is active.
pcf::IndiProperty m_indiP_fps
int newCallBack_roi_last(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_last request.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
pcf::IndiProperty m_indiP_roi_loadlast
Property used to trigger loading the last ROI as the target.
pcf::IndiProperty m_indiP_roi_w
Property used to set the ROI width.
int newCallBack_roi_set(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_set request.
pcf::IndiProperty m_indiP_roi_default
Property used to trigger setting the default and startup ROI.
int newCallBack_stdCamera(const pcf::IndiProperty &ipRecv)
The callback function for stdCamera properties.
std::string m_modeName
The current mode name.
pcf::IndiProperty m_indiP_reconfig
Request switch which forces the framegrabber to go through the reconfigure process.
int setSynchro(const mx::meta::trueFalseT< true > &t)
Interface to setSynchro when the derivedT has synchronization.
pcf::IndiProperty m_indiP_roi_bin_x
Property used to set the ROI x binning.
int newCallBack_roi_loadlast(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_loadlast request.
pcf::IndiProperty m_indiP_readoutSpeed
int setEMGain(const mx::meta::trueFalseT< true > &t)
Interface to setEMGain when the derivedT has EM Gain.
int newCallBack_vShiftSpeed(const pcf::IndiProperty &ipRecv)
Callback to process a NEW vshift speed request.
std::string m_startupMode
The camera mode to load during first init after a power-on.
pcf::IndiProperty m_indiP_roi_check
Property used to trigger checking the target ROI.
pcf::IndiProperty m_indiP_vShiftSpeed
int newCallBack_roi_check(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_check request.
int newCallBack_roi_x(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_x request.
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 appLogic()
Application logic.
int m_full_currbin_h
The current-binning full ROI height.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
pcf::IndiProperty m_indiP_exptime
int newCallBack_shutter(const pcf::IndiProperty &ipRecv)
Callback to process a NEW shutter request.
bool m_synchro
Status of synchronization, true is on, false is off.
std::string m_vShiftSpeedName
The current vshift speed name.
int newCallBack_roi_full(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_full request.
int setCropMode(const mx::meta::trueFalseT< true > &t)
Interface to setCropMode when the derivedT has crop mode.
pcf::IndiProperty m_indiP_emGain
float m_ccdTemp
The current temperature, in C.
int updateINDI()
Update the INDI properties for this device controller.
std::vector< std::string > m_vShiftSpeedNames
int newCallBack_fps(const pcf::IndiProperty &ipRecv)
Callback to process a NEW fps request.
std::string m_defaultVShiftSpeed
The default readout speed of the camera.
int newCallBack_roi_y(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_y request.
pcf::IndiProperty m_indiP_tempcont
bool m_tempControlOnTarget
Whether or not the temperature control system is on its target temperature.
int createVShiftSpeed(const mx::meta::trueFalseT< true > &t)
cameraConfigMap m_cameraModes
Map holding the possible camera mode configurations.
float m_stepExpTime
The maximum exposure time stepsize, used for INDI attributes.
int whilePowerOff()
Actions while powered off.
int setFPS(const mx::meta::trueFalseT< true > &t)
Interface to setFPS when the derivedT uses FPS controls.
int newCallBack_reconfigure(const pcf::IndiProperty &ipRecv)
Callback to process a NEW reconfigure request.
int newCallBack_emgain(const pcf::IndiProperty &ipRecv)
Callback to process a NEW EM gain request.
float m_full_currbin_y
The current-binning full ROI center y coordinate.
int appStartup()
Startup function.
int newCallBack_roi_bin_x(const pcf::IndiProperty &ipRecv)
Callback to process a NEW bin_x request.
std::vector< std::string > m_vShiftSpeedNameLabels
int setTempSetPt(const mx::meta::trueFalseT< true > &t)
Interface to setTempSetPt when the derivedT has temperature control.
pcf::IndiProperty m_indiP_roi_full
Property used to trigger setting the full ROI.
int newCallBack_synchro(const pcf::IndiProperty &ipRecv)
Callback to process a NEW synchro request.
int newCallBack_roi_default(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_default request.
pcf::IndiProperty m_indiP_roi_set
Property used to trigger setting the ROI.
int appShutdown()
Application shutdown.
pcf::IndiProperty m_indiP_shutter
Property used to control the shutter, a switch.
int newCallBack_roi_w(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_w request.
pcf::IndiProperty m_indiP_stateString
pcf::IndiProperty m_indiP_mode
Property used to report the current mode.
pcf::IndiProperty m_indiP_cropMode
Property used to toggle crop mode on and off.
float m_default_y
Power-on ROI center y coordinate.
int setNextROI(const mx::meta::trueFalseT< true > &t)
Interface to setNextROI when the derivedT uses ROIs.
pcf::IndiProperty m_indiP_fullROI
Property used to preset the full ROI dimensions.
bool stateStringValid(const mx::meta::trueFalseT< true > &t)
Interface to stateStringValid when the derivedT provides it.
float m_fps
The current FPS.
std::string stateString(const mx::meta::trueFalseT< true > &t)
Interface to stateString when the derivedT provides it.
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 newCallBack_roi_fullbin(const pcf::IndiProperty &ipRecv)
Callback to process a NEW roi_fullbin request.
int newCallBack_temp_controller(const pcf::IndiProperty &ipRecv)
Callback to process a NEW CCD temp control request.
int newCallBack_exptime(const pcf::IndiProperty &ipRecv)
Callback to process a NEW exposure time request.
int setReadoutSpeed(const mx::meta::trueFalseT< true > &t)
Interface to setReadoutSpeed when the derivedT has readout speed control.
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.
int onPowerOff()
Actions on power off.
std::string m_readoutSpeedNameSet
The user requested readout speed name, to be set by derived()
~stdCamera() noexcept
Destructor.
@ OPERATING
The device is operating, other than homing.
@ READY
The device is ready for operation, but is not operating.
@ 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_BUSY
Definition indiUtils.hpp:29
#define INDI_OK
Definition indiUtils.hpp:28
std::unordered_map< std::string, cameraConfig > cameraConfigMap
Definition stdCamera.hpp:48
int loadCameraConfig(cameraConfigMap &ccmap, mx::app::appConfigurator &config)
Load the camera configurations contained in the app configuration into a map.
Definition stdCamera.cpp:18
std::string m_serialCommand
The command to send to the camera to place it in this mode.
Definition stdCamera.hpp:34
std::string m_configFile
The file to use for this mode, e.g. an EDT configuration file.
Definition stdCamera.hpp:33
A camera configuration.
Definition stdCamera.hpp:32
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
Definition indiUtils.hpp:92
void updateSelectionSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the values of a one-of-many INDI switch vector, but only if it has changed.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:28
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
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 CAMCTRL_E_NOCONFIGS
Definition stdCamera.hpp:26
Software CRITICAL log entry.
Software ERR log entry.