10 #define baslerCtrl_hpp
14 #include <pylon/PylonIncludes.h>
15 #include <pylon/PixelData.h>
16 #include <pylon/GrabResultData.h>
17 #include <pylon/usb/BaslerUsbInstantCamera.h>
18 #include <pylon/usb/_BaslerUsbCameraParams.h>
19 #include <GenApi/IFloat.h>
21 typedef Pylon::CBaslerUsbInstantCamera
Camera_t;
24 using namespace Basler_UsbCameraParams;
26 using namespace Pylon;
29 #include <ImageStreamIO/ImageStreamIO.h>
31 #include "../../libMagAOX/libMagAOX.hpp"
32 #include "../../magaox_git_version.h"
68 static constexpr
bool c_stdCamera_tempControl =
false;
70 static constexpr
bool c_stdCamera_temp =
true;
72 static constexpr
bool c_stdCamera_readoutSpeed =
false;
74 static constexpr
bool c_stdCamera_vShiftSpeed =
false;
76 static constexpr
bool c_stdCamera_emGain =
false;
78 static constexpr
bool c_stdCamera_exptimeCtrl =
true;
80 static constexpr
bool c_stdCamera_fpsCtrl =
true;
82 static constexpr
bool c_stdCamera_fps =
true;
84 static constexpr
bool c_stdCamera_synchro =
false;
86 static constexpr
bool c_stdCamera_usesModes =
false;
88 static constexpr
bool c_stdCamera_usesROI =
true;
90 static constexpr
bool c_stdCamera_cropMode =
false;
92 static constexpr
bool c_stdCamera_hasShutter =
false;
94 static constexpr
bool c_stdCamera_usesStateString =
false;
96 static constexpr
bool c_frameGrabber_flippable =
true;
131 CBaslerUsbInstantCamera * m_camera {
nullptr};
143 virtual
void setupConfig();
146 virtual
void loadConfig();
152 virtual
int appStartup();
155 virtual
int appLogic();
158 virtual
int appShutdown();
162 int configureAcquisition();
163 int startAcquisition();
164 int acquireAndCheckValid();
165 int loadImageIntoStream(
void * dest);
203 int powerOnDefaults();
243 int checkRecordTimes();
254 m_powerMgtEnabled =
false;
260 baslerCtrl::~baslerCtrl() noexcept
266 void baslerCtrl::setupConfig()
272 config.add(
"camera.serialNumber",
"",
"camera.serialNumber", argType::Required,
"camera",
"serialNumber",
false,
"int",
"The identifying serial number of the camera.");
273 config.add(
"camera.bits",
"",
"camera.bits", argType::Required,
"camera",
"bits",
false,
"int",
"The number of bits used by the camera. Default is 10.");
280 void baslerCtrl::loadConfig()
284 config(m_serialNumber,
"camera.serialNumber");
285 config(m_bits,
"camera.bits");
294 int baslerCtrl::appStartup()
319 state(stateCodes::NOTCONNECTED);
326 int baslerCtrl::appLogic()
341 if( state() == stateCodes::NOTCONNECTED || state() == stateCodes::NODEVICE || state() == stateCodes::ERROR)
343 std::unique_lock<std::mutex>
lock(m_indiMutex);
346 log<software_error>({__FILE__, __LINE__});
349 if(state() != stateCodes::CONNECTED)
return 0;
352 if( state() == stateCodes::CONNECTED )
355 std::unique_lock<std::mutex>
lock(m_indiMutex);
357 state(stateCodes::READY);
360 if( state() == stateCodes::READY || state() == stateCodes::OPERATING )
363 std::unique_lock<std::mutex>
lock(m_indiMutex, std::try_to_lock);
366 if(!
lock.owns_lock())
return 0;
370 if(state() == stateCodes::READY || state() == stateCodes::OPERATING) state(stateCodes::ERROR);
376 if(state() == stateCodes::READY || state() == stateCodes::OPERATING) state(stateCodes::ERROR);
382 if(state() == stateCodes::READY || state() == stateCodes::OPERATING) state(stateCodes::ERROR);
388 log<software_error>({__FILE__, __LINE__});
389 state(stateCodes::ERROR);
395 log<software_error>({__FILE__, __LINE__});
396 state(stateCodes::ERROR);
402 log<software_error>({__FILE__, __LINE__});
415 int baslerCtrl::appShutdown()
421 if(m_camera) m_camera->Close();
432 int baslerCtrl::connect()
436 info.SetSerialNumber(m_serialNumber.c_str());
447 m_camera =
new CBaslerUsbInstantCamera( CTlFactory::GetInstance().CreateFirstDevice(
info) );
458 state(stateCodes::NODEVICE);
461 log<text_log>(
"no camera with serial number " + m_serialNumber +
" found.");
469 if(m_shmimName ==
"")
471 m_shmimName = (std::string)m_camera->GetDeviceInfo().GetModelName() +
"_" + (std::string)m_camera->GetDeviceInfo().GetSerialNumber();
474 m_camera->RegisterConfiguration(
new CAcquireContinuousConfiguration , RegistrationMode_ReplaceAll, Cleanup_Delete);
487 state(stateCodes::NODEVICE);
490 log<text_log>(
"error opening camera " + m_serialNumber +
".");
497 m_camera->ExposureAuto.SetValue(ExposureAuto_Off);
508 state(stateCodes::NODEVICE);
511 log<text_log>(
"failed to set exposure auto off for camera " + m_serialNumber);
520 m_camera->PixelFormat.SetValue(PixelFormat_Mono8);
522 else if(m_bits == 10)
524 m_camera->PixelFormat.SetValue(PixelFormat_Mono10);
526 else if(m_bits == 12)
528 m_camera->PixelFormat.SetValue(PixelFormat_Mono12);
532 log<text_log>(
"unsupported bit depth for camera" + m_serialNumber +
"");
544 state(stateCodes::NODEVICE);
547 log<text_log>(
"failed to set bit depth for camera" + m_serialNumber +
"");
552 state(stateCodes::CONNECTED);
555 log<text_log>(
"Found camera of type " + (std::string)m_camera->GetDeviceInfo().GetModelName() +
" with serial number " + m_serialNumber +
".");
556 log<text_log>(
"Using shared memory name " + m_shmimName +
".");
559 m_camera->BinningHorizontalMode.SetValue(BinningHorizontalMode_Sum);
560 m_camera->BinningVerticalMode.SetValue(BinningVerticalMode_Sum);
565 m_camera->StopGrabbing();
566 m_camera->OffsetX.SetValue(0);
567 m_camera->OffsetY.SetValue(0);
569 int minb = m_camera->BinningHorizontal.GetMin();
570 int incb = m_camera->BinningHorizontal.GetInc();
571 int maxb = m_camera->BinningHorizontal.GetMax();
574 for(
int b = minb; b<=maxb; b+=incb) m_binXs.push_back(b);
576 minb = m_camera->BinningVertical.GetMin();
577 incb = m_camera->BinningVertical.GetInc();
578 maxb = m_camera->BinningVertical.GetMax();
581 for(
int b = minb; b<=maxb; b+=incb) m_binYs.push_back(b);
587 for(
size_t b=0; b < m_binXs.size(); ++b)
589 m_camera->BinningHorizontal.SetValue(m_binXs[b]);
590 m_camera->BinningVertical.SetValue(m_binYs[0]);
592 m_incXs.push_back(m_camera->OffsetX.GetInc());
593 m_minWs.push_back(m_camera->Width.GetMin());
594 m_incWs.push_back(m_camera->Width.GetInc());
595 m_maxWs.push_back(m_camera->Width.GetMax());
610 for(
size_t b=0; b < m_binYs.size(); ++b)
612 m_camera->BinningHorizontal.SetValue(m_binXs[0]);
613 m_camera->BinningVertical.SetValue(m_binYs[b]);
615 m_incYs.push_back(m_camera->OffsetX.GetInc());
616 m_minHs.push_back(m_camera->Height.GetMin());
617 m_incHs.push_back(m_camera->Height.GetInc());
618 m_maxHs.push_back(m_camera->Height.GetMax());
629 m_full_w = m_camera->SensorWidth.GetValue();
630 m_full_h = m_camera->SensorHeight.GetValue();
631 m_full_x = 0.5*((float) m_full_w-1.0);
632 m_full_y = 0.5*((float) m_full_h-1.0);
634 if(m_default_w == 0) m_default_w = m_full_w;
635 if(m_default_h == 0) m_default_h = m_full_h;
636 if(m_default_x == 0) m_default_x = m_full_x;
637 if(m_default_y == 0) m_default_y = m_full_y;
638 if(m_default_bin_x == 0) m_binXs[0];
639 if(m_default_bin_y == 0) m_binYs[0];
641 m_nextROI.x = m_default_x;
642 m_nextROI.y = m_default_y;
643 m_nextROI.w = m_default_w;
644 m_nextROI.h = m_default_h;
645 m_nextROI.bin_x = m_default_bin_x;
646 m_nextROI.bin_y = m_default_bin_y;
652 int baslerCtrl::configureAcquisition()
654 if(!m_camera)
return -1;
659 m_camera->StopGrabbing();
664 m_camera->CenterX.SetValue(
false);
665 m_camera->CenterY.SetValue(
false);
668 m_camera->OffsetX.SetValue(0);
669 m_camera->OffsetY.SetValue(0);
671 if(checkNextROI() < 0)
673 log<software_error>({__FILE__, __LINE__,
"error from checkNextROI()"});
680 for(
size_t b =0; b < m_binXs.size(); ++b)
682 if(m_nextROI.bin_x == m_binXs[b])
690 for(
size_t b =0; b < m_binYs.size(); ++b)
692 if(m_nextROI.bin_y == m_binYs[b])
702 if(m_currentFlip == fgFlipLR || m_currentFlip == fgFlipUDLR)
704 xoff = (m_maxWs[bx] - 1 - m_nextROI.x) - 0.5*((
float) m_nextROI.w - 1);
708 xoff = m_nextROI.x - 0.5*((float) m_nextROI.w - 1);
711 if(m_currentFlip == fgFlipUD || m_currentFlip == fgFlipUDLR)
713 yoff = (m_maxHs[by] - 1 - m_nextROI.y) - 0.5*((
float) m_nextROI.h - 1);
717 yoff = m_nextROI.y - 0.5*((float) m_nextROI.h - 1);
720 m_camera->BinningHorizontal.SetValue(m_nextROI.bin_x);
721 m_camera->BinningVertical.SetValue(m_nextROI.bin_y);
723 m_camera->BinningHorizontalMode.SetValue(BinningHorizontalMode_Sum);
724 m_camera->BinningVerticalMode.SetValue(BinningVerticalMode_Sum);
726 m_camera->Width.SetValue(m_nextROI.w);
727 m_camera->Height.SetValue(m_nextROI.h);
729 m_camera->OffsetX.SetValue(xoff);
730 m_camera->OffsetY.SetValue(yoff);
733 m_currentROI.bin_x = m_camera->BinningHorizontal.GetValue();
734 m_currentROI.bin_y = m_camera->BinningVertical.GetValue();
737 for(
size_t b =0; b < m_binXs.size(); ++b)
739 if(m_nextROI.bin_x == m_binXs[b])
747 for(
size_t b =0; b < m_binYs.size(); ++b)
749 if(m_nextROI.bin_y == m_binYs[b])
756 m_currentROI.w = m_camera->Width.GetValue();
757 m_currentROI.h = m_camera->Height.GetValue();
759 if(m_currentFlip == fgFlipLR || m_currentFlip == fgFlipUDLR)
761 m_currentROI.x = m_maxWs[bx] - 1 - (m_camera->OffsetX.GetValue() + 0.5*((float) m_currentROI.w - 1));
765 m_currentROI.x = m_camera->OffsetX.GetValue() + 0.5*((float) m_currentROI.w - 1);
768 if(m_currentFlip == fgFlipUD || m_currentFlip == fgFlipUDLR)
770 m_currentROI.y = m_maxHs[by] - 1 - (m_camera->OffsetY.GetValue() + 0.5*((float) m_currentROI.h - 1));
774 m_currentROI.y = m_camera->OffsetY.GetValue() + 0.5*((float) m_currentROI.h - 1);
778 m_full_currbin_w = m_maxWs[bx];
779 m_full_currbin_x = 0.5*((float) m_full_currbin_w - 1.0);
780 m_full_currbin_h = m_maxHs[by];
781 m_full_currbin_y = 0.5*((float) m_full_currbin_h - 1.0);
792 m_nextROI.x = m_currentROI.x;
793 m_nextROI.y = m_currentROI.y;
794 m_nextROI.w = m_currentROI.w;
795 m_nextROI.h = m_currentROI.h;
796 m_nextROI.bin_x = m_currentROI.bin_x;
797 m_nextROI.bin_y = m_currentROI.bin_y;
806 m_width = m_currentROI.w;
807 m_height = m_currentROI.h;
808 m_dataType = _DATATYPE_INT16;
816 log<software_error>({__FILE__, __LINE__,
"invalid ROI specifications"});
817 state(stateCodes::NOTCONNECTED);
824 int baslerCtrl::startAcquisition()
828 m_camera->StartGrabbing(GrabStrategy_LatestImageOnly );
832 state(stateCodes::NOTCONNECTED);
836 state(stateCodes::OPERATING);
841 int baslerCtrl::acquireAndCheckValid()
845 m_camera->RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);
849 state(stateCodes::NOTCONNECTED);
853 if (ptrGrabResult->GrabSucceeded())
855 clock_gettime(CLOCK_REALTIME, &m_currImageTimestamp);
860 state(stateCodes::NOTCONNECTED);
866 int baslerCtrl::loadImageIntoStream(
void * dest)
871 src = (
pixelT *) ptrGrabResult->GetBuffer();
875 state(stateCodes::NOTCONNECTED);
879 if(src ==
nullptr)
return -1;
886 int baslerCtrl::reconfig()
895 int baslerCtrl::getTemp()
897 if( m_camera ==
nullptr)
return 0;
901 m_ccdTemp = (float)m_camera->DeviceTemperature.GetValue();
908 state(stateCodes::NOTCONNECTED);
917 int baslerCtrl::getExpTime()
919 if( m_camera ==
nullptr)
return 0;
923 m_expTime = (float)m_camera->ExposureTime.GetValue()/1e6;
930 state(stateCodes::NOTCONNECTED);
939 int baslerCtrl::getFPS()
941 if( m_camera ==
nullptr)
return 0;
945 m_fps = m_camera->ResultingFrameRate.GetValue();
952 state(stateCodes::NOTCONNECTED);
961 float baslerCtrl::fps()
968 int baslerCtrl::powerOnDefaults()
970 m_nextROI.x = m_default_x;
971 m_nextROI.y = m_default_y;
972 m_nextROI.w = m_default_w;
973 m_nextROI.h = m_default_h;
974 m_nextROI.bin_x = m_default_bin_x;
975 m_nextROI.bin_y = m_default_bin_y;
981 int baslerCtrl::setFPS()
983 if( m_camera ==
nullptr)
return 0;
991 m_camera->AcquisitionFrameRateEnable.SetValue(
false);
995 return log<
software_error,-1>({__FILE__, __LINE__,
"Error disabling frame rate limit."});
1002 m_camera->AcquisitionFrameRateEnable.SetValue(
true);
1003 m_camera->AcquisitionFrameRate.SetValue(m_fpsSet);
1007 return log<
software_error,-1>({__FILE__, __LINE__,
"Error setting frame rate limit."});
1015 int baslerCtrl::setExpTime()
1017 if( m_camera ==
nullptr)
return 0;
1022 m_camera->ExposureTime.SetValue(m_expTimeSet*1e6);
1026 log<software_error>({__FILE__, __LINE__,
"Error setting exposure time"});
1030 log<text_log>(
"Set exposure time: " + std::to_string(m_expTimeSet) +
" sec");
1036 int baslerCtrl::checkNextROI()
1042 for(
size_t b =0; b < m_binXs.size(); ++b)
1044 if(m_nextROI.bin_x == m_binXs[b])
1050 std::cerr <<
"req bin_x: " << m_nextROI.bin_x <<
" " <<
"adj bin_x: " << m_binXs[bx] <<
"\n";
1051 m_nextROI.bin_x = m_binXs[bx];
1054 for(
size_t b =0; b < m_binYs.size(); ++b)
1056 if(m_nextROI.bin_y == m_binYs[b])
1062 std::cerr <<
"req bin_y: " << m_nextROI.bin_y <<
" " <<
"adj bin_y: " << m_binYs[by] <<
"\n";
1063 m_nextROI.bin_y = m_binYs[by];
1068 int w = m_nextROI.w;
1069 int rw = w % m_incWs[bx];
1070 if(rw < 0.5*m_incWs[bx]) w -= rw;
1071 else w += m_incWs[bx] - rw;
1073 if(w < m_minWs[bx]) w = m_minWs[bx];
1074 else if(w > m_maxWs[bx]) w = m_maxWs[bx];
1076 std::cerr <<
"req w: " << m_nextROI.w <<
" " <<
"adj w: " << w <<
"\n";
1084 if(m_currentFlip == fgFlipLR || m_currentFlip == fgFlipUDLR)
1086 x = (m_maxWs[bx] - 1 - m_nextROI.x) - 0.5*((
float) w - 1);
1090 x = m_nextROI.x - 0.5*((float) w - 1);
1093 int rx = x % m_incXs[bx];
1094 if(rx < 0.5*m_incXs[bx]) x -= rx;
1095 else x += m_incXs[bx] - rx;
1098 else if(x > m_maxWs[bx] - w) x = m_maxWs[bx] - w;
1101 if(m_currentFlip == fgFlipLR || m_currentFlip == fgFlipUDLR)
1103 m_nextROI.x = m_maxWs[bx] - 1 - (x + 0.5*((float) w - 1.0));
1107 m_nextROI.x = x + 0.5*((float) w - 1.0);
1109 std::cerr <<
" adj x: " << m_nextROI.x <<
"\n";
1114 int h = m_nextROI.h;
1115 int rh = h % m_incHs[by];
1116 if(rh < 0.5*m_incHs[by]) h -= rh;
1117 else h += m_incHs[by] - rh;
1119 if(h < m_minHs[by]) h = m_minHs[by];
1120 else if(h > m_maxHs[by]) h = m_maxHs[by];
1122 std::cerr <<
"req h: " << m_nextROI.h <<
" " <<
"adj h: " << h <<
"\n";
1130 if(m_currentFlip == fgFlipUD || m_currentFlip == fgFlipUDLR)
1132 y = (m_maxHs[by] - 1 - m_nextROI.y) - 0.5*((
float) h - 1);
1136 y = m_nextROI.y - 0.5*((float) h - 1);
1139 int ry = y % m_incYs[by];
1140 if(ry < 0.5*m_incYs[by]) y -= ry;
1141 else y += m_incYs[by] - ry;
1144 else if(y > m_maxHs[by] - h) y = m_maxHs[by] - h;
1147 if(m_currentFlip == fgFlipUD || m_currentFlip == fgFlipUDLR)
1149 m_nextROI.y = m_maxHs[by] - 1 - (y + 0.5*((float) h - 1));
1153 m_nextROI.y = y + 0.5*((float) h - 1);
1155 std::cerr <<
" adj y: " << m_nextROI.y <<
"\n";
1168 int baslerCtrl::setNextROI()
1171 std::cerr <<
" m_nextROI.x = " << m_nextROI.x <<
"\n";
1172 std::cerr <<
" m_nextROI.y = " << m_nextROI.y <<
"\n";
1173 std::cerr <<
" m_nextROI.w = " << m_nextROI.w <<
"\n";
1174 std::cerr <<
" m_nextROI.h = " << m_nextROI.h <<
"\n";
1175 std::cerr <<
" m_nextROI.bin_x = " << m_nextROI.bin_x <<
"\n";
1176 std::cerr <<
" m_nextROI.bin_y = " << m_nextROI.bin_y <<
"\n";
1188 int baslerCtrl::checkRecordTimes()
1196 return recordCamera(
true);
Pylon::CBaslerUsbInstantCamera Camera_t
The base-class for MagAO-X applications.
std::vector< int > m_minWs
The minimum value of the width for each X-binning.
std::vector< int > m_maxWs
The minimum value of the width for each X-binning.
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)
std::vector< int > m_incHs
The minimum value of the height for each Y-binning.
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.
std::vector< int > m_binYs
The allowed values of binning in Y (vertical)
std::vector< int > m_minHs
The minimum value of the height for each Y-binning.
void * loadImageIntoStreamCopy(void *dest, void *src, size_t width, size_t height, size_t szof)
int updateINDI()
Update the INDI properties for this device controller.
MagAO-X standard camera interface.
int updateINDI()
Update the INDI properties for this device controller.
@ info
For information only.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
std::unique_lock< std::mutex > lock(m_indiMutex)
A device base class which saves telemetry.
int appLogic()
Perform telemeter application logic.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
Log entry recording stdcam stage specific status.