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