API
 
Loading...
Searching...
No Matches
baslerCtrl.hpp
Go to the documentation of this file.
1/** \file baslerCtrl.hpp
2 * \brief The MagAO-X basler camera controller.
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup baslerCtrl_files
7 */
8
9#ifndef baslerCtrl_hpp
10#define baslerCtrl_hpp
11
12#include <pylon/PylonIncludes.h>
13#include <pylon/PixelData.h>
14#include <pylon/GrabResultData.h>
15#include <pylon/usb/BaslerUsbInstantCamera.h>
16#include <pylon/usb/_BaslerUsbCameraParams.h>
17#include <GenApi/IFloat.h>
18
19typedef Pylon::CBaslerUsbInstantCamera Camera_t;
20typedef int16_t pixelT;
21
22using namespace Basler_UsbCameraParams;
23
24using namespace Pylon;
25
26// #include <ImageStruct.h>
27#include <ImageStreamIO/ImageStreamIO.h>
28
29#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
30#include "../../magaox_git_version.h"
31
32namespace MagAOX
33{
34namespace app
35{
36
37/** \defgroup baslerCtrl Basler USB3 Camera
38 * \brief Control of a Basler USB3 Camera
39 *
40 * <a href="../handbook/operating/software/apps/baslerCtrl.html">Application Documentation</a>
41 *
42 * \ingroup apps
43 *
44 */
45
46/** \defgroup baslerCtrl_files Basler USB3 Camera Files
47 * \ingroup baslerCtrl
48 */
49
50/** MagAO-X application to control a Basler USB3 Camera
51 *
52 * \ingroup baslerCtrl
53 *
54 */
55class baslerCtrl : public MagAOXApp<>,
56 public dev::stdCamera<baslerCtrl>,
57 public dev::frameGrabber<baslerCtrl>,
58 public dev::telemeter<baslerCtrl>
59{
60
61 friend class dev::stdCamera<baslerCtrl>;
62 friend class dev::frameGrabber<baslerCtrl>;
63 friend class dev::telemeter<baslerCtrl>;
64
65 public:
66 /** \name app::dev Configurations
67 *@{
68 */
69 static constexpr bool c_stdCamera_tempControl =
70 false; ///< app::dev config to tell stdCamera to not expose temperature controls
71
72 static constexpr bool c_stdCamera_temp = true; ///< app::dev config to tell stdCamera to expose temperature
73
74 static constexpr bool c_stdCamera_readoutSpeed =
75 false; ///< app::dev config to tell stdCamera not to expose readout speed controls
76
77 static constexpr bool c_stdCamera_vShiftSpeed =
78 false; ///< app:dev config to tell stdCamera not to expose vertical shift speed control
79
80 static constexpr bool c_stdCamera_emGain =
81 false; ///< app::dev config to tell stdCamera to not expose EM gain controls
82
83 static constexpr bool c_stdCamera_exptimeCtrl =
84 true; ///< app::dev config to tell stdCamera to expose exposure time controls
85
86 static constexpr bool c_stdCamera_fpsCtrl = true; ///< app::dev config to tell stdCamera to expose FPS controls
87
88 static constexpr bool c_stdCamera_fps =
89 true; ///< app::dev config to tell stdCamera not to expose FPS status (ignored since fpsCtrl=true)
90
91 static constexpr bool c_stdCamera_synchro =
92 false; ///< app::dev config to tell stdCamera to not expose synchro mode controls
93
94 static constexpr bool c_stdCamera_usesModes =
95 false; ///< app:dev config to tell stdCamera not to expose mode controls
96
97 static constexpr bool c_stdCamera_usesROI = true; ///< app:dev config to tell stdCamera to expose ROI controls
98
99 static constexpr bool c_stdCamera_cropMode =
100 false; ///< app:dev config to tell stdCamera not to expose Crop Mode controls
101
102 static constexpr bool c_stdCamera_hasShutter =
103 false; ///< app:dev config to tell stdCamera to expose shutter controls
104
105 static constexpr bool c_stdCamera_usesStateString =
106 true; ///< app::dev confg to tell stdCamera to expose the state string property
107
108 static constexpr bool c_frameGrabber_flippable =
109 true; ///< app:dev config to tell framegrabber that this camera can be flipped
110
111 ///@}
112
113 protected:
114 /** \name configurable parameters
115 *@{
116 */
117 std::string m_serialNumber; ///< The camera's identifying serial number
118
119 int m_bits{ 10 }; ///< The number of bits used by the camera.
120
121 ///@}
122
123 /** \name binning allowed values
124 * @{
125 */
126 std::vector<int> m_binXs; ///< The allowed values of binning in X (horizontal)
127 std::vector<int> m_binYs; ///< The allowed values of binning in Y (vertical)
128
129 std::vector<int> m_incXs; ///< The allowed increment in X for each X-binning
130
131 std::vector<int> m_minWs; ///< The minimum value of the width for each X-binning
132 std::vector<int> m_incWs; ///< The minimum value of the width for each X-binning
133 std::vector<int> m_maxWs; ///< The minimum value of the width for each X-binning
134
135 std::vector<int> m_incYs; ///< The allowed increment in Y for each Y-binning
136
137 std::vector<int> m_minHs; ///< The minimum value of the height for each Y-binning
138 std::vector<int> m_incHs; ///< The minimum value of the height for each Y-binning
139 std::vector<int> m_maxHs; ///< The minimum value of the height for each Y-binning
140
141 ///@}
142
143 CBaslerUsbInstantCamera *m_camera{ nullptr }; ///< The library camera handle
144 CGrabResultPtr ptrGrabResult; ///< The result of an attempt to grab an image
145
146 mx::sigproc::circularBufferIndex<float, int32_t> m_tempHist;
147
148 public:
149 /// Default c'tor
150 baslerCtrl();
151
152 /// Destructor
154
155 /// Setup the configuration system (called by MagAOXApp::setup())
156 virtual void setupConfig();
157
158 /// load the configuration system results (called by MagAOXApp::setup())
159 virtual void loadConfig();
160
161 /// Startup functions
162 /** Sets up the INDI vars.
163 *
164 */
165 virtual int appStartup();
166
167 /// Implementation of the FSM for the Siglent SDG
168 virtual int appLogic();
169
170 /// Do any needed shutdown tasks. Currently nothing in this app.
171 virtual int appShutdown();
172
173 int connect();
174
176 int startAcquisition();
178 int loadImageIntoStream( void *dest );
179 int reconfig();
180
181 protected:
182 /// Get the current detector temperature
183 /**
184 * \returns 0 on success
185 * \returns -1 on an error.
186 */
187 int getTemp();
188
189 /// Get the current exposure time
190 /**
191 * \returns 0 on success
192 * \returns -1 on an error.
193 */
194 int getExpTime();
195
196 /// Get the current framerate
197 /**
198 * \returns 0 on success
199 * \returns -1 on an error.
200 */
201 int getFPS();
202
203 float fps();
204
205 /** \name stdCamera Interface
206 *
207 * @{
208 */
209
210 /// Set defaults for a power on state.
211 /**
212 * \returns 0 on success
213 * \returns -1 on error
214 */
215 int powerOnDefaults();
216
217 /// Set the framerate.
218 /** This uses the acquistion framerate feature. If m_fpsSet is 0, acuisition framerate is disabled
219 * and the resultant framerate is based solely on exposure time and ROI. If non-zero, then the
220 * framerate will be set to m_fpsSet and the camera will maintain this (as long as exposure time
221 * and ROI allow).
222 *
223 * \returns 0 always
224 */
225 int setFPS();
226
227 /// Set the Exposure Time. [stdCamera interface]
228 /** Sets the frame rate to m_expTimeSet.
229 *
230 * \returns 0 on success
231 * \returns -1 on error
232 */
233 int setExpTime();
234
235 /// Check the next ROI
236 /** Checks if the target values are valid and adjusts them to the closest valid values if needed.
237 *
238 * \returns 0 always
239 */
240 int checkNextROI();
241
242 /// Set the next ROI
243 /**
244 * \returns 0 always
245 */
246 int setNextROI();
247
248 std::string stateString();
249
250 bool stateStringValid();
251
252 ///@}
253
254 /** \name Telemeter Interface
255 *
256 * @{
257 */
258
259 int checkRecordTimes();
260
262
263 ///@}
264};
265
272
274{
275 return;
276}
277
279{
281
283
284 config.add( "camera.serialNumber",
285 "",
286 "camera.serialNumber",
287 argType::Required,
288 "camera",
289 "serialNumber",
290 false,
291 "int",
292 "The identifying serial number of the camera." );
293 config.add( "camera.bits",
294 "",
295 "camera.bits",
296 argType::Required,
297 "camera",
298 "bits",
299 false,
300 "int",
301 "The number of bits used by the camera. Default is 10." );
302
304}
305
307{
309
310 config( m_serialNumber, "camera.serialNumber" );
311 config( m_bits, "camera.bits" );
312
314
316}
317
319{
320
321 //=================================
322 // Do camera configuration here
323
324 PylonInitialize(); // Initializes pylon runtime before using any pylon methods
325
327 {
328 return log<software_critical, -1>( { __FILE__, __LINE__ } );
329 }
330
332 {
333 return log<software_critical, -1>( { __FILE__, __LINE__ } );
334 }
335
337 {
338 return log<software_error, -1>( { __FILE__, __LINE__ } );
339 }
340
341 m_tempHist.maxEntries( 30 );
342
344
345 return 0;
346}
347
349{
350 // and run stdCamera's appLogic
352 {
353 return log<software_error, -1>( { __FILE__, __LINE__ } );
354 }
355
356 // and run frameGrabber's appLogic to see if the f.g. thread has exited.
358 {
359 return log<software_error, -1>( { __FILE__, __LINE__ } );
360 }
361
363 {
364 std::unique_lock<std::mutex> lock( m_indiMutex );
365 if( connect() < 0 )
366 {
368 }
369
371 return 0;
372 }
373
375 {
376 // Get a lock
377 std::unique_lock<std::mutex> lock( m_indiMutex );
378
380 }
381
383 {
384 // Get a lock if we can
385 std::unique_lock<std::mutex> lock( m_indiMutex, std::try_to_lock );
386
387 // but don't wait for it, just go back around.
388 if( !lock.owns_lock() )
389 return 0;
390
391 if( getTemp() < 0 )
392 {
395 return 0;
396 }
397
398 if( getExpTime() < 0 )
399 {
402 return 0;
403 }
404
405 if( getFPS() < 0 )
406 {
409 return 0;
410 }
411
413 {
416 return 0;
417 }
418
420 {
423 return 0;
424 }
425
427 {
429 return 0;
430 }
431 }
432
433 ///\todo Fall through check?
434
435 return 0;
436}
437
453
455{
457 // info.SetDeviceClass(Camera_t::DeviceClass());
458 info.SetSerialNumber( m_serialNumber.c_str() );
459
460 try
461 {
462 if( m_camera )
463 {
464 m_camera->Close();
465 delete m_camera;
466 }
467 m_camera = nullptr;
468
469 m_camera = new CBaslerUsbInstantCamera( CTlFactory::GetInstance().CreateFirstDevice( info ) );
470 }
471 catch( ... )
472 {
473 if( m_camera )
474 {
475 m_camera->Close();
476 delete m_camera;
477 }
478 m_camera = nullptr;
479
481 if( !stateLogged() )
482 {
483 log<text_log>( "no camera with serial number " + m_serialNumber + " found." );
484 }
485 return 0;
486 }
487
488 try
489 {
490 if( m_shmimName == "" )
491 {
493 (std::string)m_camera->GetDeviceInfo().GetModelName() + "_" +
494 (std::string)m_camera->GetDeviceInfo().GetSerialNumber(); // Gets m_camera model name and serial number
495 }
496
497 m_camera->RegisterConfiguration(
499
500 m_camera->Open(); // Opens camera parameters to grab images and set exposure time
501 }
502 catch( ... )
503 {
504 if( m_camera )
505 {
506 m_camera->Close();
507 delete m_camera;
508 }
509 m_camera = nullptr;
510
512 if( !stateLogged() )
513 {
514 log<text_log>( "error opening camera " + m_serialNumber + "." );
515 }
516 return -1;
517 }
518
519 try
520 {
521 m_camera->ExposureAuto.SetValue( ExposureAuto_Off );
522 }
523 catch( ... )
524 {
525 if( m_camera )
526 {
527 m_camera->Close();
528 delete m_camera;
529 }
530 m_camera = nullptr;
531
533 if( !stateLogged() )
534 {
535 log<text_log>( "failed to set exposure auto off for camera " + m_serialNumber );
536 }
537 return -1;
538 }
539
540 try
541 {
542 if( m_bits == 8 )
543 {
544 m_camera->PixelFormat.SetValue( PixelFormat_Mono8 );
545 }
546 else if( m_bits == 10 )
547 {
548 m_camera->PixelFormat.SetValue( PixelFormat_Mono10 ); // Set to 10 bits
549 }
550 else if( m_bits == 12 )
551 {
552 m_camera->PixelFormat.SetValue( PixelFormat_Mono12 );
553 }
554 else
555 {
556 log<text_log>( "unsupported bit depth for camera" + m_serialNumber + "" );
557 }
558 }
559 catch( ... )
560 {
561 if( m_camera )
562 {
563 m_camera->Close();
564 delete m_camera;
565 }
566 m_camera = nullptr;
567
569 if( !stateLogged() )
570 {
571 log<text_log>( "failed to set bit depth for camera" + m_serialNumber + "" );
572 }
573 return -1;
574 }
575
577 if( !stateLogged() )
578 {
579 log<text_log>( "Found camera of type " + (std::string)m_camera->GetDeviceInfo().GetModelName() +
580 " with serial number " + m_serialNumber + "." );
581 log<text_log>( "Using shared memory name " + m_shmimName + "." );
582 }
583
584 m_camera->BinningHorizontalMode.SetValue( BinningHorizontalMode_Sum );
585 m_camera->BinningVerticalMode.SetValue( BinningVerticalMode_Sum );
586
587 // -- Here we interrogate the camera to find valid ROI settings -- //
588
589 // Stop the camera and cycle through settings to get limits for each binning
590 m_camera->StopGrabbing();
591 m_camera->OffsetX.SetValue( 0 ); // ensure that all values are valid
592 m_camera->OffsetY.SetValue( 0 );
593
594 int minb = m_camera->BinningHorizontal.GetMin();
595 int incb = m_camera->BinningHorizontal.GetInc();
596 int maxb = m_camera->BinningHorizontal.GetMax();
597
598 m_binXs.clear();
599 for( int b = minb; b <= maxb; b += incb )
600 m_binXs.push_back( b );
601
602 minb = m_camera->BinningVertical.GetMin();
603 incb = m_camera->BinningVertical.GetInc();
604 maxb = m_camera->BinningVertical.GetMax();
605
606 m_binYs.clear();
607 for( int b = minb; b <= maxb; b += incb )
608 m_binYs.push_back( b );
609
610 m_incXs.clear();
611 m_minWs.clear();
612 m_incWs.clear();
613 m_maxWs.clear();
614 for( size_t b = 0; b < m_binXs.size(); ++b )
615 {
616 m_camera->BinningHorizontal.SetValue( m_binXs[b] );
617 m_camera->BinningVertical.SetValue( m_binYs[0] );
618
619 m_incXs.push_back( m_camera->OffsetX.GetInc() );
620 m_minWs.push_back( m_camera->Width.GetMin() );
621 m_incWs.push_back( m_camera->Width.GetInc() );
622 m_maxWs.push_back( m_camera->Width.GetMax() );
623
624 /*//Leave for troubleshooting:
625 std::cerr << "--------------------\nH-binning: " << m_binXs[b] << "\n";
626 std::cerr << "OffsetX: " << 1 << " " << m_camera->OffsetX.GetInc() << " " << m_camera->Width.GetMax() -
627 m_camera->Width.GetMin() << "\n"; std::cerr << "Width: " << m_camera->Width.GetMin() << " " <<
628 m_camera->Width.GetInc() << " " << m_camera->Width.GetMax() << "\n"; std::cerr << "OffsetY: " << 1 << " " <<
629 m_camera->OffsetY.GetInc() << " " << m_camera->Height.GetMax() - m_camera->Height.GetMin() << "\n"; std::cerr <<
630 "Height: " << m_camera->Height.GetMin() << " " << m_camera->Height.GetInc() << " " << m_camera->Height.GetMax()
631 << "\n";
632 */
633 }
634
635 m_incYs.clear();
636 m_minHs.clear();
637 m_incHs.clear();
638 m_maxHs.clear();
639 for( size_t b = 0; b < m_binYs.size(); ++b )
640 {
641 m_camera->BinningHorizontal.SetValue( m_binXs[0] );
642 m_camera->BinningVertical.SetValue( m_binYs[b] );
643
644 m_incYs.push_back( m_camera->OffsetX.GetInc() );
645 m_minHs.push_back( m_camera->Height.GetMin() );
646 m_incHs.push_back( m_camera->Height.GetInc() );
647 m_maxHs.push_back( m_camera->Height.GetMax() );
648
649 /*//Leave for troubleshooting:
650 std::cerr << "--------------------\nV-binning: " << m_binYs[b] << "\n";
651 std::cerr << "OffsetX: " << 1 << " " << m_camera->OffsetX.GetInc() << " " << m_camera->Width.GetMax() -
652 m_camera->Width.GetMin() << "\n"; std::cerr << "Width: " << m_camera->Width.GetMin() << " " <<
653 m_camera->Width.GetInc() << " " << m_camera->Width.GetMax() << "\n"; std::cerr << "OffsetY: " << 1 << " " <<
654 m_camera->OffsetY.GetInc() << " " << m_camera->Height.GetMax() - m_camera->Height.GetMin() << "\n"; std::cerr <<
655 "Height: " << m_camera->Height.GetMin() << " " << m_camera->Height.GetInc() << " " << m_camera->Height.GetMax()
656 << "\n";
657 */
658 }
659
660 m_full_w = m_camera->SensorWidth.GetValue();
661 m_full_h = m_camera->SensorHeight.GetValue();
662 m_full_x = 0.5 * ( (float)m_full_w - 1.0 );
663 m_full_y = 0.5 * ( (float)m_full_h - 1.0 );
664
665 if( m_default_w == 0 )
667 if( m_default_h == 0 )
669 if( m_default_x == 0 )
671 if( m_default_y == 0 )
673 if( m_default_bin_x == 0 )
675 if( m_default_bin_y == 0 )
677
684
685 return 0;
686}
687
689{
690 if( !m_camera )
691 return -1;
692
693 try
694 {
695 recordCamera( true );
696 m_camera->StopGrabbing();
697 /*
698 The CenterX/Y has to be set to false otherwise the software tries to auto-center the frames.
699 See: https://docs.baslerweb.com/image-roi
700 */
701 m_camera->CenterX.SetValue( false );
702 m_camera->CenterY.SetValue( false );
703
704 // set offsets to 0 so any valid w/h will work.
705 m_camera->OffsetX.SetValue( 0 );
706 m_camera->OffsetY.SetValue( 0 );
707
708 if( checkNextROI() < 0 )
709 {
710 log<software_error>( { __FILE__, __LINE__, "error from checkNextROI()" } );
711 return -1;
712 }
713
714 // Note: assuming checkNextROI has adjusted m_nextROI to valid values, so not doing any checks
715 // First find binning indices
716 size_t bx = 0;
717 for( size_t b = 0; b < m_binXs.size(); ++b )
718 {
719 if( m_nextROI.bin_x == m_binXs[b] )
720 {
721 bx = b;
722 break;
723 }
724 }
725
726 size_t by = 0;
727 for( size_t b = 0; b < m_binYs.size(); ++b )
728 {
729 if( m_nextROI.bin_y == m_binYs[b] )
730 {
731 by = b;
732 break;
733 }
734 }
735
736 // Set ROI.
737 int xoff;
738 int yoff;
740 {
741 xoff = ( m_maxWs[bx] - 1 - m_nextROI.x ) - 0.5 * ( (float)m_nextROI.w - 1 );
742 }
743 else
744 {
745 xoff = m_nextROI.x - 0.5 * ( (float)m_nextROI.w - 1 );
746 }
747
749 {
750 yoff = ( m_maxHs[by] - 1 - m_nextROI.y ) - 0.5 * ( (float)m_nextROI.h - 1 );
751 }
752 else
753 {
754 yoff = m_nextROI.y - 0.5 * ( (float)m_nextROI.h - 1 );
755 }
756
757 m_camera->BinningHorizontal.SetValue( m_nextROI.bin_x );
758 m_camera->BinningVertical.SetValue( m_nextROI.bin_y );
759 // Probably not necessary to do it every time, but just in case:
760 m_camera->BinningHorizontalMode.SetValue( BinningHorizontalMode_Sum );
761 m_camera->BinningVerticalMode.SetValue( BinningVerticalMode_Sum );
762
763 m_camera->Width.SetValue( m_nextROI.w );
764 m_camera->Height.SetValue( m_nextROI.h );
765
766 m_camera->OffsetX.SetValue( xoff );
767 m_camera->OffsetY.SetValue( yoff );
768
769 // Read the parameter from the camera to check if parameter change is successful
770 m_currentROI.bin_x = m_camera->BinningHorizontal.GetValue();
771 m_currentROI.bin_y = m_camera->BinningVertical.GetValue();
772
773 bx = 0;
774 for( size_t b = 0; b < m_binXs.size(); ++b )
775 {
776 if( m_nextROI.bin_x == m_binXs[b] )
777 {
778 bx = b;
779 break;
780 }
781 }
782
783 by = 0;
784 for( size_t b = 0; b < m_binYs.size(); ++b )
785 {
786 if( m_nextROI.bin_y == m_binYs[b] )
787 {
788 by = b;
789 break;
790 }
791 }
792
793 m_currentROI.w = m_camera->Width.GetValue();
794 m_currentROI.h = m_camera->Height.GetValue();
795
797 {
798 m_currentROI.x = m_maxWs[bx] - 1 - ( m_camera->OffsetX.GetValue() + 0.5 * ( (float)m_currentROI.w - 1 ) );
799 }
800 else
801 {
802 m_currentROI.x = m_camera->OffsetX.GetValue() + 0.5 * ( (float)m_currentROI.w - 1 );
803 }
804
806 {
807 m_currentROI.y = m_maxHs[by] - 1 - ( m_camera->OffsetY.GetValue() + 0.5 * ( (float)m_currentROI.h - 1 ) );
808 }
809 else
810 {
811 m_currentROI.y = m_camera->OffsetY.GetValue() + 0.5 * ( (float)m_currentROI.h - 1 );
812 }
813
814 // Set the full window for this binning
816 m_full_currbin_x = 0.5 * ( (float)m_full_currbin_w - 1.0 );
818 m_full_currbin_y = 0.5 * ( (float)m_full_currbin_h - 1.0 );
819
820 // Update binning
827
828 // We also update target to the settable values
833 m_nextROI.bin_x = m_currentROI.bin_x;
834 m_nextROI.bin_y = m_currentROI.bin_y;
835
842
846
847 getFPS();
848
849 recordCamera( true );
850 }
851 catch( ... )
852 {
853 log<software_error>( { __FILE__, __LINE__, "invalid ROI specifications" } );
855 return -1;
856 }
857
858 return 0;
859}
860
862{
863 try
864 {
865 m_camera->StartGrabbing( GrabStrategy_LatestImageOnly ); // Start grabbing, and always grab just the last image.
866 }
867 catch( ... )
868 {
870 return -1;
871 }
872
874
875 return 0;
876}
877
879{
880 try
881 {
882 m_camera->RetrieveResult( 1000, ptrGrabResult, TimeoutHandling_ThrowException );
883 }
884 catch( ... )
885 {
887 return -1;
888 }
889
890 if( ptrGrabResult->GrabSucceeded() ) // If image is grabbed successfully
891 {
893 return 0;
894 }
895 else
896 {
898 return -1;
899 }
900}
901
903{
904 pixelT *src = nullptr;
905 try
906 {
907 src = reinterpret_cast<pixelT *>( ptrGrabResult->GetBuffer() );
908 }
909 catch( ... )
910 {
912 return -1;
913 }
914
915 if( src == nullptr )
916 return -1;
917
919 return -1;
920
921 return 0;
922}
923
925{
926
927 return 0;
928}
929
931{
932 if( m_camera == nullptr )
933 return 0;
934
935 try
936 {
937 float temp = m_camera->DeviceTemperature.GetValue();
938 m_tempHist.nextEntry( temp );
939
940 temp = 0;
941 int32_t N = m_tempHist.size();
942 for( int32_t n = 0; n < N; ++n )
943 {
944 temp += m_tempHist[n];
945 }
946 temp /= N;
947 m_ccdTemp = temp;
948 recordCamera();
949 }
950 catch( ... )
951 {
952 m_ccdTemp = -999;
953 recordCamera();
955 return -1;
956 }
957
958 return 0;
959}
960
962{
963 if( m_camera == nullptr )
964 return 0;
965
966 try
967 {
968 m_expTime = (float)m_camera->ExposureTime.GetValue() / 1e6;
969 recordCamera();
970 }
971 catch( ... )
972 {
973 m_expTime = -999;
974 recordCamera();
976 return -1;
977 }
978
979 return 0;
980}
981
983{
984 if( m_camera == nullptr )
985 return 0;
986
987 try
988 {
989 m_fps = m_camera->ResultingFrameRate.GetValue();
990 recordCamera();
991 }
992 catch( ... )
993 {
994 m_fps = -999;
995 recordCamera();
997 return -1;
998 }
999
1000 return 0;
1001}
1002
1003inline float baslerCtrl::fps()
1004{
1005 return m_fps;
1006}
1007
1009{
1014 m_nextROI.bin_x = m_default_bin_x;
1015 m_nextROI.bin_y = m_default_bin_y;
1016
1017 return 0;
1018}
1019
1021{
1022 if( m_camera == nullptr )
1023 return 0;
1024
1025 recordCamera( true );
1026
1027 if( m_fpsSet == 0 )
1028 {
1029 try
1030 {
1031 m_camera->AcquisitionFrameRateEnable.SetValue( false );
1032 }
1033 catch( ... )
1034 {
1035 return log<software_error, -1>( { __FILE__, __LINE__, "Error disabling frame rate limit." } );
1036 }
1037 }
1038 else
1039 {
1040 try
1041 {
1042 m_camera->AcquisitionFrameRateEnable.SetValue( true );
1043 m_camera->AcquisitionFrameRate.SetValue( m_fpsSet );
1044 }
1045 catch( ... )
1046 {
1047 return log<software_error, -1>( { __FILE__, __LINE__, "Error setting frame rate limit." } );
1048 }
1049 }
1050
1051 return 0;
1052}
1053
1055{
1056 if( m_camera == nullptr )
1057 return 0;
1058
1059 try
1060 {
1061 recordCamera( true );
1062 m_camera->ExposureTime.SetValue( m_expTimeSet * 1e6 );
1063 }
1064 catch( ... )
1065 {
1066 log<software_error>( { __FILE__, __LINE__, "Error setting exposure time" } );
1067 return -1;
1068 }
1069
1070 log<text_log>( "Set exposure time: " + std::to_string( m_expTimeSet ) + " sec" );
1071
1072 return 0;
1073}
1074
1076{
1077 std::cerr << "checkNextROI!\n";
1078
1079 // First find binning indices
1080 size_t bx = 0;
1081 for( size_t b = 0; b < m_binXs.size(); ++b )
1082 {
1083 if( m_nextROI.bin_x == m_binXs[b] )
1084 {
1085 bx = b;
1086 break;
1087 }
1088 }
1089 std::cerr << "req bin_x: " << m_nextROI.bin_x << " " << "adj bin_x: " << m_binXs[bx] << "\n";
1090 m_nextROI.bin_x = m_binXs[bx]; // In case no valid value was found.
1091
1092 size_t by = 0;
1093 for( size_t b = 0; b < m_binYs.size(); ++b )
1094 {
1095 if( m_nextROI.bin_y == m_binYs[b] )
1096 {
1097 by = b;
1098 break;
1099 }
1100 }
1101 std::cerr << "req bin_y: " << m_nextROI.bin_y << " " << "adj bin_y: " << m_binYs[by] << "\n";
1102 m_nextROI.bin_y = m_binYs[by]; // In case no valid value was found.
1103
1104 // Next check width
1105 //-- round to nearest increment
1106 //-- check limits
1107 int w = m_nextROI.w;
1108 int rw = w % m_incWs[bx];
1109 if( rw < 0.5 * m_incWs[bx] )
1110 w -= rw;
1111 else
1112 w += m_incWs[bx] - rw;
1113
1114 if( w < m_minWs[bx] )
1115 w = m_minWs[bx];
1116 else if( w > m_maxWs[bx] )
1117 w = m_maxWs[bx];
1118
1119 std::cerr << "req w: " << m_nextROI.w << " " << "adj w: " << w << "\n";
1120 m_nextROI.w = w;
1121
1122 // Now check x
1123 //-- calculate offset from center
1124 //-- round to nearest increment
1125 //-- recalculate center
1126 int x;
1128 {
1129 x = ( m_maxWs[bx] - 1 - m_nextROI.x ) - 0.5 * ( (float)w - 1 );
1130 }
1131 else
1132 {
1133 x = m_nextROI.x - 0.5 * ( (float)w - 1 );
1134 }
1135
1136 int rx = x % m_incXs[bx];
1137 if( rx < 0.5 * m_incXs[bx] )
1138 x -= rx;
1139 else
1140 x += m_incXs[bx] - rx;
1141
1142 if( x < 0 )
1143 x = 0;
1144 else if( x > m_maxWs[bx] - w )
1145 x = m_maxWs[bx] - w;
1146
1147 std::cerr << "req x: " << m_nextROI.x;
1149 {
1150 m_nextROI.x = m_maxWs[bx] - 1 - ( x + 0.5 * ( (float)w - 1.0 ) );
1151 }
1152 else
1153 {
1154 m_nextROI.x = x + 0.5 * ( (float)w - 1.0 );
1155 }
1156 std::cerr << " adj x: " << m_nextROI.x << "\n";
1157
1158 // Next check height
1159 //-- round to nearest increment
1160 //-- check limits
1161 int h = m_nextROI.h;
1162 int rh = h % m_incHs[by];
1163 if( rh < 0.5 * m_incHs[by] )
1164 h -= rh;
1165 else
1166 h += m_incHs[by] - rh;
1167
1168 if( h < m_minHs[by] )
1169 h = m_minHs[by];
1170 else if( h > m_maxHs[by] )
1171 h = m_maxHs[by];
1172
1173 std::cerr << "req h: " << m_nextROI.h << " " << "adj h: " << h << "\n";
1174 m_nextROI.h = h;
1175
1176 // Now check y
1177 //-- calculate offset from center
1178 //-- round to nearest increment
1179 //-- recalculate center
1180 int y;
1182 {
1183 y = ( m_maxHs[by] - 1 - m_nextROI.y ) - 0.5 * ( (float)h - 1 );
1184 }
1185 else
1186 {
1187 y = m_nextROI.y - 0.5 * ( (float)h - 1 );
1188 }
1189
1190 int ry = y % m_incYs[by];
1191 if( ry < 0.5 * m_incYs[by] )
1192 y -= ry;
1193 else
1194 y += m_incYs[by] - ry;
1195
1196 if( y < 0 )
1197 y = 0;
1198 else if( y > m_maxHs[by] - h )
1199 y = m_maxHs[by] - h;
1200
1201 std::cerr << "req y: " << m_nextROI.y;
1203 {
1204 m_nextROI.y = m_maxHs[by] - 1 - ( y + 0.5 * ( (float)h - 1 ) );
1205 }
1206 else
1207 {
1208 m_nextROI.y = y + 0.5 * ( (float)h - 1 );
1209 }
1210 std::cerr << " adj y: " << m_nextROI.y << "\n";
1211
1212 try
1213 {
1220
1221 return 0;
1222 }
1223 catch( const std::exception &e )
1224 {
1225 return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
1226 }
1227}
1228
1230{
1231 std::cerr << "setNextROI:\n";
1232 std::cerr << " m_nextROI.x = " << m_nextROI.x << "\n";
1233 std::cerr << " m_nextROI.y = " << m_nextROI.y << "\n";
1234 std::cerr << " m_nextROI.w = " << m_nextROI.w << "\n";
1235 std::cerr << " m_nextROI.h = " << m_nextROI.h << "\n";
1236 std::cerr << " m_nextROI.bin_x = " << m_nextROI.bin_x << "\n";
1237 std::cerr << " m_nextROI.bin_y = " << m_nextROI.bin_y << "\n";
1238
1239 m_reconfig = true;
1240
1241 updateSwitchIfChanged( m_indiP_roi_set, "request", pcf::IndiElement::Off, INDI_IDLE );
1242 updateSwitchIfChanged( m_indiP_roi_full, "request", pcf::IndiElement::Off, INDI_IDLE );
1243 updateSwitchIfChanged( m_indiP_roi_last, "request", pcf::IndiElement::Off, INDI_IDLE );
1244 updateSwitchIfChanged( m_indiP_roi_default, "request", pcf::IndiElement::Off, INDI_IDLE );
1245 return 0;
1246}
1247
1249{
1250 std::string ss;
1251
1252 ss += std::to_string( m_currentROI.x ) + "_" + std::to_string( m_currentROI.y ) + "_";
1253 ss += std::to_string( m_currentROI.w ) + "x" + std::to_string( m_currentROI.h ) + "_";
1254 ss += std::to_string( m_currentROI.bin_x ) + "x" + std::to_string( m_currentROI.bin_y ) + "_";
1255 ss += std::to_string( m_expTime ) + "_";
1256 ss += std::to_string( floor( m_ccdTemp + 0.5 ) );
1257
1258 return ss;
1259}
1260
1262{
1263 return true;
1264}
1265
1270
1272{
1273 return recordCamera( true );
1274}
1275
1276} // namespace app
1277} // namespace MagAOX
1278#endif
Pylon::CBaslerUsbInstantCamera Camera_t
int16_t pixelT
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
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.
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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int setFPS()
Set the framerate.
~baslerCtrl() noexcept
Destructor.
virtual int appStartup()
Startup functions.
static constexpr bool c_stdCamera_exptimeCtrl
app::dev config to tell stdCamera to expose exposure time controls
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
baslerCtrl()
Default c'tor.
static constexpr bool c_stdCamera_cropMode
app:dev config to tell stdCamera not to expose Crop Mode controls
static constexpr bool c_stdCamera_emGain
app::dev config to tell stdCamera to not expose EM gain controls
static constexpr bool c_stdCamera_fpsCtrl
app::dev config to tell stdCamera to expose FPS controls
int m_bits
The number of bits used by the camera.
static constexpr bool c_stdCamera_readoutSpeed
app::dev config to tell stdCamera not to expose readout speed controls
std::vector< int > m_minWs
The minimum value of the width for each X-binning.
static constexpr bool c_stdCamera_fps
app::dev config to tell stdCamera not to expose FPS status (ignored since fpsCtrl=true)
static constexpr bool c_stdCamera_hasShutter
app:dev config to tell stdCamera to expose shutter controls
int setExpTime()
Set the Exposure Time. [stdCamera interface].
static constexpr bool c_stdCamera_usesStateString
app::dev confg to tell stdCamera to expose the state string property
static constexpr bool c_stdCamera_vShiftSpeed
app:dev config to tell stdCamera not to expose vertical shift speed control
std::vector< int > m_maxWs
The minimum value of the width for each X-binning.
int getTemp()
Get the current detector temperature.
static constexpr bool c_stdCamera_synchro
app::dev config to tell stdCamera to not expose synchro mode controls
static constexpr bool c_stdCamera_temp
app::dev config to tell stdCamera to expose temperature
int recordTelem(const telem_stdcam *)
static constexpr bool c_stdCamera_usesModes
app:dev config to tell stdCamera not to expose mode controls
static constexpr bool c_stdCamera_usesROI
app:dev config to tell stdCamera to expose ROI controls
int checkNextROI()
Check the next ROI.
CBaslerUsbInstantCamera * m_camera
The library camera handle.
CGrabResultPtr ptrGrabResult
The result of an attempt to grab an image.
std::vector< int > m_maxHs
The minimum value of the height for each Y-binning.
std::vector< int > m_incYs
The allowed increment in Y for each Y-binning.
std::vector< int > m_binXs
The allowed values of binning in X (horizontal)
int setNextROI()
Set the next ROI.
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber that this camera can be flipped
static constexpr bool c_stdCamera_tempControl
app::dev config to tell stdCamera to not expose temperature controls
int getExpTime()
Get the current exposure time.
std::vector< int > m_incHs
The minimum value of the height for each Y-binning.
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
int getFPS()
Get the current framerate.
virtual int appLogic()
Implementation of the FSM for the Siglent SDG.
int loadImageIntoStream(void *dest)
std::vector< int > m_incWs
The minimum value of the width for each X-binning.
std::string m_serialNumber
The camera's identifying serial number.
std::vector< int > m_incXs
The allowed increment in X for each X-binning.
int powerOnDefaults()
Set defaults for a power on state.
std::vector< int > m_binYs
The allowed values of binning in Y (vertical)
mx::sigproc::circularBufferIndex< float, int32_t > m_tempHist
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
std::vector< int > m_minHs
The minimum value of the height for each Y-binning.
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
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_fpsSet
The commanded fps, as set by user.
pcf::IndiProperty m_indiP_roi_y
Property used to set the ROI x center coordinate.
int m_full_currbin_w
The current-binning full ROI width.
float m_default_x
Power-on ROI center x coordinate.
float m_full_currbin_x
The current-binning full ROI center x coordinate.
float m_expTime
The current exposure time, in seconds.
int m_default_bin_x
Power-on ROI x binning.
pcf::IndiProperty m_indiP_roi_last
Property used to trigger setting the last ROI.
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.
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_default
Property used to trigger setting the default and startup ROI.
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 m_full_currbin_h
The current-binning full ROI height.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
float m_ccdTemp
The current temperature, in C.
float m_full_currbin_y
The current-binning full ROI center y coordinate.
pcf::IndiProperty m_indiP_roi_full
Property used to trigger setting the full ROI.
pcf::IndiProperty m_indiP_roi_set
Property used to trigger setting the ROI.
int appShutdown()
Application shutdown.
float m_default_y
Power-on ROI center y coordinate.
pcf::IndiProperty m_indiP_roi_bin_y
Property used to set the ROI y binning.
pcf::IndiProperty m_indiP_roi_x
Property used to set the ROI x center coordinate.
int m_default_bin_y
Power-on ROI y binning.
@ 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.
@ info
For information only.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_OK
Definition indiUtils.hpp:28
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:26
A device base class which saves telemetry.
Definition telemeter.hpp:69
int appShutdown()
Perform telemeter application shutdown.
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.