void MICCD::updateTemperature() { float ccdtemp = 0; float ccdpower = 0; int err = 0; if (isSimulation()) { ccdtemp = TemperatureN[0].value; if (TemperatureN[0].value < TemperatureRequest) ccdtemp += TEMP_THRESHOLD; else if (TemperatureN[0].value > TemperatureRequest) ccdtemp -= TEMP_THRESHOLD; ccdpower = 30; } else { if (gxccd_get_value(cameraHandle, GV_CHIP_TEMPERATURE, &ccdtemp) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Getting temperature failed: %s.", errorStr); err |= 1; } if (gxccd_get_value(cameraHandle, GV_POWER_UTILIZATION, &ccdpower) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Getting voltage failed: %s.", errorStr); err |= 2; } } TemperatureN[0].value = ccdtemp; CoolerN[0].value = ccdpower * 100.0; if (TemperatureNP.s == IPS_BUSY && fabs(TemperatureN[0].value - TemperatureRequest) <= TEMP_THRESHOLD) { // end of temperature ramp TemperatureN[0].value = TemperatureRequest; TemperatureNP.s = IPS_OK; } if (err) { if (err & 1) TemperatureNP.s = IPS_ALERT; if (err & 2) CoolerNP.s = IPS_ALERT; } else { CoolerNP.s = IPS_OK; } IDSetNumber(&TemperatureNP, nullptr); IDSetNumber(&CoolerNP, nullptr); temperatureID = IEAddTimer(POLLMS, MICCD::updateTemperatureHelper, this); }
/* Downloads the image from the CCD. */ int MICCD::grabImage() { unsigned char *image = (unsigned char *) PrimaryCCD.getFrameBuffer(); if (isSimulation()) { int height = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); int width = PrimaryCCD.getSubW() / PrimaryCCD.getBinX(); uint16_t *buffer = (uint16_t *) image; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) buffer[i * width + j] = rand() % UINT16_MAX; } else { int ret = 0; if (gxccd_read_image(cameraHandle, image, PrimaryCCD.getFrameBufferSize()) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Error getting image: %s.", errorStr); } } if (ExposureRequest > POLLMS * 5) DEBUG(INDI::Logger::DBG_SESSION, "Download complete."); downloading = false; ExposureComplete(&PrimaryCCD); return 0; }
IPState MICCD::GuideWest(float duration) { if (gxccd_move_telescope(cameraHandle, duration, 0) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "GuideWest() failed: %s.", errorStr); return IPS_ALERT; } return IPS_OK; }
IPState MICCD::GuideWest(uint32_t ms) { if (gxccd_move_telescope(cameraHandle, static_cast<int16_t>(ms), 0) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("GuideWest() failed: %s.", errorStr); return IPS_ALERT; } return IPS_OK; }
bool MICCD::setupParams() { bool sim = isSimulation(); if (sim) { SetCCDParams(4032, 2688, 16, 9, 9); } else { int chipW, chipD, pixelW, pixelD; gxccd_get_integer_parameter(cameraHandle, GIP_CHIP_W, &chipW); gxccd_get_integer_parameter(cameraHandle, GIP_CHIP_D, &chipD); gxccd_get_integer_parameter(cameraHandle, GIP_PIXEL_W, &pixelW); gxccd_get_integer_parameter(cameraHandle, GIP_PIXEL_D, &pixelD); SetCCDParams(chipW, chipD, 16, pixelW / 1000.0, pixelD / 1000.0); } int nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8; nbuf += 512; PrimaryCCD.setFrameBufferSize(nbuf); int expTime = 0; gxccd_get_integer_parameter(cameraHandle, GIP_MINIMAL_EXPOSURE, &expTime); minExpTime = expTime / 1000000.0; // convert to seconds PrimaryCCD.setMinMaxStep("CCD_EXPOSURE", "CCD_EXPOSURE_VALUE", minExpTime, 3600, 1, false); gxccd_get_integer_parameter(cameraHandle, GIP_MAX_BINNING_X, &maxBinX); gxccd_get_integer_parameter(cameraHandle, GIP_MAX_BINNING_Y, &maxBinY); if (!sim && hasGain) { float gain = 0; if (gxccd_get_value(cameraHandle, GV_ADC_GAIN, &gain) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Getting gain failed: %s.", errorStr); GainN[0].value = 0; GainNP.s = IPS_ALERT; IDSetNumber(&GainNP, NULL); return false; } else { GainN[0].value = gain; GainNP.s = IPS_OK; IDSetNumber(&GainNP, NULL); } } return true; }
bool MICCD::SelectFilter(int position) { if (!isSimulation() && gxccd_set_filter(cameraHandle, position - 1) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting filter failed: %s.", errorStr); return false; } CurrentFilter = position; SelectFilterDone(position); LOGF_DEBUG("Filter changed to %d", position); return true; }
MICCD::MICCD(int camId, bool eth) : FilterInterface(this) { cameraId = camId; isEth = eth; if (isEth) cameraHandle = gxccd_initialize_eth(cameraId); else cameraHandle = gxccd_initialize_usb(cameraId); if (!cameraHandle) IDLog("Error connecting MI camera!\n"); char sp[MAXINDINAME]; if (gxccd_get_string_parameter(cameraHandle, GSP_CAMERA_DESCRIPTION, sp, sizeof(sp)) < 0) { gxccd_get_last_error(cameraHandle, sp, sizeof(sp)); IDLog("Error getting MI camera info: %s.\n", sp); strncpy(name, "MI CCD", MAXINDIDEVICE); } else { // trim trailing spaces char *end = sp + strlen(sp) - 1; while (end > sp && isspace(*end)) end--; *(end + 1) = '\0'; snprintf(name, MAXINDINAME, "MI CCD %s", sp); IDLog("Detected camera: %s.\n", name); } gxccd_get_integer_parameter(cameraHandle, GIP_READ_MODES, &numReadModes); gxccd_get_integer_parameter(cameraHandle, GIP_FILTERS, &numFilters); gxccd_get_integer_parameter(cameraHandle, GIP_MAX_FAN, &maxFanValue); gxccd_get_integer_parameter(cameraHandle, GIP_MAX_WINDOW_HEATING, &maxHeatingValue); gxccd_release(cameraHandle); cameraHandle = nullptr; hasGain = false; useShutter = true; canDoPreflash = false; setDeviceName(name); setVersion(INDI_MI_VERSION_MAJOR, INDI_MI_VERSION_MINOR); }
bool MICCD::UpdateCCDBin(int hor, int ver) { if (hor < 1 || hor > maxBinX || ver < 1 || ver > maxBinY) { DEBUGF(INDI::Logger::DBG_ERROR, "Binning (%dx%d) are out of range. Range from 1x1 to (%dx%d)", maxBinX, maxBinY); return false; } if (gxccd_set_binning(cameraHandle, hor, ver) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Setting binning failed: %s.", errorStr); return false; } PrimaryCCD.setBin(hor, ver); return UpdateCCDFrame(PrimaryCCD.getSubX(), PrimaryCCD.getSubY(), PrimaryCCD.getSubW(), PrimaryCCD.getSubH()); }
bool MICCD::AbortExposure() { if (InExposure && !isSimulation()) { if (gxccd_abort_exposure(cameraHandle, false) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Aborting exposure failed: %s.", errorStr); return false; } } InExposure = false; downloading = false; LOG_INFO("Exposure aborted."); return true; }
int MICCD::SetTemperature(double temperature) { // If there difference, for example, is less than TEMP_THRESHOLD degrees, let's immediately return OK. if (fabs(temperature - TemperatureN[0].value) < TEMP_THRESHOLD) return 1; TemperatureRequest = temperature; if (!isSimulation() && gxccd_set_temperature(cameraHandle, temperature) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting temperature failed: %s.", errorStr); return -1; } return 0; }
bool MICCD::AbortExposure() { if (InExposure && !isSimulation()) { if (gxccd_abort_exposure(cameraHandle, false) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Aborting exposure failed: %s.", errorStr); return false; } } InExposure = false; downloading = false; DEBUG(INDI::Logger::DBG_SESSION, "Exposure aborted."); return true; }
void MICCD::TimerHit() { if (!isConnected()) return; // No need to reset timer if we are not connected anymore if (InExposure || downloading) { long timeleft = calcTimeLeft(); bool ready = false; if (gxccd_image_ready(cameraHandle, &ready) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Getting image ready failed: %s.", errorStr); } if (ready) { // grab and save image grabImage(); } // camera may need some time for image download -> update client only for positive values else if (timeleft >= 0) { DEBUGF(INDI::Logger::DBG_DEBUG, "Exposure in progress: Time left %ld", timeleft); PrimaryCCD.setExposureLeft(timeleft); } else if (!downloading) { PrimaryCCD.setExposureLeft(0); InExposure = false; downloading = true; // Don't spam the session log unless it is a long exposure > 5 seconds if (ExposureRequest > POLLMS * 5) DEBUG(INDI::Logger::DBG_SESSION, "Exposure done, downloading image..."); } } SetTimer(POLLMS); }
/* Downloads the image from the CCD. */ int MICCD::grabImage() { std::unique_lock<std::mutex> guard(ccdBufferLock); int ret = 0; unsigned char *image = (unsigned char *)PrimaryCCD.getFrameBuffer(); int width = PrimaryCCD.getSubW() / PrimaryCCD.getBinX(); int height = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); if (isSimulation()) { uint16_t *buffer = (uint16_t *)image; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) buffer[i * width + j] = rand() % UINT16_MAX; } else { ret = gxccd_read_image(cameraHandle, image, PrimaryCCD.getFrameBufferSize()); if (ret < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Error getting image: %s.", errorStr); } else { mirror_image(image, width, height); } } guard.unlock(); if (ExposureRequest > POLLMS * 5 && !ret) LOG_INFO("Download complete."); downloading = false; ExposureComplete(&PrimaryCCD); return ret; }
bool MICCD::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) { if (strcmp(dev, getDeviceName()) == 0) { if (!strcmp(name, FilterSlotNP.name)) { INDI::FilterInterface::processNumber(dev, name, values, names, n); return true; } if (!strcmp(name, FanNP.name)) { IUUpdateNumber(&FanNP, values, names, n); if (!isSimulation() && gxccd_set_fan(cameraHandle, FanN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting fan failed: %s.", errorStr); FanNP.s = IPS_ALERT; } else { FanNP.s = IPS_OK; } IDSetNumber(&FanNP, nullptr); return true; } if (!strcmp(name, WindowHeatingNP.name)) { IUUpdateNumber(&WindowHeatingNP, values, names, n); if (!isSimulation() && gxccd_set_window_heating(cameraHandle, WindowHeatingN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting heating failed: %s.", errorStr); WindowHeatingNP.s = IPS_ALERT; } else { WindowHeatingNP.s = IPS_OK; } IDSetNumber(&WindowHeatingNP, nullptr); return true; } if (!strcmp(name, TemperatureRampNP.name)) { IUUpdateNumber(&TemperatureRampNP, values, names, n); if (!isSimulation() && gxccd_set_temperature_ramp(cameraHandle, TemperatureRampN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting temp. ramp failed: %s.", errorStr); TemperatureRampNP.s = IPS_ALERT; } else { TemperatureRampNP.s = IPS_OK; } IDSetNumber(&TemperatureRampNP, nullptr); return true; } if (!strcmp(name, PreflashNP.name)) { IUUpdateNumber(&PreflashNP, values, names, n); // set NIR pre-flash if available. if (canDoPreflash) { if (!isSimulation() && gxccd_set_preflash(cameraHandle, PreflashN[0].value, PreflashN[1].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); LOGF_ERROR("Setting NIR preflash failed: %s.", errorStr); PreflashNP.s = IPS_ALERT; } else { PreflashNP.s = IPS_OK; } } IDSetNumber(&PreflashNP, nullptr); return true; } } return INDI::CCD::ISNewNumber(dev, name, values, names, n); }
bool MICCD::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev, getDeviceName()) == 0) { if (!strcmp(name, FilterSlotNP.name)) { processFilterSlot(getDeviceName(), values, names); return true; } if (!strcmp(name, FanNP.name)) { IUUpdateNumber(&FanNP, values, names, n); if (!isSimulation() && gxccd_set_fan(cameraHandle, FanN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Setting fan failed: %s.", errorStr); FanNP.s = IPS_ALERT; } else { FanNP.s = IPS_OK; } IDSetNumber(&FanNP, NULL); return true; } if (!strcmp(name, WindowHeatingNP.name)) { IUUpdateNumber(&WindowHeatingNP, values, names, n); if (!isSimulation() && gxccd_set_window_heating(cameraHandle, WindowHeatingN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Setting heating failed: %s.", errorStr); WindowHeatingNP.s = IPS_ALERT; } else { WindowHeatingNP.s = IPS_OK; } IDSetNumber(&WindowHeatingNP, NULL); return true; } if (!strcmp(name, TemperatureRampNP.name)) { IUUpdateNumber(&TemperatureRampNP, values, names, n); if (!isSimulation() && gxccd_set_temperature_ramp(cameraHandle, TemperatureRampN[0].value) < 0) { char errorStr[MAX_ERROR_LEN]; gxccd_get_last_error(cameraHandle, errorStr, sizeof(errorStr)); DEBUGF(INDI::Logger::DBG_ERROR, "Setting temp. ramp failed: %s.", errorStr); TemperatureRampNP.s = IPS_ALERT; } else { TemperatureRampNP.s = IPS_OK; } IDSetNumber(&TemperatureRampNP, NULL); return true; } } return INDI::CCD::ISNewNumber(dev, name, values, names, n); }