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