From e940fd970538154908142f7b2d1a6e79f4be61cb Mon Sep 17 00:00:00 2001 From: jctk <52247294+jctk@users.noreply.github.com> Date: Sun, 1 Oct 2023 22:53:35 +0900 Subject: [PATCH] Stabilization of SVBONYBase::workerExposure (#845) --- indi-svbony/svbony_base.cpp | 192 ++++++++++++++++------------------- indi-svbony/svbony_base.h | 3 +- indi-svbony/svbony_helpers.h | 5 +- 3 files changed, 91 insertions(+), 109 deletions(-) diff --git a/indi-svbony/svbony_base.cpp b/indi-svbony/svbony_base.cpp index 664cb1070..8616c1914 100644 --- a/indi-svbony/svbony_base.cpp +++ b/indi-svbony/svbony_base.cpp @@ -125,7 +125,7 @@ void SVBONYBase::workerExposure(const std::atomic_bool &isAboutToQuit, float dur if (ret == SVB_SUCCESS) break; - LOGF_ERROR("Failed to start exposure (%d)", Helpers::toString(ret)); + LOGF_ERROR("Failed to start exposure (%s)", Helpers::toString(ret)); // Wait 100ms before trying again usleep(100 * 1000); } @@ -135,12 +135,44 @@ void SVBONYBase::workerExposure(const std::atomic_bool &isAboutToQuit, float dur if (duration > VERBOSE_EXPOSURE) LOGF_INFO("Taking a %g seconds frame...", duration); + /* + Prepare a read buffer for SVB_IMG_RGB24. + */ + SVB_IMG_TYPE type = getImageType(); + + std::unique_lock guard(ccdBufferLock); + uint8_t *image = PrimaryCCD.getFrameBuffer(); + uint8_t *buffer = image; + + uint16_t subW = PrimaryCCD.getSubW() / PrimaryCCD.getBinX(); + uint16_t subH = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); + int nChannels = (type == SVB_IMG_RGB24) ? 3 : 1; + size_t nTotalBytes = subW * subH * nChannels * (PrimaryCCD.getBPP() / 8); + + if (type == SVB_IMG_RGB24) + { + buffer = static_cast(malloc(nTotalBytes)); + if (buffer == nullptr) + { + LOGF_ERROR("%s: %d malloc failed (RGB 24).", getDeviceName(), nTotalBytes); + return; + } + } + + /* + Perform exposure and image data reading + */ + int nRetry = 100; // Number of retries when ret is SVB_ERROR_TIMEOUT while (1) { if (isAboutToQuit) { - // Discard from buffer but do not send - grabImage(0, false); + ret = SVBGetVideoData(mCameraInfo.CameraID, buffer, nTotalBytes, 1000); + LOGF_DEBUG("Discard unretrieved exposure data: SVBGetVideoData(%s)", Helpers::toString(ret)); + if (type == SVB_IMG_RGB24) + free(buffer); + guard.unlock(); + PrimaryCCD.setExposureLeft(0); return; } @@ -161,17 +193,63 @@ void SVBONYBase::workerExposure(const std::atomic_bool &isAboutToQuit, float dur delay = std::max(timeLeft - std::trunc(timeLeft), 0.005f); timeLeft = std::round(timeLeft); } - if (timeLeft > 0) { PrimaryCCD.setExposureLeft(timeLeft); } else { - grabImage(duration); - return; - } + ret = SVBGetVideoData(mCameraInfo.CameraID, buffer, nTotalBytes, 1000); + LOGF_DEBUG("Retrieved exposure data: SVBGetVideoData(%s)", Helpers::toString(ret)); + switch (ret) + { + case SVB_SUCCESS: + if (type == SVB_IMG_RGB24) + { + uint8_t *dstR = image; + uint8_t *dstG = image + subW * subH; + uint8_t *dstB = image + subW * subH * 2; + + const uint8_t *src = buffer; + const uint8_t *end = buffer + subW * subH * 3; + + while (src != end) + { + *dstB++ = *src++; + *dstG++ = *src++; + *dstR++ = *src++; + } + free(buffer); + } + guard.unlock(); + sendImage(type, duration); + + mExposureRetry = 0; + PrimaryCCD.setExposureLeft(0.0); + if (PrimaryCCD.getExposureDuration() > VERBOSE_EXPOSURE) + LOG_INFO("Exposure done, downloading image..."); + return; + break; + case SVB_ERROR_TIMEOUT: + --nRetry; + LOGF_DEBUG("Remaining retry count for SVBGetVideoData:%d", nRetry); + if (nRetry) + { + // No image data is prepared in the buffer yet. Retry next step of while loop. + delay = 0.5f; + break; + } + //fall through + default: // Cannot continue to retrive image data when ret is any error except timeout. + if (type == SVB_IMG_RGB24) + free(buffer); + guard.unlock(); + PrimaryCCD.setExposureLeft(0); + PrimaryCCD.setExposureFailed(); + return; + } + } usleep(delay * 1000 * 1000); } } @@ -963,104 +1041,6 @@ bool SVBONYBase::UpdateCCDBin(int binx, int biny) return UpdateCCDFrame(PrimaryCCD.getSubX(), PrimaryCCD.getSubY(), PrimaryCCD.getSubW(), PrimaryCCD.getSubH()); } -/* Downloads the image from the CCD. - N.B. No processing is done on the image */ -bool SVBONYBase::grabImage(float duration, bool send) -{ - SVB_ERROR_CODE ret = SVB_SUCCESS; - - SVB_IMG_TYPE type = getImageType(); - - std::unique_lock guard(ccdBufferLock); - uint8_t *image = PrimaryCCD.getFrameBuffer(); - uint8_t *buffer = image; - - uint16_t subW = PrimaryCCD.getSubW() / PrimaryCCD.getBinX(); - uint16_t subH = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); - int nChannels = (type == SVB_IMG_RGB24) ? 3 : 1; - size_t nTotalBytes = subW * subH * nChannels * (PrimaryCCD.getBPP() / 8); - - if (type == SVB_IMG_RGB24) - { - buffer = static_cast(malloc(nTotalBytes)); - if (buffer == nullptr) - { - LOGF_ERROR("%s: %d malloc failed (RGB 24).", getDeviceName()); - return -1; - } - } - - for (int i = 0; i < 5; i++) - { - ret = SVBGetVideoData(mCameraInfo.CameraID, buffer, nTotalBytes, 1000); - // Sleep for 100 ms and try up to five times - if (ret == SVB_ERROR_TIMEOUT) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - continue; - } - else if (ret != SVB_SUCCESS) - { - LOGF_ERROR("Failed to get data after exposure (%dx%d #%d channels) (%s).", subW, subH, nChannels, Helpers::toString(ret)); - PrimaryCCD.setExposureLeft(0); - PrimaryCCD.setExposureFailed(); - if (type == SVB_IMG_RGB24) - free(buffer); - return false; - } - else - break; - } - - PrimaryCCD.setExposureLeft(0); - - // Duration 0 means aborted so we just need to discard the frame. - if (duration == 0) - { - PrimaryCCD.setExposureFailed(); - if (type == SVB_IMG_RGB24) - free(buffer); - return true; - } - else if (ret != SVB_SUCCESS) - { - LOGF_ERROR("Failed to get data after exposure (%dx%d #%d channels) (%s).", subW, subH, nChannels, Helpers::toString(ret)); - PrimaryCCD.setExposureFailed(); - if (type == SVB_IMG_RGB24) - free(buffer); - return false; - } - else - { - if (PrimaryCCD.getExposureDuration() > VERBOSE_EXPOSURE) - LOG_INFO("Exposure done, downloading image..."); - } - - if (type == SVB_IMG_RGB24) - { - uint8_t *dstR = image; - uint8_t *dstG = image + subW * subH; - uint8_t *dstB = image + subW * subH * 2; - - const uint8_t *src = buffer; - const uint8_t *end = buffer + subW * subH * 3; - - while (src != end) - { - *dstB++ = *src++; - *dstG++ = *src++; - *dstR++ = *src++; - } - - free(buffer); - } - guard.unlock(); - - if (send) - sendImage(type, duration); - return true; -} - void SVBONYBase::sendImage(SVB_IMG_TYPE type, float duration) { PrimaryCCD.setNAxis(type == SVB_IMG_RGB24 ? 3 : 2); @@ -1377,4 +1357,4 @@ bool SVBONYBase::saveConfigItems(FILE *fp) bool SVBONYBase::SetCaptureFormat(uint8_t index) { return setVideoFormat(index); -} +} \ No newline at end of file diff --git a/indi-svbony/svbony_base.h b/indi-svbony/svbony_base.h index f4641a773..22acb6779 100644 --- a/indi-svbony/svbony_base.h +++ b/indi-svbony/svbony_base.h @@ -89,8 +89,7 @@ class SVBONYBase : public INDI::CCD void workerStreamVideo(const std::atomic_bool &isAboutToQuit); void workerExposure(const std::atomic_bool &isAboutToQuit, float duration); - /** Get image from CCD and send it to client */ - bool grabImage(float duration, bool send = true); + /** Send CCD image to client */ void sendImage(SVB_IMG_TYPE type, float duration); protected: diff --git a/indi-svbony/svbony_helpers.h b/indi-svbony/svbony_helpers.h index d2ee9513f..7f5048f4c 100644 --- a/indi-svbony/svbony_helpers.h +++ b/indi-svbony/svbony_helpers.h @@ -87,6 +87,7 @@ const char *toString(SVB_IMG_TYPE type) case SVB_IMG_RGB24: return "SVB_IMG_RGB24"; case SVB_IMG_RAW16: return "SVB_IMG_RAW16"; case SVB_IMG_Y8: return "SVB_IMG_Y8"; + case SVB_IMG_Y16: return "SVB_IMG_Y16"; case SVB_IMG_END: return "SVB_IMG_END"; default: return "UNKNOWN"; } @@ -99,7 +100,8 @@ const char *toPrettyString(SVB_IMG_TYPE type) case SVB_IMG_RAW8: return "Raw 8 bit"; case SVB_IMG_RGB24: return "RGB 24"; case SVB_IMG_RAW16: return "Raw 16 bit"; - case SVB_IMG_Y8: return "Luma"; + case SVB_IMG_Y8: return "Luma 8 bit"; + case SVB_IMG_Y16: return "Luma 16 bit"; case SVB_IMG_END: return "END"; default: return "UNKNOWN"; } @@ -114,6 +116,7 @@ INDI_PIXEL_FORMAT pixelFormat(SVB_IMG_TYPE type, SVB_BAYER_PATTERN pattern, bool { case SVB_IMG_RGB24: return INDI_RGB; case SVB_IMG_Y8: return INDI_MONO; + case SVB_IMG_Y16: return INDI_MONO; default:; // see below }