API
 
Loading...
Searching...
No Matches
picamCtrl.hpp
Go to the documentation of this file.
1/** \file picamCtrl.hpp
2 * \brief The MagAO-X Princeton Instruments EMCCD camera controller.
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup picamCtrl_files
7 */
8
9#ifndef picamCtrl_hpp
10#define picamCtrl_hpp
11
12
13//#include <ImageStruct.h>
14#include <ImageStreamIO/ImageStreamIO.h>
15
16#include <picam_advanced.h>
17
18#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
19#include "../../magaox_git_version.h"
20
21#define DEBUG
22
23#ifdef DEBUG
24#define BREADCRUMB std::cerr << __FILE__ << " " << __LINE__ << "\n";
25#else
26#define BREADCRUMB
27#endif
28
29inline
30std::string PicamEnum2String( PicamEnumeratedType type, piint value )
31{
32 const pichar* string;
33 Picam_GetEnumerationString( type, value, &string );
34 std::string str(string);
35 Picam_DestroyString( string );
36
37 return str;
38}
39
40namespace MagAOX
41{
42namespace app
43{
44
45int readoutParams( piint & adcQual,
46 piflt & adcSpeed,
47 const std::string & rosn
48 )
49{
50 if(rosn == "ccd_00_1MHz")
51 {
52 adcQual = PicamAdcQuality_LowNoise;
53 adcSpeed = 0.1;
54 }
55 else if(rosn == "ccd_01MHz")
56 {
57 adcQual = PicamAdcQuality_LowNoise;
58 adcSpeed = 1;
59 }
60 else if(rosn == "emccd_05MHz")
61 {
62 adcQual = PicamAdcQuality_ElectronMultiplied;
63 adcSpeed = 5;
64 }
65 else if(rosn == "emccd_10MHz")
66 {
67 adcQual = PicamAdcQuality_ElectronMultiplied;
68 adcSpeed = 10;
69 }
70 else if(rosn == "emccd_20MHz")
71 {
72 adcQual = PicamAdcQuality_ElectronMultiplied;
73 adcSpeed = 20;
74 }
75 else if(rosn == "emccd_30MHz")
76 {
77 adcQual = PicamAdcQuality_ElectronMultiplied;
78 adcSpeed = 30;
79 }
80 else
81 {
82 return -1;
83 }
84
85 return 0;
86}
87
88int vshiftParams( piflt & vss,
89 const std::string & vsn
90 )
91{
92 if(vsn == "0_7us")
93 {
94 vss = 0.7;
95 }
96 else if(vsn == "1_2us")
97 {
98 vss = 1.2;
99 }
100 else if(vsn == "2_0us")
101 {
102 vss = 2.0;
103 }
104 else if(vsn == "5_0us")
105 {
106 vss = 5.0;
107 }
108 else
109 {
110 return -1;
111 }
112
113 return 0;
114}
115
116
117/** \defgroup picamCtrl Princeton Instruments EMCCD Camera
118 * \brief Control of a Princeton Instruments EMCCD Camera.
119 *
120 * <a href="../handbook/operating/software/apps/picamCtrl.html">Application Documentation</a>
121 *
122 * \ingroup apps
123 *
124 */
125
126/** \defgroup picamCtrl_files Princeton Instruments EMCCD Camera Files
127 * \ingroup picamCtrl
128 */
129
130/** MagAO-X application to control a Princeton Instruments EMCCD
131 *
132 * \ingroup picamCtrl
133 *
134 * \todo Config item for ImageStreamIO name filename
135 * \todo implement ImageStreamIO circular buffer, with config setting
136 */
137class picamCtrl : public MagAOXApp<>, public dev::stdCamera<picamCtrl>, public dev::frameGrabber<picamCtrl>, public dev::dssShutter<picamCtrl>, public dev::telemeter<picamCtrl>
138{
139
140 friend class dev::stdCamera<picamCtrl>;
141 friend class dev::frameGrabber<picamCtrl>;
142 friend class dev::dssShutter<picamCtrl>;
143 friend class dev::telemeter<picamCtrl>;
144
146
147public:
148 /** \name app::dev Configurations
149 *@{
150 */
151 static constexpr bool c_stdCamera_tempControl = true; ///< app::dev config to tell stdCamera to expose temperature controls
152
153 static constexpr bool c_stdCamera_temp = true; ///< app::dev config to tell stdCamera to expose temperature
154
155 static constexpr bool c_stdCamera_readoutSpeed = true; ///< app::dev config to tell stdCamera to expose readout speed controls
156
157 static constexpr bool c_stdCamera_vShiftSpeed = true; ///< app:dev config to tell stdCamera to expose vertical shift speed control
158
159 static constexpr bool c_stdCamera_emGain = true; ///< app::dev config to tell stdCamera to expose EM gain controls
160
161 static constexpr bool c_stdCamera_exptimeCtrl = true; ///< app::dev config to tell stdCamera to expose exposure time controls
162
163 static constexpr bool c_stdCamera_fpsCtrl = false; ///< app::dev config to tell stdCamera not to expose FPS controls
164
165 static constexpr bool c_stdCamera_fps = true; ///< app::dev config to tell stdCamera not to expose FPS status
166
167 static constexpr bool c_stdCamera_synchro = true; ///< app::dev config to tell stdCamera to not expose synchro mode controls
168
169 static constexpr bool c_stdCamera_usesModes = false; ///< app:dev config to tell stdCamera not to expose mode controls
170
171 static constexpr bool c_stdCamera_usesROI = true; ///< app:dev config to tell stdCamera to expose ROI controls
172
173 static constexpr bool c_stdCamera_cropMode = false; ///< app:dev config to tell stdCamera to expose Crop Mode controls
174
175 static constexpr bool c_stdCamera_hasShutter = true; ///< app:dev config to tell stdCamera to expose shutter controls
176
177 static constexpr bool c_stdCamera_usesStateString = false; ///< app::dev confg to tell stdCamera to expose the state string property
178
179 static constexpr bool c_frameGrabber_flippable = true; ///< app:dev config to tell framegrabber this camera can be flipped
180 ///@}
181
182protected:
183
184 /** \name configurable parameters
185 *@{
186 */
187 std::string m_serialNumber; ///< The camera's identifying serial number
188
189
190 ///@}
191
192 int m_depth {0};
193
195 pi64s m_tsRes; // time stamp resolution
197 double m_camera_timestamp {0.0};
200
201 std::string m_fxngenName { "fxngensync" }; ///< Default fxngen device name
202 std::string m_fxngenCh { "C2" }; ///< Default fxngen channel
203
204 std::string m_otherCamName;
205
206
207
210
213
214 std::string m_cameraName;
215 std::string m_cameraModel;
216
217public:
218
219 ///Default c'tor
220 picamCtrl();
221
222 ///Destructor
224
225 /// Setup the configuration system (called by MagAOXApp::setup())
226 virtual void setupConfig();
227
228 /// load the configuration system results (called by MagAOXApp::setup())
229 virtual void loadConfig();
230
231 /// Startup functions
232 /** Sets up the INDI vars.
233 *
234 */
235 virtual int appStartup();
236
237 /// Implementation of the FSM for the Siglent SDG
238 virtual int appLogic();
239
240 /// Implementation of the on-power-off FSM logic
241 virtual int onPowerOff();
242
243 /// Implementation of the while-powered-off FSM
245
246 /// Do any needed shutdown tasks. Currently nothing in this app.
247 virtual int appShutdown();
248
250 int getPicamParameter( piint & value,
252 );
253
254 int getPicamParameter( piflt & value,
256 );
257
259 pi64s value,
260 bool commit = true
261 );
262
264 piint value,
265 bool commit = true
266 );
267
270 piflt value,
271 bool commit = true
272 );
273
276 piint value,
277 bool commit = true
278 );
279
280
282 piflt value,
283 bool commit = true
284 );
285
288 piflt value
289 );
290
292 piflt value
293 );
294
297 piint value
298 );
299
301 piint value
302 );
303
304 int connect();
305
307
308 int getTemps();
309
310 // stdCamera interface:
311
312 //This must set the power-on default values of
313 /* -- m_ccdTempSetpt
314 * -- m_currentROI
315 */
316 int powerOnDefaults();
317
318 int setTempControl();
319 int setTempSetPt();
320 int setReadoutSpeed();
321 int setVShiftSpeed();
322 int setEMGain();
323 int setExpTime();
324 int capExpTime(piflt& exptime);
325 int setFPS();
326 int setSynchro();
327 void updateFxnGenSync();
328
329 /// Check the next ROI
330 /** Checks if the target values are valid and adjusts them to the closest valid values if needed.
331 *
332 * \returns 0 if successful
333 * \returns -1 otherwise
334 */
335 int checkNextROI();
336
337 int setNextROI();
338
339 /// Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface]
340 /**
341 * \returns 0 always
342 */
343 int setShutter(int sh);
344
345 //Framegrabber interface:
347 float fps();
348 int startAcquisition();
350 int loadImageIntoStream(void * dest);
351 int reconfig();
352
353
354 //INDI:
356
358 pcf::IndiProperty m_indiP_fxngensync_freq; ///< Property for setting fxngensync frequency
359 pcf::IndiProperty m_indiP_fxngensync_output; ///< Proprety for turning on fxngensync
360
361 pcf::IndiProperty m_indiP_receiveSynchro; ///< Synchro that can only be triggered from the otherCam
362 pcf::IndiProperty m_indiP_receiveExptime; ///< Exptime that can only be triggered from the otherCam
363
364 pcf::IndiProperty m_indiP_otherCamExptime; ///< Property for setting otherCam exptime
365 pcf::IndiProperty m_indiP_otherCamSynchro; ///< Property for setting otherCam synchro
366
367public:
369
371
373
374 /** \name Telemeter Interface
375 *
376 * @{
377 */
378 int checkRecordTimes();
379
381
382
383 ///@}
384};
385
386inline
388{
389 m_powerMgtEnabled = true;
390
391 m_acqBuff.memory_size = 0;
392 m_acqBuff.memory = 0;
393
394 m_defaultReadoutSpeed = "emccd_05MHz";
395 m_readoutSpeedNames = {"ccd_00_1MHz", "ccd_01MHz", "emccd_05MHz", "emccd_10MHz", "emccd_20MHz", "emccd_30MHz"};
396 m_readoutSpeedNameLabels = {"CCD 0.1 MHz", "CCD 1 MHz", "EMCCD 5 MHz", "EMCCD 10 MHz", "EMCCD 20 MHz", "EMCCD 30 MHz"};
397
398 m_defaultVShiftSpeed = "1_2us";
399 m_vShiftSpeedNames = {"0_7us", "1_2us", "2_0us", "5_0us"};
400 m_vShiftSpeedNameLabels = {"0.7 us", "1.2 us", "2.0 us", "5.0 us"};
401
402 m_full_x = 511.5;
403 m_full_y = 511.5;
404 m_full_w = 1024;
405 m_full_h = 1024;
406
407 m_maxEMGain = 1000;
408
409 return;
410}
411
412inline
414{
415 if(m_acqBuff.memory)
416 {
417 free(m_acqBuff.memory);
418 }
419
420 return;
421}
422
423
424/// Interface to setSynchro when the derivedT has synchronization
425 /** Tag-dispatch resolution of c_stdCamera_synchro==true will call this function.
426 * Calls derivedT::setSynchro.
427 */
429{
430 m_reconfig = true;
431
432 if (!m_otherCamName.empty())
433 {
434 if (m_synchroSet)
435 {
436 std::cerr << "Turning synchro on for " << m_otherCamName << std::endl;
437 m_indiP_otherCamSynchro["toggle"] = pcf::IndiElement::On;
439
440 std::cerr << "Setting " << m_otherCamName << "'s exposure time" << std::endl;
443 }
444 else
445 {
446 std::cerr << "Turning synchro off for " << m_otherCamName << std::endl;
447 m_indiP_otherCamSynchro["toggle"] = pcf::IndiElement::Off;
449 }
450 }
451
452 recordCamera(true);
453
454 return 0;
455}
456
457inline
459{
460 config.add("camera.serialNumber", "", "camera.serialNumber", argType::Required, "camera", "serialNumber", false, "int", "The identifying serial number of the camera.");
461
462 config.add("synchro.deviceName", "", "synchro.deviceName", argType::Required, "synchro", "deviceName", false, "string", "The fxngen device name used for synchronizing the camera.");
463 config.add("synchro.channel", "", "synchro.channel", argType::Required, "synchro", "channel", false, "string", "The fxngen channel used for synchronizing the camera.");
464 config.add("synchro.otherCamName", "", "synchro.otherCamName", argType::Required, "synchro", "otherCamName", false, "string", "The other camera (used for coupling exposure time while synchro'd)");
465
470}
471
472inline
474{
475
476 config(m_serialNumber, "camera.serialNumber");
477 config(m_fxngenName, "synchro.deviceName");
478 config(m_fxngenCh, "synchro.channel");
479 config(m_otherCamName, "synchro.otherCamName");
480
485
486
487}
488
489inline
491{
492
493 // DELETE ME
494 //m_outfile = fopen("/home/xsup/test2.txt", "w");
495
496 createROIndiNumber( m_indiP_readouttime, "readout_time", "Readout Time (s)");
497 indi::addNumberElement<float>( m_indiP_readouttime, "value", 0.0, std::numeric_limits<float>::max(), 0.0, "%0.1f", "readout time");
499
500
501 m_minTemp = -55;
502 m_maxTemp = 25;
503 m_stepTemp = 0;
504
505 m_minROIx = 0;
506 m_maxROIx = 1023;
507 m_stepROIx = 0;
508
509 m_minROIy = 0;
510 m_maxROIy = 1023;
511 m_stepROIy = 0;
512
513 m_minROIWidth = 1;
514 m_maxROIWidth = 1024;
515 m_stepROIWidth = 4;
516
517 m_minROIHeight = 1;
518 m_maxROIHeight = 1024;
519 m_stepROIHeight = 1;
520
524
526 m_maxROIBinning_y = 1024;
528
530 {
532 }
533
535 {
537 }
538
540 {
542 }
543
545 {
546 return log<software_error,-1>({__FILE__,__LINE__});
547 }
548
549
550 m_indiP_fxngensync_freq = pcf::IndiProperty( pcf::IndiProperty::Number );
552 m_indiP_fxngensync_freq.setName( m_fxngenCh + "freq" );
553 m_indiP_fxngensync_freq.add( pcf::IndiElement( "target" ) );
554
555 m_indiP_fxngensync_output = pcf::IndiProperty( pcf::IndiProperty::Text );
557 m_indiP_fxngensync_output.setName( m_fxngenCh + "outp" );
558 m_indiP_fxngensync_output.add( pcf::IndiElement( "value" ) );
559
560
561 CREATE_REG_INDI_NEW_NUMBERD(m_indiP_receiveExptime, "receiveExptime", m_minExpTime, m_maxExpTime, m_stepExpTime, "%0.3f", "Exptime", "Other cam");
563
564
565 m_indiP_otherCamExptime = pcf::IndiProperty( pcf::IndiProperty::Number );
567 m_indiP_otherCamExptime.setName( "receiveExptime" );
568 m_indiP_otherCamExptime.add( pcf::IndiElement( "target" ) );
569
570 m_indiP_otherCamSynchro = pcf::IndiProperty( pcf::IndiProperty::Switch );
572 m_indiP_otherCamSynchro.setName( "receiveSynchro" );
573 m_indiP_otherCamSynchro.add( pcf::IndiElement( "toggle" ) );
574
575 return 0;
576
577}
578
579inline
581{
582 //and run stdCamera's appLogic
584 {
585 return log<software_error, -1>({__FILE__, __LINE__});
586 }
587
588 //first run frameGrabber's appLogic to see if the f.g. thread has exited.
590 {
591 return log<software_error, -1>({__FILE__, __LINE__});
592 }
593
594 //and run dssShutter's appLogic
596 {
597 return log<software_error, -1>({__FILE__, __LINE__});
598 }
599
600
602 {
603 m_reconfig = true; //Trigger a f.g. thread reconfig.
604
605 //Might have gotten here because of a power off.
606 if(powerState() != 1 || powerStateTarget() != 1) return 0;
607
608 std::cerr << __LINE__ << '\n';
609 std::unique_lock<std::mutex> lock(m_indiMutex);
610 if(connect() < 0)
611 {
612 if(powerState() != 1 || powerStateTarget() != 1) return 0;
614 }
615
616 if(state() != stateCodes::CONNECTED) return 0;
617 }
618
620 {
621 //Get a lock
622 std::unique_lock<std::mutex> lock(m_indiMutex);
623
624 if( getAcquisitionState() < 0 )
625 {
626 if(powerState() != 1 || powerStateTarget() != 1) return 0;
628 }
629
630 if( setTempSetPt() < 0 ) //m_ccdTempSetpt already set on power on
631 {
632 if(powerState() != 1 || powerStateTarget() != 1) return 0;
634 }
635
636
638 {
640 }
641
643
644
645 }
646
648 {
649 //Get a lock if we can
650 std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
651
652 //but don't wait for it, just go back around.
653 if(!lock.owns_lock()) return 0;
654
655 if(getAcquisitionState() < 0)
656 {
657 if(powerState() != 1 || powerStateTarget() != 1) return 0;
658
660 return 0;
661 }
662
663
664
665 if(getTemps() < 0)
666 {
667 if(powerState() != 1 || powerStateTarget() != 1) return 0;
668
670 return 0;
671 }
672
674 {
676 }
677
679 {
681 }
682
684 {
686 return 0;
687 }
688
689 }
690
691 //Fall through check?
692 return 0;
693
694}
695
696inline
698{
699 std::lock_guard<std::mutex> lock(m_indiMutex);
700
702 {
704 m_cameraHandle = 0;
705 }
706
708
710 {
712 }
713
715 {
717 }
718
719 return 0;
720}
721
722inline
724{
726 {
728 }
729
731 {
733 }
734
735 return 0;
736}
737
738inline
740{
742
744 {
746 m_cameraHandle = 0;
747 }
748
750
751 ///\todo error check these base class fxns.
754
755 return 0;
756}
757
758inline
761 )
762{
764
765 if(MagAOXAppT::m_powerState == 0) return -1; //Flag error but don't log
766
768 {
769 if(powerState() != 1 || powerStateTarget() != 1) return -1;
771 return -1;
772 }
773
774 return 0;
775}
776
777inline
780 )
781{
783
784 if(MagAOXAppT::m_powerState == 0) return -1; //Flag error but don't log
785
787 {
788 if(powerState() != 1 || powerStateTarget() != 1) return -1;
790 return -1;
791 }
792
793 return 0;
794}
795
796inline
798 pi64s value,
799 bool commit
800 )
801{
804 {
805 if(powerState() != 1 || powerStateTarget() != 1) return -1;
807 return -1;
808 }
809
810 if(!commit) return 0;
811
814
817 {
818 if(powerState() != 1 || powerStateTarget() != 1) return -1;
820 return -1;
821 }
822
823 for( int i=0; i< failed_parameters_count; ++i)
824 {
826 {
828 return log<text_log,-1>( "Parameter not committed");
829 }
830 }
831
833
834 return 0;
835}
836
837inline
840 piflt value,
841 bool commit
842 )
843{
846 {
847 if(powerState() != 1 || powerStateTarget() != 1) return -1;
849 return -1;
850 }
851
852 if(!commit) return 0;
853
856
859 {
860 if(powerState() != 1 || powerStateTarget() != 1) return -1;
862 return -1;
863 }
864
865 for( int i=0; i< failed_parameters_count; ++i)
866 {
868 {
870 return log<text_log,-1>( "Parameter not committed");
871 }
872 }
873
875
876 return 0;
877}
878
879inline
882 piint value,
883 bool commit
884 )
885{
888 {
889 if(powerState() != 1 || powerStateTarget() != 1) return -1;
891 return -1;
892 }
893
894 if(!commit) return 0;
895
898
901 {
902 if(powerState() != 1 || powerStateTarget() != 1) return -1;
904 return -1;
905 }
906
907 for( int i=0; i< failed_parameters_count; ++i)
908 {
910 {
912 return log<text_log,-1>( "Parameter not committed");
913 }
914 }
915
917
918 return 0;
919}
920
921inline
929
930inline
938
939inline
955
956inline
963
964inline
980
981inline
988
989inline
991{
992 std::cerr << __LINE__ << '\n';
996
997 if(m_acqBuff.memory)
998 {
999 free(m_acqBuff.memory);
1000 m_acqBuff.memory = NULL;
1001 m_acqBuff.memory_size = 0;
1002 }
1003
1004 std::cerr << __LINE__ << '\n';
1005
1007
1008 std::cerr << __LINE__ << '\n';
1009
1010 //Have to initialize the library every time. Otherwise we won't catch a newly booted camera.
1012
1013 std::cerr << __LINE__ << '\n';
1014
1015 if(m_cameraHandle)
1016 {
1018 m_cameraHandle = 0;
1019 }
1020
1021 std::cerr << __LINE__ << '\n';
1022
1024
1025 std::cerr << __LINE__ << '\n';
1026
1027 if(powerState() != 1 || powerStateTarget() != 1) return 0;
1028
1029 std::cerr << __LINE__ << '\n';
1030
1031 if(id_count == 0)
1032 {
1034
1036
1038 if(!stateLogged())
1039 {
1040 log<text_log>("no P.I. Cameras available.", logPrio::LOG_NOTICE);
1041 }
1042 return 0;
1043 }
1044 else
1045 {
1046 std::cerr << "found " << id_count << " PI cameras.\n";
1047 }
1048
1049 for(int i=0; i< id_count; ++i)
1050 {
1051 if( std::string(id_array[i].serial_number) == m_serialNumber )
1052 {
1053 log<text_log>("Camera was found. Now connecting.");
1054
1056 if(error == PicamError_None)
1057 {
1058 m_cameraName = id_array[i].sensor_name;
1060
1062 if( error != PicamError_None )
1063 {
1064 log<software_error>({__FILE__, __LINE__, "failed to get camera model"});
1065 }
1066
1068 log<text_log>("Connected to " + m_cameraName + " [S/N " + m_serialNumber + "]");
1069
1071
1074
1075 return 0;
1076 }
1077 else
1078 {
1079 if(powerState() != 1 || powerStateTarget() != 1) return 0;
1080
1082 if(!stateLogged())
1083 {
1084 log<software_error>({__FILE__,__LINE__, 0, error, "Error connecting to camera."});
1085 }
1086
1088
1090 return -1;
1091 }
1092 }
1093 }
1094
1096 if(!stateLogged())
1097 {
1098 log<text_log>("Camera not found in available ids.");
1099 }
1100
1102
1103
1105
1106
1107 return 0;
1108}
1109
1110
1111inline
1113{
1114 pibln running = false;
1115
1117
1118 if(MagAOXAppT::m_powerState == 0) return 0;
1119
1120 if(error != PicamError_None)
1121 {
1122 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1125 return -1;
1126 }
1127
1130
1131 if(!running)
1132 {
1133 log<text_log>("acqusition stopped. restarting", logPrio::LOG_ERROR);
1134 m_reconfig = true;
1135 }
1136
1137 return 0;
1138
1139}
1140
1141inline
1143{
1145
1147 {
1148 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1149
1152 return -1;
1153 }
1154
1156
1157 //PicamSensorTemperatureStatus
1158 piint status;
1159
1161 {
1162 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1163
1166 return -1;
1167 }
1168
1170 {
1171 m_tempControlStatus = true;
1172 m_tempControlOnTarget = false;
1173 m_tempControlStatusStr = "UNLOCKED";
1174 }
1175 else if(status == PicamSensorTemperatureStatus_Locked)
1176 {
1177 m_tempControlStatus = true;
1178 m_tempControlOnTarget = true;
1179 m_tempControlStatusStr = "LOCKED";
1180 }
1181 else if(status == PicamSensorTemperatureStatus_Faulted)
1182 {
1183 m_tempControlStatus = false;
1184 m_tempControlOnTarget = false;
1185 m_tempControlStatusStr = "FAULTED";
1186 log<text_log>("temperature control faulted", logPrio::LOG_ALERT);
1187 }
1188 else
1189 {
1190 m_tempControlStatus = false;
1191 m_tempControlOnTarget = false;
1192 m_tempControlStatusStr = "UNKNOWN";
1193 }
1194
1195 recordCamera();
1196
1197 return 0;
1198
1199}
1200
1201inline
1203{
1204 return 0;
1205}
1206
1207inline
1209{
1210 m_ccdTempSetpt = -55; //This is the power on setpoint
1211
1212 /*m_currentROI.x = 511.5;
1213 m_currentROI.y = 511.5;
1214 m_currentROI.w = 1024;
1215 m_currentROI.h = 1024;
1216 m_currentROI.bin_x = 1;
1217 m_currentROI.bin_y = 1;*/
1218
1219 m_readoutSpeedName = "emccd_05MHz";
1220 m_vShiftSpeedName = "1_2us";
1221 return 0;
1222}
1223
1224inline
1226{
1227 //Always on
1228 m_tempControlStatus = true;
1230 updateSwitchIfChanged(m_indiP_tempcont, "toggle", pcf::IndiElement::On, INDI_IDLE);
1231 recordCamera(true);
1232 return 0;
1233}
1234
1235inline
1237{
1238 ///\todo bounds check here.
1239 m_reconfig = true;
1240
1241 recordCamera(true);
1242 return 0;
1243}
1244
1245inline
1247{
1248 m_reconfig = true;
1249 recordCamera(true);
1250 return 0;
1251}
1252
1253inline
1255{
1256 m_reconfig = true;
1257 recordCamera(true);
1258 return 0;
1259}
1260
1261inline
1263{
1264 piint adcQual;
1265 piflt adcSpeed;
1266
1267 if(readoutParams(adcQual, adcSpeed, m_readoutSpeedName) < 0)
1268 {
1269 log<software_error>({__FILE__, __LINE__, "Invalid readout speed: " + m_readoutSpeedNameSet});
1271 return -1;
1272 }
1273
1275 {
1276 m_emGain = 1;
1277 m_adcSpeed = adcSpeed;
1278 recordCamera(true);
1279 log<text_log>("Attempt to set EM gain while in conventional amplifier.", logPrio::LOG_NOTICE);
1280 return 0;
1281 }
1282
1284 if(emg < 0)
1285 {
1286 emg = 0;
1287 log<text_log>("EM gain limited to 0", logPrio::LOG_WARNING);
1288 }
1289
1290 if(emg > m_maxEMGain)
1291 {
1292 emg = m_maxEMGain;
1293 log<text_log>("EM gain limited to maxEMGain = " + std::to_string(emg), logPrio::LOG_WARNING);
1294 }
1295
1296 recordCamera(true);
1298 {
1299 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1300 log<software_error>({__FILE__, __LINE__, "Error setting EM gain"});
1301 return -1;
1302 }
1303
1306 {
1307 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1308 return log<software_error,-1>({__FILE__, __LINE__, "could not get AdcEMGain"});
1309 }
1311 m_adcSpeed = adcSpeed;
1312 recordCamera(true);
1313 return 0;
1314}
1315
1316
1318{
1319
1320 std::cerr << "Setting fxngen frequency to " << std::to_string(m_fps) << " Hz" << std::endl;
1321 m_indiP_fxngensync_freq["target"] = m_fps;
1323
1324 // make sure fxngen is on!
1325 m_indiP_fxngensync_output["value"] = "On";
1327}
1328
1329inline
1331{
1332 long intexptime = m_expTimeSet * 1000 * 10000 + 0.5;
1333 piflt exptime = ((double)intexptime)/10000;
1334 capExpTime(exptime);
1335
1336 int rv;
1337
1338 recordCamera(true);
1339
1341 {
1343 }
1344 else
1345 {
1347 }
1348
1349 if(rv < 0)
1350 {
1351 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1352 log<software_error>({__FILE__, __LINE__, "Error setting exposure time"});
1353 return -1;
1354 }
1355
1356 m_expTime = exptime/1000.0;
1357
1358 recordCamera(true);
1359
1361
1363 {
1364 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1365 log<software_error>({__FILE__, __LINE__, "could not get FrameRateCalculation"});
1366 }
1368
1369
1370 if (m_synchro && !m_otherCamName.empty())
1371 {
1372 std::cerr << "Setting " << m_otherCamName << " exptime to " << std::to_string(m_expTime) << std::endl;
1375
1377 }
1378
1379 recordCamera(true);
1380
1381 return 0;
1382}
1383
1384inline
1386{
1387 // cap at minimum possible value
1388 if(exptime < m_ReadOutTimeCalculation)
1389 {
1390 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1391 log<text_log>("Got exposure time " + std::to_string(exptime) + " ms but min value is " + std::to_string(m_ReadOutTimeCalculation) + " ms");
1392 long intexptime = m_ReadOutTimeCalculation * 10000 + 0.5;
1393 exptime = ((double)intexptime)/10000;
1394 }
1395
1396 return 0;
1397}
1398
1399inline
1401{
1402 return 0;
1403}
1404
1405//Set ROI property to busy if accepted, set toggle to Off and Idlw either way.
1406//Set ROI actual
1407//Update current values (including struct and indiP) and set to OK when done
1408inline
1410{
1411 m_reconfig = true;
1412
1413 updateSwitchIfChanged(m_indiP_roi_set, "request", pcf::IndiElement::Off, INDI_IDLE);
1414
1415 return 0;
1416
1417}
1418
1419inline
1424
1425inline
1427{
1428
1432 //piint frameSize;
1434
1435 m_camera_timestamp = 0; // reset tracked timestamp
1436
1437 std::unique_lock<std::mutex> lock(m_indiMutex);
1438
1439
1440 // Time stamp handling
1442 {
1443 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1444 log<software_error>({__FILE__,__LINE__, "Could not set time stamp mask"});
1445 }
1447 {
1448 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1449 log<software_error>({__FILE__,__LINE__, "Could not get timestamp resolution"}) ;
1450 }
1451
1452 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1453 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1454 // Check Frame Transfer
1455 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1456 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1457
1458 piint cmode;
1460 {
1461 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1462 log<software_error>({__FILE__,__LINE__, "could not get Readout Control Mode"});
1463 return -1;
1464 }
1465
1467 {
1468 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1469 log<software_error>({__FILE__,__LINE__, "Readout Control Mode not configured for frame transfer"}) ;
1470 return -1;
1471 }
1472
1473 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1474 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1475 // Temperature
1476 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1477 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1478
1480 {
1481 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1482 log<software_error>({__FILE__, __LINE__, "Error setting temperature setpoint"});
1484 return -1;
1485 }
1486
1487 //log<text_log>( "Set temperature set point: " + std::to_string(m_ccdTempSetpt) + " C");
1488
1489 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1490 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1491 // ADC Speed and Quality
1492 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1493 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1494
1495 piint adcQual;
1496 piflt adcSpeed;
1497
1498 if(readoutParams(adcQual, adcSpeed, m_readoutSpeedNameSet) < 0)
1499 {
1500 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1501 log<software_error>({__FILE__, __LINE__, "Invalid readout speed: " + m_readoutSpeedNameSet});
1503 return -1;
1504 }
1505
1506 if( setPicamParameter(m_modelHandle, PicamParameter_AdcSpeed, adcSpeed, false) < 0) //don't commit b/c it will error if quality mismatched
1507 {
1508 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1509 log<software_error>({__FILE__, __LINE__, "Error setting ADC Speed"});
1510 //state(stateCodes::ERROR);
1511 //return -1;
1512 }
1513
1515 {
1516 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1517 log<software_error>({__FILE__, __LINE__, "Error setting ADC Quality"});
1519 return -1;
1520 }
1521 m_adcSpeed = adcSpeed;
1523 log<text_log>( "Readout speed set to: " + m_readoutSpeedNameSet);
1524
1526 {
1527 m_emGain = 1.0;
1528 m_emGainSet = 1.0;
1529 }
1530
1531 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1532 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1533 // Vertical Shift Rate
1534 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1535 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1536
1537 piflt vss;
1539 {
1540 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1541 log<software_error>({__FILE__, __LINE__, "Invalid vertical shift speed: " + m_vShiftSpeedNameSet});
1543 return -1;
1544 }
1545
1547 {
1548 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1549 log<software_error>({__FILE__, __LINE__, "Error setting Vertical Shift Rate"});
1551 return -1;
1552 }
1553
1556 log<text_log>( "Vertical Shift Rate set to: " + m_vShiftSpeedName);
1557
1558 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1559 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1560 // Dimensions
1561 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1562 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1563
1566
1567 nextrois.roi_array = &nextroi;
1568 nextrois.roi_count = 1;
1569
1570 int roi_err = false;
1572 {
1573 nextroi.x = ((1023-m_nextROI.x) - 0.5*( (float) m_nextROI.w - 1.0));
1574 }
1575 else
1576 {
1577 nextroi.x = (m_nextROI.x - 0.5*( (float) m_nextROI.w - 1.0));
1578 }
1579
1580 if(nextroi.x < 0)
1581 {
1582 log<software_error>({__FILE__, __LINE__, "can't set ROI to x center < 0"});
1583 roi_err = true;
1584 }
1585
1586 if(nextroi.x > 1023)
1587 {
1588 log<software_error>({__FILE__, __LINE__, "can't set ROI to x center > 1023"});
1589 roi_err = true;
1590 }
1591
1592
1594 {
1595 nextroi.y = ((1023 - m_nextROI.y) - 0.5*( (float) m_nextROI.h - 1.0));
1596 }
1597 else
1598 {
1599 nextroi.y = (m_nextROI.y - 0.5*( (float) m_nextROI.h - 1.0));
1600 }
1601
1602 if(nextroi.y < 0)
1603 {
1604 log<software_error>({__FILE__, __LINE__, "can't set ROI to y center < 0"});
1605 roi_err = true;
1606 }
1607
1608 if(nextroi.y > 1023)
1609 {
1610 log<software_error>({__FILE__, __LINE__, "can't set ROI to y center > 1023"});
1611 roi_err = true;
1612 }
1613
1614 nextroi.width = m_nextROI.w;
1615
1616 if(nextroi.width < 0)
1617 {
1618 log<software_error>({__FILE__, __LINE__, "can't set ROI to width to be < 0"});
1619 roi_err = true;
1620 }
1621
1622 if(nextroi.x + nextroi.width > 1024)
1623 {
1624 log<software_error>({__FILE__, __LINE__, "can't set ROI to width such that edge is > 1023"});
1625 roi_err = true;
1626 }
1627
1628 nextroi.height = m_nextROI.h;
1629
1630 if(nextroi.y + nextroi.height > 1024)
1631 {
1632 log<software_error>({__FILE__, __LINE__, "can't set ROI to height such that edge is > 1023"});
1633 roi_err = true;
1634 }
1635
1636 if(nextroi.height < 0)
1637 {
1638 log<software_error>({__FILE__, __LINE__, "can't set ROI to height to be < 0"});
1639 roi_err = true;
1640 }
1641
1642 nextroi.x_binning = m_nextROI.bin_x;
1643
1644 if(nextroi.x_binning < 0)
1645 {
1646 log<software_error>({__FILE__, __LINE__, "can't set ROI x binning < 0"});
1647 roi_err = true;
1648 }
1649
1650 nextroi.y_binning = m_nextROI.bin_y;
1651
1652 if(nextroi.y_binning < 0)
1653 {
1654 log<software_error>({__FILE__, __LINE__, "can't set ROI y binning < 0"});
1655 roi_err = true;
1656 }
1657
1659
1660 if(!roi_err)
1661 {
1663 if( error != PicamError_None )
1664 {
1665 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1666 std::cerr << PicamEnum2String(PicamEnumeratedType_Error, error) << "\n";
1669 return -1;
1670 }
1671 }
1672
1674 {
1675 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1676 log<software_error>({__FILE__, __LINE__, "Error getting readout stride"});
1678 return -1;
1679 }
1680
1682 {
1683 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1684 log<software_error>({__FILE__, __LINE__, "Error getting frame stride"});
1686
1687 return -1;
1688 }
1689
1691 {
1692 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1693 log<software_error>({__FILE__, __LINE__, "Error getting frames per readout"});
1695 return -1;
1696 }
1697
1699 {
1700 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1701 log<software_error>({__FILE__, __LINE__, "Error getting frame size"});
1703 return -1;
1704 }
1705
1707 {
1708 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1709 log<software_error>({__FILE__, __LINE__,"Error getting pixel bit depth"});
1711 return -1;
1712 }
1714
1715 const PicamRois* rois;
1717 if( error != PicamError_None )
1718 {
1719 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1722 return -1;
1723 }
1724 m_xbinning = rois->roi_array[0].x_binning;
1725 m_currentROI.bin_x = m_xbinning;
1726 m_ybinning = rois->roi_array[0].y_binning;
1727 m_currentROI.bin_y = m_ybinning;
1728
1729 std::cerr << rois->roi_array[0].x << "\n";
1730 std::cerr << (rois->roi_array[0].x-1) << "\n";
1731 std::cerr << rois->roi_array[0].width << "\n";
1732 std::cerr << 0.5*( (float) (rois->roi_array[0].width - 1.0)) << "\n";
1733
1734
1736 {
1737 m_currentROI.x = (1023.0-rois->roi_array[0].x) - 0.5*( (float) (rois->roi_array[0].width - 1.0)) ;
1738 //nextroi.x = ((1023-m_nextROI.x) - 0.5*( (float) m_nextROI.w - 1.0));
1739 }
1740 else
1741 {
1742 m_currentROI.x = (rois->roi_array[0].x) + 0.5*( (float) (rois->roi_array[0].width - 1.0)) ;
1743 }
1744
1745
1747 {
1748 m_currentROI.y = (1023.0-rois->roi_array[0].y) - 0.5*( (float) (rois->roi_array[0].height - 1.0)) ;
1749 //nextroi.y = ((1023 - m_nextROI.y) - 0.5*( (float) m_nextROI.h - 1.0));
1750 }
1751 else
1752 {
1753 m_currentROI.y = (rois->roi_array[0].y) + 0.5*( (float) (rois->roi_array[0].height - 1.0)) ;
1754 }
1755
1756
1757
1758
1759
1760 m_currentROI.w = rois->roi_array[0].width;
1761 m_currentROI.h = rois->roi_array[0].height;
1762
1763 m_width = rois->roi_array[0].width / rois->roi_array[0].x_binning;
1764 m_height = rois->roi_array[0].height / rois->roi_array[0].y_binning;
1766
1767
1774
1775
1776 //We also update target to the settable values
1777 m_nextROI.x = m_currentROI.x;
1778 m_nextROI.y = m_currentROI.y;
1779 m_nextROI.w = m_currentROI.w;
1780 m_nextROI.h = m_currentROI.h;
1781 m_nextROI.bin_x = m_currentROI.bin_x;
1782 m_nextROI.bin_y = m_currentROI.bin_y;
1783
1790
1791
1792 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1793 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1794 // Exposure Time and Frame Rate
1795 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1796 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
1797
1799 {
1800 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1801 return log<software_error, -1>({__FILE__, __LINE__, "could not get ReadOutTimeCalculation"});
1802 }
1803 std::cerr << "Readout time is: " << m_ReadOutTimeCalculation << "\n";
1804 updateIfChanged( m_indiP_readouttime, "value", m_ReadOutTimeCalculation/1000.0, INDI_OK); // convert from msec to sec
1805
1809
1810 if(constraint_count != 1)
1811 {
1812 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1813 log<text_log>("Constraint count is not 1: " + std::to_string(constraint_count) + " constraints",logPrio::LOG_ERROR);
1814 }
1815 else
1816 {
1817 m_minExpTime = constraint_array[0].minimum;
1818 m_maxExpTime = constraint_array[0].maximum;
1819 m_stepExpTime = constraint_array[0].increment;
1820
1821 m_indiP_exptime["current"].setMin(m_minExpTime);
1822 m_indiP_exptime["current"].setMax(m_maxExpTime);
1823 m_indiP_exptime["current"].setStep(m_stepExpTime);
1824
1825 m_indiP_exptime["target"].setMin(m_minExpTime);
1826 m_indiP_exptime["target"].setMax(m_maxExpTime);
1827 m_indiP_exptime["target"].setStep(m_stepExpTime);
1828 }
1829
1830 if(m_expTimeSet > 0)
1831 {
1832 long intexptime = m_expTimeSet * 1000 * 10000 + 0.5;
1833 piflt exptime = ((double)intexptime)/10000;
1834 capExpTime(exptime);
1835 std::cerr << "Setting exposure time to " << m_expTimeSet << "\n";
1837
1838 if(rv < 0)
1839 {
1840 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1841 return log<software_error, -1>({__FILE__, __LINE__, "Error setting exposure time"});
1842 }
1843 }
1844
1845 piflt exptime;
1847 {
1848 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1849 return log<software_error,-1>({__FILE__, __LINE__, "Error getting exposure time"});
1850 }
1851 else
1852 {
1853 capExpTime(exptime);
1854 m_expTime = exptime/1000.0;
1855 m_expTimeSet = m_expTime; //At this point it must be true.
1858 }
1859
1861 {
1862 if(powerState() != 1 || powerStateTarget() != 1) return -1;
1863 return log<software_error,-1>({__FILE__, __LINE__, "Error getting frame rate"});
1864 }
1865 else
1866 {
1869 }
1870 std::cerr << "FrameRate is: " << m_FrameRateCalculation << "\n";
1871
1874 {
1875 std::cerr << "could not get AdcQuality\n";
1876 }
1878 std::cerr << "AdcQuality is: " << adcqStr << "\n";
1879
1882 {
1883 std::cerr << "could not get VerticalShiftRate\n";
1884 }
1885 std::cerr << "VerticalShiftRate is: " << verticalShiftRate << "\n";
1886
1889 {
1890 std::cerr << "could not get AdcSpeed\n";
1891 }
1892 std::cerr << "AdcSpeed is: " << AdcSpeed << "\n";
1893
1894
1895 std::cerr << "************************************************************\n";
1896
1897
1900 {
1901 std::cerr << "could not get AdcAnalogGain\n";
1902 }
1904 std::cerr << "AdcAnalogGain is: " << adcgStr << "\n";
1905
1906 if(m_readoutSpeedName == "ccd_00_1MHz" || m_readoutSpeedName == "ccd_01MHz")
1907 {
1908 m_emGain = 1;
1909 }
1910 else
1911 {
1914 {
1915 std::cerr << "could not get AdcEMGain\n";
1916 }
1918 }
1919
1920/*
1921 std::cerr << "Onlineable:\n";
1922 pibln onlineable;
1923 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_ReadoutControlMode,&onlineable);
1924 std::cerr << "ReadoutControlMode: " << onlineable << "\n"; //0
1925
1926 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_AdcQuality,&onlineable);
1927 std::cerr << "AdcQuality: " << onlineable << "\n"; //0
1928
1929 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_AdcAnalogGain,&onlineable);
1930 std::cerr << "AdcAnalogGain: " << onlineable << "\n"; //1
1931
1932 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_DisableCoolingFan,&onlineable);
1933 std::cerr << "DisableCoolingFan: " << onlineable << "\n";//0
1934
1935 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_SensorTemperatureSetPoint,&onlineable);
1936 std::cerr << "SensorTemperatureSetPoint: " << onlineable << "\n"; //0
1937
1938 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_AdcEMGain,&onlineable);
1939 std::cerr << "AdcEMGain: " << onlineable << "\n"; //1
1940
1941 Picam_CanSetParameterOnline(m_modelHandle, PicamParameter_FrameRateCalculation,&onlineable);
1942 std::cerr << "FrameRateCalculation: " << onlineable << "\n"; //0
1943
1944 std::cerr << "************************************************************\n";
1945*/
1946
1947 //If not previously allocated, allocate a nice big buffer to play with
1948 pi64s newbuffsz = framesPerReadout*readoutStride*10; //Save room for 10 frames
1949 if( newbuffsz > m_acqBuff.memory_size)
1950 {
1951 if(m_acqBuff.memory)
1952 {
1953 std::cerr << "Clearing\n";
1954 free(m_acqBuff.memory);
1955 m_acqBuff.memory = NULL;
1957 }
1958
1959 m_acqBuff.memory_size = newbuffsz;
1960 std::cerr << "m_acqBuff.memory_size: " << m_acqBuff.memory_size << "\n";
1961 m_acqBuff.memory = malloc(m_acqBuff.memory_size);
1962
1964 if(error != PicamError_None)
1965 {
1968
1969 std::cerr << "-->" << PicamEnum2String(PicamEnumeratedType_Error, error) << "\n";
1970 }
1971 }
1972
1973 // Hardware trigger
1974 if (m_synchroSet)
1975 {
1977
1978 std::cerr << "Turning synchro on" << std::endl;
1981 m_synchro = true;
1982 updateSwitchIfChanged(m_indiP_synchro, "toggle", pcf::IndiElement::On, INDI_IDLE);
1983 }
1984 else
1985 {
1986 std::cerr << "Turning synchro off" << std::endl;
1988 m_synchro = false;
1989 updateSwitchIfChanged(m_indiP_synchro, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1990 }
1991
1992 //Start continuous acquisition
1994 {
1995 log<software_error>({__FILE__, __LINE__, "Error setting readouts=0"});
1997 return -1;
1998 }
1999
2000 recordCamera();
2001
2003 if(error != PicamError_None)
2004 {
2007
2008 return -1;
2009 }
2010
2011 m_dataType = _DATATYPE_UINT16; //Where does this go?
2012
2013 return 0;
2014
2015}
2016
2017inline
2019{
2020 return m_fps;
2021}
2022
2023inline
2025{
2026 return 0;
2027}
2028
2029inline
2031{
2032 piint camTimeOut = 1000; //1 second keeps us responsive without busy-waiting too much
2033
2035
2037
2040
2042 {
2043 return 1; //This sends it back to framegrabber to check for reconfig, etc.
2044 }
2045
2047
2048 if(error != PicamError_None)
2049 {
2052
2053 return -1;
2054 }
2055
2056 m_available.initial_readout = available.initial_readout;
2057 m_available.readout_count = available.readout_count;
2058
2059 if(m_available.initial_readout == 0)
2060 {
2061 return 1;
2062 }
2063
2064 //std::cerr << "readout: " << m_available.initial_readout << " " << m_available.readout_count << "\n";
2065
2066 // camera time stamp
2067 pibyte *frame = NULL;
2069
2070 frame = static_cast<pibyte*>(m_available.initial_readout);
2071 metadataOffset = (pi64s)frame + m_frameSize;
2072
2073 pi64s *tmpPtr = reinterpret_cast<pi64s*>(metadataOffset);
2074
2075 double cam_ts = (double)*tmpPtr/(double)m_tsRes;
2077
2078 // check for a frame skip
2079 if(delta_ts > 1.5 / m_FrameRateCalculation){
2080 std::cerr << "Skipped frame(s)! (Expected a " << 1000./m_FrameRateCalculation << " ms gap but got " << 1000*delta_ts << " ms)\n";
2081 }
2082 // print
2083
2084 m_camera_timestamp = cam_ts; // update to latest
2085
2086 //fprintf(m_outfile, "%d %-15.8f\n", m_imageStream->md->cnt0+1, (double)*tmpPtr/(double)m_tsRes);
2087
2088 return 0;
2089
2090}
2091
2092inline
2094{
2095 if( frameGrabber<picamCtrl>::loadImageIntoStreamCopy(dest, m_available.initial_readout, m_width, m_height, m_typeSize) == nullptr) return -1;
2096
2097 return 0;
2098}
2099
2100inline
2102{
2103 ///\todo clean this up. Just need to wait on acquisition update the first time probably.
2104
2106 if(error != PicamError_None)
2107 {
2110
2111 return -1;
2112 }
2113
2114 pibln running = true;
2115
2117
2118 while(running)
2119 {
2120 if(MagAOXAppT::m_powerState == 0) return 0;
2121 sleep(1);
2122
2124
2125 if(error != PicamError_None)
2126 {
2129 return -1;
2130 }
2131
2132 piint camTimeOut = 1000;
2133
2135
2137
2139 if(error != PicamError_None)
2140 {
2143 return -1;
2144 }
2145
2146// if(! status.running )
2147// {
2148// std::cerr << "Not running \n";
2149//
2150// std::cerr << "status.running: " << status.running << "\n";
2151// std::cerr << "status.errors: " << status.errors << "\n";
2152// std::cerr << "CameraFaulted: " << (int)(status.errors & PicamAcquisitionErrorsMask_CameraFaulted) << "\n";
2153// std::cerr << "CannectionLost: " << (int)(status.errors & PicamAcquisitionErrorsMask_ConnectionLost) << "\n";
2154// std::cerr << "DataLost: " << (int)(status.errors & PicamAcquisitionErrorsMask_DataLost) << "\n";
2155// std::cerr << "DataNotArriving: " << (int)(status.errors & PicamAcquisitionErrorsMask_DataNotArriving) << "\n";
2156// std::cerr << "None: " << (int)(status.errors & PicamAcquisitionErrorsMask_None) << "\n";
2157// std::cerr << "ShutterOverheated: " << (int)(status.errors & PicamAcquisitionErrorsMask_ShutterOverheated) << "\n";
2158// std::cerr << "status.readout_rate: " << status.readout_rate << "\n";
2159// }
2160
2162 if(error != PicamError_None)
2163 {
2166 return -1;
2167 }
2168 }
2169
2170 return 0;
2171}
2172
2173
2174
2179
2181{
2182 return recordCamera(true);
2183}
2184
2185
2187{
2188
2190
2191 if( ipRecv.getName() != m_indiP_receiveSynchro.getName() )
2192 {
2193 log<software_error>( { __FILE__, __LINE__, "wrong INDI property received" } );
2194
2195 return -1;
2196 }
2197
2198 if( !ipRecv.find( "toggle" ) )
2199 {
2200 return 0;
2201 }
2202
2203 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
2204 {
2205 updateSwitchIfChanged( m_indiP_receiveSynchro, "toggle", pcf::IndiElement::On, INDI_IDLE );
2206
2207 m_synchroSet = true;
2208
2209 }
2210 else
2211 {
2212 updateSwitchIfChanged( m_indiP_receiveSynchro, "toggle", pcf::IndiElement::Off, INDI_IDLE );
2213
2214 m_synchroSet = false;
2215 }
2216
2217 m_reconfig = true;
2218
2219 return 0;
2220}
2221
2223{
2224
2226
2227 if( ipRecv.getName() != m_indiP_receiveExptime.getName() )
2228 {
2229 log<software_error>( { __FILE__, __LINE__, "wrong INDI property received" } );
2230
2231 return -1;
2232 }
2233
2234 if( !ipRecv.find( "target" ) )
2235 {
2236 return 0;
2237 }
2238
2239 m_expTimeSet = ipRecv["target"].get<double>();
2240
2242
2243 // we don't need to strictly reconfig because setExpTime works online, but this
2244 // eludes an infinite loop of triggering the 'otherCam' in setExptime
2245 m_reconfig = 1;
2246
2247 return 0;
2248}
2249
2250
2251
2252}//namespace app
2253} //namespace MagAOX
2254#endif
The base-class for XWCTk applications.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
stateCodes::stateCodeT state()
Get the current state code.
int powerState()
Returns the current power state.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
int powerStateTarget()
Returns the target power state.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int sendNewProperty(const pcf::IndiProperty &ipSend, const std::string &el, const T &newVal)
Send a newProperty command to another device (using the INDI Client interface)
MagAO-X Uniblitz DSS Shutter interface.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int appShutdown()
applogic shutdown
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int m_xbinning
The x-binning according to the framegrabber.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
int appShutdown()
Shuts down the framegrabber thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int m_ybinning
The y-binning according to the framegrabber.
size_t m_typeSize
The size of the type, in bytes. Result of sizeof.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_reconfig
Flag to set if a camera reconfiguration requires a framegrabber reset.
uint32_t m_height
The height of the image, once deinterlaced etc.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
MagAO-X standard camera interface.
float m_maxEMGain
The configurable maximum EM gain. To be enforced in derivedT.
std::vector< std::string > m_readoutSpeedNames
float m_minExpTime
The minimum exposure time, used for INDI attributes.
bool m_synchroSet
Target status of m_synchro.
pcf::IndiProperty m_indiP_roi_y
Property used to set the ROI x center coordinate.
std::string m_tempControlStatusStr
Camera specific description of temperature control status.
float m_emGain
The camera's current EM gain (if available).
std::vector< std::string > m_readoutSpeedNameLabels
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()
std::string m_defaultReadoutSpeed
The default readout speed of the camera.
float m_expTime
The current exposure time, in seconds.
float m_maxExpTime
The maximum exposure time, used for INDI attributes.
float m_expTimeSet
The exposure time, in seconds, as set by user.
pcf::IndiProperty m_indiP_roi_h
Property used to set the ROI height.
float m_full_y
The full ROI center y coordinate.
std::string m_readoutSpeedName
The current readout speed name.
float m_ccdTempSetpt
The desired temperature, in C.
bool m_tempControlStatus
Whether or not temperature control is active.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
pcf::IndiProperty m_indiP_roi_w
Property used to set the ROI width.
pcf::IndiProperty m_indiP_roi_bin_x
Property used to set the ROI x binning.
float m_full_x
The full ROI center x coordinate.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
bool m_synchro
Status of synchronization, true is on, false is off.
std::string m_vShiftSpeedName
The current vshift speed name.
float m_ccdTemp
The current temperature, in C.
std::vector< std::string > m_vShiftSpeedNames
std::string m_defaultVShiftSpeed
The default readout speed of the camera.
bool m_tempControlOnTarget
Whether or not the temperature control system is on its target temperature.
float m_stepExpTime
The maximum exposure time stepsize, used for INDI attributes.
std::vector< std::string > m_vShiftSpeedNameLabels
pcf::IndiProperty m_indiP_roi_set
Property used to trigger setting the ROI.
pcf::IndiProperty m_indiP_roi_bin_y
Property used to set the ROI y binning.
pcf::IndiProperty m_indiP_roi_x
Property used to set the ROI x center coordinate.
bool m_tempControlStatusSet
Desired state of temperature control.
std::string m_readoutSpeedNameSet
The user requested readout speed name, to be set by derived()
int recordTelem(const telem_stdcam *)
int loadImageIntoStream(void *dest)
static constexpr bool c_stdCamera_usesROI
app:dev config to tell stdCamera to expose ROI controls
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
pcf::IndiProperty m_indiP_otherCamSynchro
Property for setting otherCam synchro.
std::string m_cameraModel
std::string m_serialNumber
The camera's identifying serial number.
static constexpr bool c_stdCamera_exptimeCtrl
app::dev config to tell stdCamera to expose exposure time controls
static constexpr bool c_stdCamera_synchro
app::dev config to tell stdCamera to not expose synchro mode controls
int setShutter(int sh)
Sets the shutter state, via call to dssShutter::setShutterState(int) [stdCamera interface].
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
static constexpr bool c_stdCamera_vShiftSpeed
app:dev config to tell stdCamera to expose vertical shift speed control
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
int checkNextROI()
Check the next ROI.
PicamHandle m_cameraHandle
pcf::IndiProperty m_indiP_receiveSynchro
Synchro that can only be triggered from the otherCam.
static constexpr bool c_stdCamera_fpsCtrl
app::dev config to tell stdCamera not to expose FPS controls
static constexpr bool c_stdCamera_cropMode
app:dev config to tell stdCamera to expose Crop Mode controls
std::string m_otherCamName
PicamHandle m_modelHandle
static constexpr bool c_stdCamera_hasShutter
app:dev config to tell stdCamera to expose shutter controls
pcf::IndiProperty m_indiP_otherCamExptime
Property for setting otherCam exptime.
static constexpr bool c_stdCamera_tempControl
app::dev config to tell stdCamera to expose temperature controls
static constexpr bool c_stdCamera_temp
app::dev config to tell stdCamera to expose temperature
~picamCtrl() noexcept
Destructor.
static constexpr bool c_stdCamera_emGain
app::dev config to tell stdCamera to expose EM gain controls
int setSynchro()
Interface to setSynchro when the derivedT has synchronization.
pcf::IndiProperty m_indiP_readouttime
virtual int whilePowerOff()
Implementation of the while-powered-off FSM.
pcf::IndiProperty m_indiP_fxngensync_freq
Property for setting fxngensync frequency.
int getPicamParameter(piint &value, PicamParameter parameter)
picamCtrl()
Default c'tor.
int setPicamParameter(PicamParameter parameter, pi64s value, bool commit=true)
static constexpr bool c_stdCamera_readoutSpeed
app::dev config to tell stdCamera to expose readout speed controls
virtual int onPowerOff()
Implementation of the on-power-off FSM logic.
static constexpr bool c_stdCamera_usesModes
app:dev config to tell stdCamera not to expose mode controls
pcf::IndiProperty m_indiP_receiveExptime
Exptime that can only be triggered from the otherCam.
static constexpr bool c_stdCamera_usesStateString
app::dev confg to tell stdCamera to expose the state string property
int setPicamParameterOnline(PicamHandle handle, PicamParameter parameter, piflt value)
std::string m_fxngenCh
Default fxngen channel.
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber this camera can be flipped
PicamAvailableData m_available
static constexpr bool c_stdCamera_fps
app::dev config to tell stdCamera not to expose FPS status
virtual int appStartup()
Startup functions.
virtual int appLogic()
Implementation of the FSM for the Siglent SDG.
pcf::IndiProperty m_indiP_fxngensync_output
Proprety for turning on fxngensync.
PicamAcquisitionBuffer m_acqBuff
int capExpTime(piflt &exptime)
std::string m_fxngenName
Default fxngen device name.
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_TOGGLESWITCH(prop, name)
Create and register a NEW INDI property as a standard toggle switch, using the standard callback name...
#define CREATE_REG_INDI_NEW_NUMBERD(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as double, using the standard callback n...
#define INDI_NEWCALLBACK_DECL(class, prop)
Declare the callback for a new property request, and declare and define the static wrapper.
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_OK
Definition indiUtils.hpp:28
int readoutParams(int &newa, int &newhss, const std::string &ron)
const pcf::IndiProperty & ipRecv
int vshiftParams(int &newvs, const std::string &vssn, float &vs)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:19
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
static constexpr logPrioT LOG_ALERT
This should only be used if some action is required by operators to keep the system safe.
std::string PicamEnum2String(PicamEnumeratedType type, piint value)
Definition picamCtrl.hpp:30
A device base class which saves telemetry.
Definition telemeter.hpp:75
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording stdcam stage specific status.
A simple text log, a string-type log.
Definition text_log.hpp:24