diff --git a/indi-asi/asi_base.cpp b/indi-asi/asi_base.cpp index 2038be21d..553ba10ff 100644 --- a/indi-asi/asi_base.cpp +++ b/indi-asi/asi_base.cpp @@ -33,8 +33,10 @@ #include #include #include +#include +#include -#define MAX_EXP_RETRIES 3 +#define MAX_EXP_RETRIES 2 #define VERBOSE_EXPOSURE 3 #define TEMP_TIMER_MS 1000 /* Temperature polling time (ms) */ #define TEMP_THRESHOLD .25 /* Differential temperature threshold (C)*/ @@ -93,6 +95,8 @@ void ASIBase::workerStreamVideo(const std::atomic_bool &isAboutToQuit) Streamer->newFrame(targetFrame, totalBytes); } + + ASIStopVideoCapture(mCameraInfo.CameraID); } void ASIBase::workerBlinkExposure(const std::atomic_bool &isAboutToQuit, int blinks, float duration) @@ -269,9 +273,57 @@ void ASIBase::workerExposure(const std::atomic_bool &isAboutToQuit, float durati return; } - LOGF_ERROR("Exposure failed after %d attempts.", mExposureRetry); + LOGF_WARN("Exposure failed after %d attempts. Attempting USB reset...", mExposureRetry); ASIStopExposure(mCameraInfo.CameraID); - PrimaryCCD.setExposureFailed(); + ASICloseCamera(mCameraInfo.CameraID); + + resetUSBDevice(); + + LOG_INFO("Reopening camera after reset..."); + ASI_ERROR_CODE ret = ASIOpenCamera(mCameraInfo.CameraID); + if (ret != ASI_SUCCESS) + { + LOGF_ERROR("Failed to reopen camera after USB reset (%s)", Helpers::toString(ret)); + PrimaryCCD.setExposureFailed(); + return; + } + + LOG_INFO("Reinitializing camera..."); + ret = ASIInitCamera(mCameraInfo.CameraID); + if (ret != ASI_SUCCESS) + { + LOGF_ERROR("Failed to reinitialize camera after USB reset (%s)", Helpers::toString(ret)); + PrimaryCCD.setExposureFailed(); + return; + } + + // Restore previous settings + ASI_IMG_TYPE currentType = getImageType(); + ret = ASISetROIFormat(mCameraInfo.CameraID, + PrimaryCCD.getSubW() / PrimaryCCD.getBinX(), + PrimaryCCD.getSubH() / PrimaryCCD.getBinY(), + PrimaryCCD.getBinX(), currentType); + if (ret != ASI_SUCCESS) + { + LOGF_ERROR("Failed to restore ROI format after USB reset (%s)", Helpers::toString(ret)); + PrimaryCCD.setExposureFailed(); + return; + } + + ret = ASISetStartPos(mCameraInfo.CameraID, + PrimaryCCD.getSubX() / PrimaryCCD.getBinX(), + PrimaryCCD.getSubY() / PrimaryCCD.getBinY()); + if (ret != ASI_SUCCESS) + { + LOGF_ERROR("Failed to restore start position after USB reset (%s)", Helpers::toString(ret)); + PrimaryCCD.setExposureFailed(); + return; + } + + // Try one more time after reset + LOG_INFO("Attempting exposure again after USB reset..."); + ASIStopExposure(mCameraInfo.CameraID); + workerExposure(isAboutToQuit, duration); return; } } @@ -1579,6 +1631,147 @@ void ASIBase::addFITSKeywords(INDI::CCDChip *targetChip, std::vector +#include #include "indipropertyswitch.h" #include "indipropertynumber.h" @@ -132,6 +133,9 @@ class ASIBase : public INDI::CCD /** Can the camera flip the image horizontally and vertically */ bool hasFlipControl(); + /** Reset USB device when camera gets stuck */ + void resetUSBDevice(); + /** Additional Properties to INDI::CCD */ INDI::PropertyNumber CoolerNP {1}; INDI::PropertySwitch CoolerSP {2};