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