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
64
65 friend class dev::stdCamera<baslerCtrl>;
66 friend class dev::frameGrabber<baslerCtrl>;
67 friend class dev::telemeter<baslerCtrl>;
68
69 public:
70 /** \name app::dev Configurations
71 *@{
72 */
73 static constexpr bool c_stdCamera_tempControl =
74 false; ///< app::dev config to tell stdCamera to not expose temperature controls
75
76 static constexpr bool c_stdCamera_temp = true; ///< app::dev config to tell stdCamera to expose temperature
77
78 static constexpr bool c_stdCamera_readoutSpeed =
79 false; ///< app::dev config to tell stdCamera not to expose readout speed controls
80
81 static constexpr bool c_stdCamera_vShiftSpeed =
82 false; ///< app:dev config to tell stdCamera not to expose vertical shift speed control
83
84 static constexpr bool c_stdCamera_emGain =
85 false; ///< app::dev config to tell stdCamera to not expose EM gain controls
86
87 static constexpr bool c_stdCamera_exptimeCtrl =
88 true; ///< app::dev config to tell stdCamera to expose exposure time controls
89
90 static constexpr bool c_stdCamera_fpsCtrl = true; ///< app::dev config to tell stdCamera to expose FPS controls
91
92 static constexpr bool c_stdCamera_fps =
93 true; ///< app::dev config to tell stdCamera not to expose FPS status (ignored since fpsCtrl=true)
94
95 static constexpr bool c_stdCamera_synchro =
96 false; ///< app::dev config to tell stdCamera to not expose synchro mode controls
97
98 static constexpr bool c_stdCamera_usesModes =
99 false; ///< app:dev config to tell stdCamera not to expose mode controls
100
101 static constexpr bool c_stdCamera_usesROI = true; ///< app:dev config to tell stdCamera to expose ROI controls
102
103 static constexpr bool c_stdCamera_cropMode =
104 false; ///< app:dev config to tell stdCamera not to expose Crop Mode controls
105
106 static constexpr bool c_stdCamera_hasShutter =
107 false; ///< app:dev config to tell stdCamera to expose shutter controls
108
109 static constexpr bool c_stdCamera_usesStateString =
110 true; ///< app::dev confg to tell stdCamera to expose the state string property
111
112 static constexpr bool c_frameGrabber_flippable =
113 true; ///< app:dev config to tell framegrabber that this camera can be flipped
114
115 ///@}
116
117 protected:
118 /** \name configurable parameters
119 *@{
120 */
121 std::string m_serialNumber; ///< The camera's identifying serial number
122
123 int m_bits{ 10 }; ///< The number of bits used by the camera.
124
125 ///@}
126
127 /** \name binning allowed values
128 * @{
129 */
130 std::vector<int> m_binXs; ///< The allowed values of binning in X (horizontal)
131 std::vector<int> m_binYs; ///< The allowed values of binning in Y (vertical)
132
133 std::vector<int> m_incXs; ///< The allowed increment in X for each X-binning
134
135 std::vector<int> m_minWs; ///< The minimum value of the width for each X-binning
136 std::vector<int> m_incWs; ///< The minimum value of the width for each X-binning
137 std::vector<int> m_maxWs; ///< The minimum value of the width for each X-binning
138
139 std::vector<int> m_incYs; ///< The allowed increment in Y for each Y-binning
140
141 std::vector<int> m_minHs; ///< The minimum value of the height for each Y-binning
142 std::vector<int> m_incHs; ///< The minimum value of the height for each Y-binning
143 std::vector<int> m_maxHs; ///< The minimum value of the height for each Y-binning
144
145 ///@}
146
147 CBaslerUsbInstantCamera *m_camera{ nullptr }; ///< The library camera handle
148 CGrabResultPtr ptrGrabResult; ///< The result of an attempt to grab an image
149
150 mx::sigproc::circularBufferIndex<float, int32_t> m_tempHist;
151
152 public:
153 /// Default c'tor
154 baslerCtrl();
155
156 /// Destructor
158
159 /// Setup the configuration system (called by MagAOXApp::setup())
160 virtual void setupConfig();
161
162 /// Implementation of loadConfig logic, separated for testing.
163 /** This is called by loadConfig().
164 */
165 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
166 from which to load values*/
167 );
168
169 /// load the configuration system results (called by MagAOXApp::setup())
170 virtual void loadConfig();
171
172 /// Startup functions
173 /** Sets up the INDI vars.
174 *
175 */
176 virtual int appStartup();
177
178 /// Implementation of the FSM for the Siglent SDG
179 virtual int appLogic();
180
181 /// Do any needed shutdown tasks. Currently nothing in this app.
182 virtual int appShutdown();
183
184 int connect();
185
187 int startAcquisition();
189 int loadImageIntoStream( void *dest );
190 int reconfig();
191
192 protected:
193 /// Get the current detector temperature
194 /**
195 * \returns 0 on success
196 * \returns -1 on an error.
197 */
198 int getTemp();
199
200 /// Get the current exposure time
201 /**
202 * \returns 0 on success
203 * \returns -1 on an error.
204 */
205 int getExpTime();
206
207 /// Get the current framerate
208 /**
209 * \returns 0 on success
210 * \returns -1 on an error.
211 */
212 int getFPS();
213
214 float fps();
215
216 /** \name stdCamera Interface
217 *
218 * @{
219 */
220
221 /// Set defaults for a power on state.
222 /**
223 * \returns 0 on success
224 * \returns -1 on error
225 */
226 int powerOnDefaults();
227
228 /// Set the framerate.
229 /** This uses the acquistion framerate feature. If m_fpsSet is 0, acuisition framerate is disabled
230 * and the resultant framerate is based solely on exposure time and ROI. If non-zero, then the
231 * framerate will be set to m_fpsSet and the camera will maintain this (as long as exposure time
232 * and ROI allow).
233 *
234 * \returns 0 always
235 */
236 int setFPS();
237
238 /// Set the Exposure Time. [stdCamera interface]
239 /** Sets the frame rate to m_expTimeSet.
240 *
241 * \returns 0 on success
242 * \returns -1 on error
243 */
244 int setExpTime();
245
246 /// Check the next ROI
247 /** Checks if the target values are valid and adjusts them to the closest valid values if needed.
248 *
249 * \returns 0 always
250 */
251 int checkNextROI();
252
253 /// Set the next ROI
254 /**
255 * \returns 0 always
256 */
257 int setNextROI();
258
259 std::string stateString();
260
261 bool stateStringValid();
262
263 ///@}
264
265 /** \name Telemeter Interface
266 *
267 * @{
268 */
269
270 int checkRecordTimes();
271
273
274 ///@}
275};
276
278{
279 m_powerMgtEnabled = false;
280
281 m_full_x = 335.5;
282 m_full_y = 255.5;
283 m_full_w = 672;
284 m_full_h = 512;
285
286 return;
287}
288
290{
291 return;
292}
293
295{
296
297 config.add( "camera.serialNumber",
298 "",
299 "camera.serialNumber",
300 argType::Required,
301 "camera",
302 "serialNumber",
303 false,
304 "int",
305 "The identifying serial number of the camera." );
306
307 config.add( "camera.bits",
308 "",
309 "camera.bits",
310 argType::Required,
311 "camera",
312 "bits",
313 false,
314 "int",
315 "The number of bits used by the camera. Default is 10." );
316
317 STDCAMERA_SETUP_CONFIG( config );
318
320
321 TELEMETER_SETUP_CONFIG( config );
322}
323
324int baslerCtrl::loadConfigImpl( mx::app::appConfigurator &_config )
325{
326 config( m_serialNumber, "camera.serialNumber" );
327 config( m_bits, "camera.bits" );
328
330
332
334
335 return 0;
336}
337
339{
340 if( loadConfigImpl( config ) < 0 )
341 {
342 log<software_critical>( { __FILE__, __LINE__, "error loading config" } );
343 m_shutdown = 1;
344 }
345}
346
348{
349 PylonInitialize(); // Initializes pylon runtime before using any pylon methods
350
352
354
356
357 m_tempHist.maxEntries( 30 );
358
360
361 return 0;
362}
363
365{
367
369
371 {
372 std::unique_lock<std::mutex> lock( m_indiMutex );
373 if( connect() < 0 )
374 {
376 }
377
379 {
380 return 0;
381 }
382 }
383
385 {
386 // Get a lock
387 std::unique_lock<std::mutex> lock( m_indiMutex );
388
390 }
391
393 {
394 // Get a lock if we can
395 std::unique_lock<std::mutex> lock( m_indiMutex, std::try_to_lock );
396
397 // but don't wait for it, just go back around.
398 if( !lock.owns_lock() )
399 {
400 return 0;
401 }
402
403 if( getTemp() < 0 )
404 {
406 {
408 }
409
410 return 0;
411 }
412
413 if( getExpTime() < 0 )
414 {
416 {
418 }
419
420 return 0;
421 }
422
423 if( getFPS() < 0 )
424 {
426 {
428 }
429
430 return 0;
431 }
432
434
436
438 }
439
440 ///\todo Fall through check?
441
442 return 0;
443}
444
446{
448
450
451 if( m_camera )
452 {
453 m_camera->Close();
454 }
455
457
459
460 return 0;
461}
462
464{
466 // info.SetDeviceClass(Camera_t::DeviceClass());
467 info.SetSerialNumber( m_serialNumber.c_str() );
468
469 try
470 {
471 if( m_camera )
472 {
473 m_camera->Close();
474 delete m_camera;
475 }
476 m_camera = nullptr;
477
478 m_camera = new CBaslerUsbInstantCamera( CTlFactory::GetInstance().CreateFirstDevice( info ) );
479 }
480 catch( ... )
481 {
482 if( m_camera )
483 {
484 m_camera->Close();
485 delete m_camera;
486 }
487 m_camera = nullptr;
488
490 if( !stateLogged() )
491 {
492 log<text_log>( "no camera with serial number " + m_serialNumber + " found." );
493 }
494 return 0;
495 }
496
497 try
498 {
499 if( m_shmimName == "" )
500 {
502 (std::string)m_camera->GetDeviceInfo().GetModelName() + "_" +
503 (std::string)m_camera->GetDeviceInfo().GetSerialNumber(); // Gets m_camera model name and serial number
504 }
505
506 m_camera->RegisterConfiguration(
508
509 m_camera->Open(); // Opens camera parameters to grab images and set exposure time
510 }
511 catch( ... )
512 {
513 if( m_camera )
514 {
515 m_camera->Close();
516 delete m_camera;
517 }
518 m_camera = nullptr;
519
521 if( !stateLogged() )
522 {
523 log<text_log>( "error opening camera " + m_serialNumber + "." );
524 }
525 return -1;
526 }
527
528 try
529 {
530 m_camera->ExposureAuto.SetValue( ExposureAuto_Off );
531 }
532 catch( ... )
533 {
534 if( m_camera )
535 {
536 m_camera->Close();
537 delete m_camera;
538 }
539 m_camera = nullptr;
540
542 if( !stateLogged() )
543 {
544 log<text_log>( "failed to set exposure auto off for camera " + m_serialNumber );
545 }
546 return -1;
547 }
548
549 try
550 {
551 if( m_bits == 8 )
552 {
553 m_camera->PixelFormat.SetValue( PixelFormat_Mono8 );
554 }
555 else if( m_bits == 10 )
556 {
557 m_camera->PixelFormat.SetValue( PixelFormat_Mono10 ); // Set to 10 bits
558 }
559 else if( m_bits == 12 )
560 {
561 m_camera->PixelFormat.SetValue( PixelFormat_Mono12 );
562 }
563 else
564 {
565 log<text_log>( "unsupported bit depth for camera" + m_serialNumber + "" );
566 }
567 }
568 catch( ... )
569 {
570 if( m_camera )
571 {
572 m_camera->Close();
573 delete m_camera;
574 }
575 m_camera = nullptr;
576
578 if( !stateLogged() )
579 {
580 log<text_log>( "failed to set bit depth for camera" + m_serialNumber + "" );
581 }
582 return -1;
583 }
584
586 if( !stateLogged() )
587 {
588 log<text_log>( "Found camera of type " + (std::string)m_camera->GetDeviceInfo().GetModelName() +
589 " with serial number " + m_serialNumber + "." );
590 log<text_log>( "Using shared memory name " + m_shmimName + "." );
591 }
592
593 m_camera->BinningHorizontalMode.SetValue( BinningHorizontalMode_Sum );
594 m_camera->BinningVerticalMode.SetValue( BinningVerticalMode_Sum );
595
596 // -- Here we interrogate the camera to find valid ROI settings -- //
597
598 // Stop the camera and cycle through settings to get limits for each binning
599 m_camera->StopGrabbing();
600 m_camera->OffsetX.SetValue( 0 ); // ensure that all values are valid
601 m_camera->OffsetY.SetValue( 0 );
602
603 int minb = m_camera->BinningHorizontal.GetMin();
604 int incb = m_camera->BinningHorizontal.GetInc();
605 int maxb = m_camera->BinningHorizontal.GetMax();
606
607 m_binXs.clear();
608 for( int b = minb; b <= maxb; b += incb )
609 m_binXs.push_back( b );
610
611 minb = m_camera->BinningVertical.GetMin();
612 incb = m_camera->BinningVertical.GetInc();
613 maxb = m_camera->BinningVertical.GetMax();
614
615 m_binYs.clear();
616 for( int b = minb; b <= maxb; b += incb )
617 m_binYs.push_back( b );
618
619 m_incXs.clear();
620 m_minWs.clear();
621 m_incWs.clear();
622 m_maxWs.clear();
623 for( size_t b = 0; b < m_binXs.size(); ++b )
624 {
625 m_camera->BinningHorizontal.SetValue( m_binXs[b] );
626 m_camera->BinningVertical.SetValue( m_binYs[0] );
627
628 m_incXs.push_back( m_camera->OffsetX.GetInc() );
629 m_minWs.push_back( m_camera->Width.GetMin() );
630 m_incWs.push_back( m_camera->Width.GetInc() );
631 m_maxWs.push_back( m_camera->Width.GetMax() );
632
633 /*//Leave for troubleshooting:
634 std::cerr << "--------------------\nH-binning: " << m_binXs[b] << "\n";
635 std::cerr << "OffsetX: " << 1 << " " << m_camera->OffsetX.GetInc() << " " << m_camera->Width.GetMax() -
636 m_camera->Width.GetMin() << "\n"; std::cerr << "Width: " << m_camera->Width.GetMin() << " " <<
637 m_camera->Width.GetInc() << " " << m_camera->Width.GetMax() << "\n"; std::cerr << "OffsetY: " << 1 << " " <<
638 m_camera->OffsetY.GetInc() << " " << m_camera->Height.GetMax() - m_camera->Height.GetMin() << "\n"; std::cerr <<
639 "Height: " << m_camera->Height.GetMin() << " " << m_camera->Height.GetInc() << " " << m_camera->Height.GetMax()
640 << "\n";
641 */
642 }
643
644 m_incYs.clear();
645 m_minHs.clear();
646 m_incHs.clear();
647 m_maxHs.clear();
648 for( size_t b = 0; b < m_binYs.size(); ++b )
649 {
650 m_camera->BinningHorizontal.SetValue( m_binXs[0] );
651 m_camera->BinningVertical.SetValue( m_binYs[b] );
652
653 m_incYs.push_back( m_camera->OffsetX.GetInc() );
654 m_minHs.push_back( m_camera->Height.GetMin() );
655 m_incHs.push_back( m_camera->Height.GetInc() );
656 m_maxHs.push_back( m_camera->Height.GetMax() );
657
658 /*//Leave for troubleshooting:
659 std::cerr << "--------------------\nV-binning: " << m_binYs[b] << "\n";
660 std::cerr << "OffsetX: " << 1 << " " << m_camera->OffsetX.GetInc() << " " << m_camera->Width.GetMax() -
661 m_camera->Width.GetMin() << "\n"; std::cerr << "Width: " << m_camera->Width.GetMin() << " " <<
662 m_camera->Width.GetInc() << " " << m_camera->Width.GetMax() << "\n"; std::cerr << "OffsetY: " << 1 << " " <<
663 m_camera->OffsetY.GetInc() << " " << m_camera->Height.GetMax() - m_camera->Height.GetMin() << "\n"; std::cerr <<
664 "Height: " << m_camera->Height.GetMin() << " " << m_camera->Height.GetInc() << " " << m_camera->Height.GetMax()
665 << "\n";
666 */
667 }
668
669 if( m_full_w != m_camera->SensorWidth.GetValue() )
670 {
671 return log<software_critical, -1>( { __FILE__, __LINE__, "full ROI w (camera.full_w) mismatch with camera" } );
672 }
673
674 if( m_full_h != m_camera->SensorHeight.GetValue() )
675 {
676 return log<software_critical, -1>( { __FILE__, __LINE__, "full ROI h (camera.full_h) mismatch with camera" } );
677 }
678
679 if( m_full_x != 0.5 * ( (float)m_full_w - 1.0 ) )
680 {
681 return log<software_critical, -1>( { __FILE__, __LINE__, "full ROI x (camera.full_x) mismatch with camera" } );
682 }
683
684 if( m_full_y != 0.5 * ( (float)m_full_h - 1.0 ) )
685 {
686 return log<software_critical, -1>( { __FILE__, __LINE__, "full ROI y (camera.full_y) mismatch with camera" } );
687 }
688
689 return 0;
690}
691
693{
694 if( !m_camera )
695 {
696 return -1;
697 }
698
699 try
700 {
701 recordCamera( true );
702 m_camera->StopGrabbing();
703 /*
704 The CenterX/Y has to be set to false otherwise the software tries to auto-center the frames.
705 See: https://docs.baslerweb.com/image-roi
706 */
707 m_camera->CenterX.SetValue( false );
708 m_camera->CenterY.SetValue( false );
709
710 // set offsets to 0 so any valid w/h will work.
711 m_camera->OffsetX.SetValue( 0 );
712 m_camera->OffsetY.SetValue( 0 );
713
714 if( checkNextROI() < 0 )
715 {
716 log<software_error>( { __FILE__, __LINE__, "error from checkNextROI()" } );
717 return -1;
718 }
719
720 // Note: assuming checkNextROI has adjusted m_nextROI to valid values, so not doing any checks
721 // First find binning indices
722 size_t bx = 0;
723 for( size_t b = 0; b < m_binXs.size(); ++b )
724 {
725 if( m_nextROI.bin_x == m_binXs[b] )
726 {
727 bx = b;
728 break;
729 }
730 }
731
732 size_t by = 0;
733 for( size_t b = 0; b < m_binYs.size(); ++b )
734 {
735 if( m_nextROI.bin_y == m_binYs[b] )
736 {
737 by = b;
738 break;
739 }
740 }
741
742 // Set ROI.
743 int xoff;
744 int yoff;
746 {
747 xoff = ( m_maxWs[bx] - 1 - m_nextROI.x ) - 0.5 * ( (float)m_nextROI.w - 1 );
748 }
749 else
750 {
751 std::cerr << "m_nextROI.x: " << m_nextROI.x << " m_nextROI.w:" << m_nextROI.w << '\n';
752 xoff = m_nextROI.x - 0.5 * ( (float)m_nextROI.w - 1 );
753 }
754
756 {
757 yoff = ( m_maxHs[by] - 1 - m_nextROI.y ) - 0.5 * ( (float)m_nextROI.h - 1 );
758 }
759 else
760 {
761 std::cerr << "m_nextROI.y: " << m_nextROI.y << " m_nextROI.h:" << m_nextROI.h << '\n';
762 yoff = m_nextROI.y - 0.5 * ( (float)m_nextROI.h - 1 );
763 }
764
765 m_camera->BinningHorizontal.SetValue( m_nextROI.bin_x );
766 m_camera->BinningVertical.SetValue( m_nextROI.bin_y );
767 // Probably not necessary to do it every time, but just in case:
768 m_camera->BinningHorizontalMode.SetValue( BinningHorizontalMode_Sum );
769 m_camera->BinningVerticalMode.SetValue( BinningVerticalMode_Sum );
770
771 m_camera->Width.SetValue( m_nextROI.w );
772 m_camera->Height.SetValue( m_nextROI.h );
773
774 std::cerr << "xoff: " << xoff << " yoff: " << yoff << '\n';
775
776 m_camera->OffsetX.SetValue( xoff );
777 m_camera->OffsetY.SetValue( yoff );
778
779 // Read the parameter from the camera to check if parameter change is successful
780 m_currentROI.bin_x = m_camera->BinningHorizontal.GetValue();
781 m_currentROI.bin_y = m_camera->BinningVertical.GetValue();
782
783 bx = 0;
784 for( size_t b = 0; b < m_binXs.size(); ++b )
785 {
786 if( m_nextROI.bin_x == m_binXs[b] )
787 {
788 bx = b;
789 break;
790 }
791 }
792
793 by = 0;
794 for( size_t b = 0; b < m_binYs.size(); ++b )
795 {
796 if( m_nextROI.bin_y == m_binYs[b] )
797 {
798 by = b;
799 break;
800 }
801 }
802
803 m_currentROI.w = m_camera->Width.GetValue();
804 m_currentROI.h = m_camera->Height.GetValue();
805
807 {
808 m_currentROI.x = m_maxWs[bx] - 1 - ( m_camera->OffsetX.GetValue() + 0.5 * ( (float)m_currentROI.w - 1 ) );
809 }
810 else
811 {
812 m_currentROI.x = m_camera->OffsetX.GetValue() + 0.5 * ( (float)m_currentROI.w - 1 );
813 }
814
816 {
817 m_currentROI.y = m_maxHs[by] - 1 - ( m_camera->OffsetY.GetValue() + 0.5 * ( (float)m_currentROI.h - 1 ) );
818 }
819 else
820 {
821 m_currentROI.y = m_camera->OffsetY.GetValue() + 0.5 * ( (float)m_currentROI.h - 1 );
822 }
823
824 // Set the full window for this binning
826 m_full_currbin_x = 0.5 * ( (float)m_full_currbin_w - 1.0 );
828 m_full_currbin_y = 0.5 * ( (float)m_full_currbin_h - 1.0 );
829
830 // Update binning
837
838 // We also update target to the settable values
843 m_nextROI.bin_x = m_currentROI.bin_x;
844 m_nextROI.bin_y = m_currentROI.bin_y;
845
852
856
857 getFPS();
858
859 recordCamera( true );
860 }
861 catch( ... )
862 {
863 log<software_error>( { __FILE__, __LINE__, "invalid ROI specifications" } );
865 return -1;
866 }
867
868 return 0;
869}
870
872{
873 try
874 {
875 m_camera->StartGrabbing( GrabStrategy_LatestImageOnly ); // Start grabbing, and always grab just the last image.
876 }
877 catch( ... )
878 {
880 return -1;
881 }
882
884
885 return 0;
886}
887
889{
890 try
891 {
892 m_camera->RetrieveResult( 1000, ptrGrabResult, TimeoutHandling_ThrowException );
893 }
894 catch( ... )
895 {
897 return -1;
898 }
899
900 if( ptrGrabResult->GrabSucceeded() ) // If image is grabbed successfully
901 {
903 return 0;
904 }
905 else
906 {
908 return -1;
909 }
910}
911
913{
914 pixelT *src = nullptr;
915 try
916 {
917 src = reinterpret_cast<pixelT *>( ptrGrabResult->GetBuffer() );
918 }
919 catch( ... )
920 {
922 return -1;
923 }
924
925 if( src == nullptr )
926 return -1;
927
929 return -1;
930
931 return 0;
932}
933
935{
936
937 return 0;
938}
939
941{
942 if( m_camera == nullptr )
943 return 0;
944
945 try
946 {
947 float temp = m_camera->DeviceTemperature.GetValue();
948 m_tempHist.nextEntry( temp );
949
950 temp = 0;
951 int32_t N = m_tempHist.size();
952 for( int32_t n = 0; n < N; ++n )
953 {
954 temp += m_tempHist[n];
955 }
956 temp /= N;
957 m_ccdTemp = temp;
958 recordCamera();
959 }
960 catch( ... )
961 {
962 m_ccdTemp = -999;
963 recordCamera();
965 return -1;
966 }
967
968 return 0;
969}
970
972{
973 if( m_camera == nullptr )
974 return 0;
975
976 try
977 {
978 m_expTime = (float)m_camera->ExposureTime.GetValue() / 1e6;
979 recordCamera();
980 }
981 catch( ... )
982 {
983 m_expTime = -999;
984 recordCamera();
986 return -1;
987 }
988
989 return 0;
990}
991
993{
994 if( m_camera == nullptr )
995 return 0;
996
997 try
998 {
999 m_fps = m_camera->ResultingFrameRate.GetValue();
1000 recordCamera();
1001 }
1002 catch( ... )
1003 {
1004 m_fps = -999;
1005 recordCamera();
1007 return -1;
1008 }
1009
1010 return 0;
1011}
1012
1013inline float baslerCtrl::fps()
1014{
1015 return m_fps;
1016}
1017
1019{
1020 /*m_nextROI.x = m_default_x;
1021 m_nextROI.y = m_default_y;
1022 m_nextROI.w = m_default_w;
1023 m_nextROI.h = m_default_h;
1024 m_nextROI.bin_x = m_default_bin_x;
1025 m_nextROI.bin_y = m_default_bin_y;*/
1026
1027 return 0;
1028}
1029
1031{
1032 if( m_camera == nullptr )
1033 return 0;
1034
1035 recordCamera( true );
1036
1037 if( m_fpsSet == 0 )
1038 {
1039 try
1040 {
1041 m_camera->AcquisitionFrameRateEnable.SetValue( false );
1042 }
1043 catch( ... )
1044 {
1045 return log<software_error, -1>( { __FILE__, __LINE__, "Error disabling frame rate limit." } );
1046 }
1047 }
1048 else
1049 {
1050 try
1051 {
1052 m_camera->AcquisitionFrameRateEnable.SetValue( true );
1053 m_camera->AcquisitionFrameRate.SetValue( m_fpsSet );
1054 }
1055 catch( ... )
1056 {
1057 return log<software_error, -1>( { __FILE__, __LINE__, "Error setting frame rate limit." } );
1058 }
1059 }
1060
1061 return 0;
1062}
1063
1065{
1066 if( m_camera == nullptr )
1067 return 0;
1068
1069 try
1070 {
1071 recordCamera( true );
1072 m_camera->ExposureTime.SetValue( m_expTimeSet * 1e6 );
1073 }
1074 catch( ... )
1075 {
1076 log<software_error>( { __FILE__, __LINE__, "Error setting exposure time" } );
1077 return -1;
1078 }
1079
1080 log<text_log>( "Set exposure time: " + std::to_string( m_expTimeSet ) + " sec" );
1081
1082 return 0;
1083}
1084
1086{
1087 std::cerr << "checkNextROI!\n";
1088
1089 // First find binning indices
1090 size_t bx = 0;
1091 for( size_t b = 0; b < m_binXs.size(); ++b )
1092 {
1093 if( m_nextROI.bin_x == m_binXs[b] )
1094 {
1095 bx = b;
1096 break;
1097 }
1098 }
1099 std::cerr << "req bin_x: " << m_nextROI.bin_x << " " << "adj bin_x: " << m_binXs[bx] << "\n";
1100 m_nextROI.bin_x = m_binXs[bx]; // In case no valid value was found.
1101
1102 size_t by = 0;
1103 for( size_t b = 0; b < m_binYs.size(); ++b )
1104 {
1105 if( m_nextROI.bin_y == m_binYs[b] )
1106 {
1107 by = b;
1108 break;
1109 }
1110 }
1111 std::cerr << "req bin_y: " << m_nextROI.bin_y << " " << "adj bin_y: " << m_binYs[by] << "\n";
1112 m_nextROI.bin_y = m_binYs[by]; // In case no valid value was found.
1113
1114 // Next check width
1115 //-- round to nearest increment
1116 //-- check limits
1117 int w = m_nextROI.w;
1118 int rw = w % m_incWs[bx];
1119 if( rw < 0.5 * m_incWs[bx] )
1120 w -= rw;
1121 else
1122 w += m_incWs[bx] - rw;
1123
1124 if( w < m_minWs[bx] )
1125 w = m_minWs[bx];
1126 else if( w > m_maxWs[bx] )
1127 w = m_maxWs[bx];
1128
1129 std::cerr << "req w: " << m_nextROI.w << " " << "adj w: " << w << "\n";
1130 m_nextROI.w = w;
1131
1132 // Now check x
1133 //-- calculate offset from center
1134 //-- round to nearest increment
1135 //-- recalculate center
1136 int x;
1138 {
1139 x = ( m_maxWs[bx] - 1 - m_nextROI.x ) - 0.5 * ( (float)w - 1 );
1140 }
1141 else
1142 {
1143 x = m_nextROI.x - 0.5 * ( (float)w - 1 );
1144 }
1145
1146 int rx = x % m_incXs[bx];
1147 if( rx < 0.5 * m_incXs[bx] )
1148 x -= rx;
1149 else
1150 x += m_incXs[bx] - rx;
1151
1152 if( x < 0 )
1153 x = 0;
1154 else if( x > m_maxWs[bx] - w )
1155 x = m_maxWs[bx] - w;
1156
1157 std::cerr << "req x: " << m_nextROI.x;
1159 {
1160 m_nextROI.x = m_maxWs[bx] - 1 - ( x + 0.5 * ( (float)w - 1.0 ) );
1161 }
1162 else
1163 {
1164 m_nextROI.x = x + 0.5 * ( (float)w - 1.0 );
1165 }
1166 std::cerr << " adj x: " << m_nextROI.x << "\n";
1167
1168 // Next check height
1169 //-- round to nearest increment
1170 //-- check limits
1171 int h = m_nextROI.h;
1172 int rh = h % m_incHs[by];
1173 if( rh < 0.5 * m_incHs[by] )
1174 h -= rh;
1175 else
1176 h += m_incHs[by] - rh;
1177
1178 if( h < m_minHs[by] )
1179 h = m_minHs[by];
1180 else if( h > m_maxHs[by] )
1181 h = m_maxHs[by];
1182
1183 std::cerr << "req h: " << m_nextROI.h << " " << "adj h: " << h << "\n";
1184 m_nextROI.h = h;
1185
1186 // Now check y
1187 //-- calculate offset from center
1188 //-- round to nearest increment
1189 //-- recalculate center
1190 int y;
1192 {
1193 y = ( m_maxHs[by] - 1 - m_nextROI.y ) - 0.5 * ( (float)h - 1 );
1194 }
1195 else
1196 {
1197 y = m_nextROI.y - 0.5 * ( (float)h - 1 );
1198 }
1199
1200 int ry = y % m_incYs[by];
1201 if( ry < 0.5 * m_incYs[by] )
1202 y -= ry;
1203 else
1204 y += m_incYs[by] - ry;
1205
1206 if( y < 0 )
1207 y = 0;
1208 else if( y > m_maxHs[by] - h )
1209 y = m_maxHs[by] - h;
1210
1211 std::cerr << "req y: " << m_nextROI.y;
1213 {
1214 m_nextROI.y = m_maxHs[by] - 1 - ( y + 0.5 * ( (float)h - 1 ) );
1215 }
1216 else
1217 {
1218 m_nextROI.y = y + 0.5 * ( (float)h - 1 );
1219 }
1220 std::cerr << " adj y: " << m_nextROI.y << "\n";
1221
1222 try
1223 {
1230
1231 return 0;
1232 }
1233 catch( const std::exception &e )
1234 {
1235 return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
1236 }
1237}
1238
1240{
1241 std::cerr << "setNextROI:\n";
1242 std::cerr << " m_nextROI.x = " << m_nextROI.x << "\n";
1243 std::cerr << " m_nextROI.y = " << m_nextROI.y << "\n";
1244 std::cerr << " m_nextROI.w = " << m_nextROI.w << "\n";
1245 std::cerr << " m_nextROI.h = " << m_nextROI.h << "\n";
1246 std::cerr << " m_nextROI.bin_x = " << m_nextROI.bin_x << "\n";
1247 std::cerr << " m_nextROI.bin_y = " << m_nextROI.bin_y << "\n";
1248
1249 m_reconfig = true;
1250
1251 updateSwitchIfChanged( m_indiP_roi_set, "request", pcf::IndiElement::Off, INDI_IDLE );
1252 updateSwitchIfChanged( m_indiP_roi_full, "request", pcf::IndiElement::Off, INDI_IDLE );
1253 updateSwitchIfChanged( m_indiP_roi_last, "request", pcf::IndiElement::Off, INDI_IDLE );
1254 updateSwitchIfChanged( m_indiP_roi_default, "request", pcf::IndiElement::Off, INDI_IDLE );
1255 return 0;
1256}
1257
1259{
1260 std::string ss;
1261
1262 ss += std::to_string( m_currentROI.x ) + "_" + std::to_string( m_currentROI.y ) + "_";
1263 ss += std::to_string( m_currentROI.w ) + "x" + std::to_string( m_currentROI.h ) + "_";
1264 ss += std::to_string( m_currentROI.bin_x ) + "x" + std::to_string( m_currentROI.bin_y ) + "_";
1265 ss += std::to_string( m_expTime ) + "_";
1266 ss += std::to_string( floor( m_ccdTemp + 0.5 ) );
1267
1268 return ss;
1269}
1270
1272{
1273 return true;
1274}
1275
1280
1282{
1283 return recordCamera( true );
1284}
1285
1286} // namespace app
1287} // namespace MagAOX
1288#endif
Pylon::CBaslerUsbInstantCamera Camera_t
int16_t pixelT
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 m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
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
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
dev::telemeter< baslerCtrl > telemeterT
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.
dev::frameGrabber< baslerCtrl > frameGrabberT
std::vector< int > m_incXs
The allowed increment in X for each X-binning.
int powerOnDefaults()
Set defaults for a power on state.
dev::stdCamera< baslerCtrl > stdCameraT
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.
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.
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_full_currbin_x
The current-binning full ROI center x coordinate.
float m_expTime
The current exposure time, in seconds.
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.
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.
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.
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.
go_lp b(m_lp.m_c)
#define FRAMEGRABBER_SETUP_CONFIG(cfig)
Call frameGrabberT::setupConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_LOGIC
Call frameGrabberT::appLogic with error checking for frameGrabber.
#define FRAMEGRABBER_APP_SHUTDOWN
Call frameGrabberT::appShutdown with error checking for frameGrabber.
#define FRAMEGRABBER_UPDATE_INDI
Call frameGrabberT::updateINDI with error checking for frameGrabber.
#define FRAMEGRABBER_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
@ 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:28
#define STDCAMERA_SETUP_CONFIG(cfig)
Call stdCameraT::setupConfig with error checking for stdCamera.
#define STDCAMERA_APP_LOGIC
Call stdCameraT::appLogic with error checking for stdCamera.
#define STDCAMERA_APP_STARTUP
Call stdCameraT::appStartup with error checking for stdCamera.
#define STDCAMERA_LOAD_CONFIG(cfig)
Call stdCameraT::loadConfig with error checking for stdCamera.
#define STDCAMERA_UPDATE_INDI
Call stdCameraT::updateINDI with error checking for stdCamera.
#define STDCAMERA_APP_SHUTDOWN
Call stdCameraT::appShutdown with error checking for stdCamera.
A device base class which saves telemetry.
Definition telemeter.hpp:75
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording stdcam stage specific status.
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.