/* Downloads the image from the CCD. */ int QHYCCD::grabImage() { if (sim) { unsigned char * image = (unsigned char *) PrimaryCCD.getFrameBuffer(); int width = PrimaryCCD.getSubW() / PrimaryCCD.getBinX() * PrimaryCCD.getBPP() / 8; int height = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) image[i * width + j] = rand() % 255; } else { uint32_t ret, w,h,bpp,channels; ret = GetQHYCCDSingleFrame(camhandle,&w,&h,&bpp,&channels,PrimaryCCD.getFrameBuffer()); if (ret != QHYCCD_SUCCESS) DEBUGF(INDI::Logger::DBG_ERROR, "GetQHYCCDSingleFrame error (%d)", ret); } // Perform software binning if necessary //PrimaryCCD.binFrame(); DEBUG(INDI::Logger::DBG_DEBUG, "Download complete."); if (ExposureRequest > POLLMS * 5) DEBUG(INDI::Logger::DBG_SESSION, "Download complete."); ExposureComplete(&PrimaryCCD); return 0; }
bool Camera_QHY::Capture(int duration, usImage& img, int options, const wxRect& subframe) { bool useSubframe = UseSubframes && !subframe.IsEmpty(); if (Binning != m_curBin) { FullSize = wxSize(m_maxSize.GetX() / Binning, m_maxSize.GetY() / Binning); m_curBin = Binning; useSubframe = false; // subframe may be out of bounds now } if (img.Init(FullSize)) { DisconnectWithAlert(CAPT_FAIL_MEMORY); return true; } wxRect frame = useSubframe ? subframe : wxRect(FullSize); if (useSubframe) img.Clear(); wxRect roi; if (useSubframe) { // Use a larger ROI around the subframe to avoid changing the ROI as the centroid // wobbles around. Changing the ROI introduces a lag of several seconds. // This also satifies the constraint that ROI width and height must be multiples of 4. enum { PAD = 1 << 5 }; roi.SetLeft(round_down(subframe.GetLeft(), PAD)); roi.SetRight(round_up(subframe.GetRight() + 1, PAD) - 1); roi.SetTop(round_down(subframe.GetTop(), PAD)); roi.SetBottom(round_up(subframe.GetBottom() + 1, PAD) - 1); } else { roi = frame; } uint32_t ret = QHYCCD_ERROR; // lzr from QHY says this needs to be set for every exposure ret = SetQHYCCDBinMode(m_camhandle, Binning, Binning); if (ret != QHYCCD_SUCCESS) { Debug.Write(wxString::Format("SetQHYCCDBinMode failed! ret = %d\n", (int)ret)); } if (m_roi != roi) { // when roi changes, must call this ret = CancelQHYCCDExposingAndReadout(m_camhandle); if (ret == QHYCCD_SUCCESS) { Debug.Write("CancelQHYCCDExposingAndReadout success\n"); } else { Debug.Write("CancelQHYCCDExposingAndReadout failed\n"); } ret = SetQHYCCDResolution(m_camhandle, roi.GetLeft(), roi.GetTop(), roi.GetWidth(), roi.GetHeight()); if (ret == QHYCCD_SUCCESS) { m_roi = roi; } else { Debug.Write(wxString::Format("SetQHYCCDResolution(%d,%d,%d,%d) failed! ret = %d\n", roi.GetLeft(), roi.GetTop(), roi.GetWidth(), roi.GetHeight(), (int)ret)); } } if (duration != m_curExposure) { ret = SetQHYCCDParam(m_camhandle, CONTROL_EXPOSURE, duration * 1000.0); // QHY duration is usec if (ret == QHYCCD_SUCCESS) { m_curExposure = duration; } else { Debug.Write(wxString::Format("QHY set exposure ret %d\n", (int)ret)); pFrame->Alert(_("Failed to set camera exposure")); } } if (GuideCameraGain != m_curGain) { double gain = m_gainMin + GuideCameraGain * (m_gainMax - m_gainMin) / 100.0; gain = floor(gain / m_gainStep) * m_gainStep; Debug.Write(wxString::Format("QHY set gain %g (%g..%g incr %g)\n", gain, m_gainMin, m_gainMax, m_gainStep)); ret = SetQHYCCDParam(m_camhandle, CONTROL_GAIN, gain); if (ret == QHYCCD_SUCCESS) { m_curGain = GuideCameraGain; } else { Debug.Write(wxString::Format("QHY set gain ret %d\n", (int)ret)); pFrame->Alert(_("Failed to set camera gain")); } } ret = ExpQHYCCDSingleFrame(m_camhandle); if (ret == QHYCCD_ERROR) { Debug.Write(wxString::Format("QHY exp single frame ret %d\n", (int)ret)); DisconnectWithAlert(_("QHY exposure failed"), NO_RECONNECT); return true; } if (ret == QHYCCD_SUCCESS) { Debug.Write(wxString::Format("QHY: 200ms delay needed\n")); WorkerThread::MilliSleep(200); } if (ret == QHYCCD_READ_DIRECTLY) { //Debug.Write("QHYCCD_READ_DIRECTLY\n"); } uint32_t w, h, bpp, channels; ret = GetQHYCCDSingleFrame(m_camhandle, &w, &h, &bpp, &channels, RawBuffer); if (ret != QHYCCD_SUCCESS || (bpp != 8 && bpp != 16)) { Debug.Write(wxString::Format("QHY get single frame ret %d bpp %u\n", ret, bpp)); // users report that reconnecting the camera after this failure allows // them to resume guiding so we'll try to reconnect automatically DisconnectWithAlert(_("QHY get frame failed"), RECONNECT); return true; } if (useSubframe) { img.Subframe = frame; int xofs = subframe.GetLeft() - roi.GetLeft(); int yofs = subframe.GetTop() - roi.GetTop(); int dxr = w - frame.width - xofs; if (bpp == 8) { const unsigned char *src = RawBuffer + yofs * w; unsigned short *dst = img.ImageData + frame.GetTop() * FullSize.GetWidth() + frame.GetLeft(); for (int y = 0; y < frame.height; y++) { unsigned short *d = dst; src += xofs; for (int x = 0; x < frame.width; x++) *d++ = (unsigned short) *src++; src += dxr; dst += FullSize.GetWidth(); } } else // bpp == 16 { const unsigned short *src = (const unsigned short *) RawBuffer + yofs * w; unsigned short *dst = img.ImageData + frame.GetTop() * FullSize.GetWidth() + frame.GetLeft(); for (int y = 0; y < frame.height; y++) { src += xofs; memcpy(dst, src, frame.width * sizeof(unsigned short)); src += frame.width + dxr; dst += FullSize.GetWidth(); } } } else { if (bpp == 8) { const unsigned char *src = RawBuffer; unsigned short *dst = img.ImageData; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { *dst++ = (unsigned short) *src++; } } } else // bpp == 16 { memcpy(img.ImageData, RawBuffer, w * h * sizeof(unsigned short)); } } if (options & CAPTURE_SUBTRACT_DARK) SubtractDark(img); if (Color && Binning == 1 && (options & CAPTURE_RECON)) QuickLRecon(img); return false; }