示例#1
0
文件: mi_ccd.cpp 项目: garlick/indi
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;
}
示例#2
0
文件: gphoto_ccd.cpp 项目: A-j-K/indi
bool GPhotoCCD::updateProperties()
{
  INDI::CCD::updateProperties();

  if (isConnected())
  {      
      if (mIsoSP.nsp > 0)
        defineSwitch(&mIsoSP);
      if (mFormatSP.nsp > 0)
        defineSwitch(&mFormatSP);

      defineSwitch(&transferFormatSP);
      defineSwitch(&livePreviewSP);
      defineSwitch(&autoFocusSP);

      defineSwitch(&FocusMotionSP);
      defineNumber(&FocusSpeedNP);
      defineNumber(&FocusTimerNP);

      imageBP=getBLOB("CCD1");
      imageB=imageBP->bp;

      // Dummy values until first capture is done
      SetCCDParams(1280, 1024, 8, 5.4, 5.4);

    if (sim == false)
    {
        ShowExtendedOptions();
        DEBUG(INDI::Logger::DBG_SESSION, "Please update the camera pixel size in the Image Info section. The camera resolution will be updated after the first exposure is complete.");

        // Only show mirror lock if the camera is canon
        ITextVectorProperty *modelTP = getText("model");
        if (modelTP && !strcmp(modelTP->label, "model") && strstr(modelTP->tp[0].text, "Canon"))
            defineNumber(&mMirrorLockNP);
    }

    //timerID = SetTimer(POLLMS);
  } else
  {
    if (mIsoSP.nsp > 0)
       deleteProperty(mIsoSP.name);
    if (mFormatSP.nsp > 0)
       deleteProperty(mFormatSP.name);

    deleteProperty(mMirrorLockNP.name);

    deleteProperty(livePreviewSP.name);
    deleteProperty(autoFocusSP.name);    
    deleteProperty(transferFormatSP.name);
    deleteProperty(FocusMotionSP.name);
    deleteProperty(FocusSpeedNP.name);
    deleteProperty(FocusTimerNP.name);

    HideExtendedOptions();
    //rmTimer(timerID);
  }

  return true;
}
示例#3
0
/*******************************************************************************
** Setting up CCD parameters
*******************************************************************************/
void DSICCD::setupParams()
{
    SetCCDParams(dsi->getImageWidth(), dsi->getImageHeight(),
        dsi->getReadBpp() * 8, dsi->getPixelSizeX(), dsi->getPixelSizeY());

    /* calculate how much memory we need for the primary CCD buffer */
    PrimaryCCD.setFrameBufferSize(PrimaryCCD.getXRes() *
                                  PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8);
}
示例#4
0
文件: ffmv_ccd.cpp 项目: A-j-K/indi
/**************************************************************************************
** Setting up CCD parameters
***************************************************************************************/
void FFMVCCD::setupParams()
{
    // The FireFly MV has a Micron MT9V022 CMOS sensor
    SetCCDParams(640, 480, 16, 6.0, 6.0);

    // Let's calculate how much memory we need for the primary CCD buffer
    int nbuf;
    nbuf=PrimaryCCD.getXRes()*PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8;
    PrimaryCCD.setFrameBufferSize(nbuf);
}
示例#5
0
/**************************************************************************************
** Setting up CCD parameters
***************************************************************************************/
void INovaCCD::setupParams()
{
    int bpp = iNovaSDK_GetDataWide() > 0 ? 16 : 8;
    SetCCDParams(iNovaSDK_GetImageWidth(), iNovaSDK_GetImageHeight(), bpp, iNovaSDK_GetPixelSizeX(), iNovaSDK_GetPixelSizeY());

    // Let's calculate how much memory we need for the primary CCD buffer
    int nbuf;
    nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8;
    nbuf += 512;  //  leave a little extra at the end
    PrimaryCCD.setFrameBufferSize(nbuf);
}
示例#6
0
文件: qhy_ccd.cpp 项目: A-j-K/indi
bool QHYCCD::setupParams()
{

    uint32_t nbuf,ret,imagew,imageh,bpp;
    double chipw,chiph,pixelw,pixelh;

    if (sim)
    {
        chipw=imagew=1280;
        chiph=imageh=1024;
        pixelh = pixelw = 5.4;
        bpp=8;
    }
    else
    {
        ret = GetQHYCCDChipInfo(camhandle,&chipw,&chiph,&imagew,&imageh,&pixelw,&pixelh,&bpp);

        /* JM: We need GetQHYCCDErrorString(ret) to get the string description of the error, please implement this in the SDK */
        if (ret != QHYCCD_SUCCESS)
        {
            DEBUGF(INDI::Logger::DBG_ERROR, "Error: GetQHYCCDChipInfo() (%d)", ret);
            return false;
        }

        DEBUGF(INDI::Logger::DBG_DEBUG, "GetQHYCCDChipInfo: chipW :%g chipH: %g imageW: %g imageH: %g pixelW: %g pixelH: %g bbp %g",
                                chipw,chiph,imagew,imageh,pixelw,pixelh,bpp);

        camroix = 0;
        camroiy = 0;
        camroiwidth = imagew;
        camroiheight = imageh;
    }

    SetCCDParams(imagew,imageh,bpp,pixelw,pixelh);

    nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8;
    PrimaryCCD.setFrameBufferSize(nbuf);

#ifndef OSX_EMBEDED_MODE
    streamer->setPixelFormat(V4L2_PIX_FMT_GREY);
    streamer->setRecorderSize(imagew,imageh);
#endif
    return true;
}
示例#7
0
bool FishCampCCD::initProperties()
{
    // Init parent properties first
    INDI::CCD::initProperties();

    IUFillNumber(&GainN[0], "Range", "", "%g", 1, 15, 1., 4.);
    IUFillNumberVector(&GainNP, GainN, 1, getDeviceName(), "Gain", "", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);

    IUFillNumber(&CoolerN[0], "Power %", "", "%g", 1, 100, 0, 0.0);
    IUFillNumberVector(&CoolerNP, CoolerN, 1, getDeviceName(), "Cooler", "", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);

    char *strBuf = new char[MAXINDINAME];

    IUFillText(&CamInfoT[0], "Name", "", name);
    IUFillText(&CamInfoT[1], "Serial #", "", (char *)&camInfo.camSerialStr);

    snprintf(strBuf, MAXINDINAME, "%d", camInfo.boardVersion);
    IUFillText(&CamInfoT[2], "Board version", "", strBuf);

    snprintf(strBuf, MAXINDINAME, "%d", camInfo.boardRevision);
    IUFillText(&CamInfoT[3], "Board revision", "", strBuf);

    snprintf(strBuf, MAXINDINAME, "%d", camInfo.fpgaVersion);
    IUFillText(&CamInfoT[4], "FPGA version", "", strBuf);

    snprintf(strBuf, MAXINDINAME, "%d", camInfo.fpgaRevision);
    IUFillText(&CamInfoT[5], "FPGA revision", "", strBuf);

    IUFillTextVector(&CamInfoTP, CamInfoT, 6, getDeviceName(), "Camera Info", "", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);

    SetCCDParams(camInfo.width, camInfo.height, 16, camInfo.pixelWidth / 10.0, camInfo.pixelHeight / 10.0);

    int nbuf;
    nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8; //  this is pixel cameraCount
    nbuf += 512;                                                                  //  leave a little extra at the end
    PrimaryCCD.setFrameBufferSize(nbuf);

    SetCCDCapability(CCD_CAN_ABORT | CCD_CAN_SUBFRAME | CCD_HAS_COOLER | CCD_HAS_ST4_PORT);

    delete[] strBuf;

    return true;
}
示例#8
0
bool CCDSim::SetupParms()
{
    int nbuf;
    SetCCDParams(SimulatorSettingsN[0].value,SimulatorSettingsN[1].value,16,SimulatorSettingsN[2].value,SimulatorSettingsN[3].value);

    //  Kwiq
    maxnoise=SimulatorSettingsN[8].value;
    skyglow=SimulatorSettingsN[9].value;
    maxval=SimulatorSettingsN[4].value;
    bias=SimulatorSettingsN[5].value;
    limitingmag=SimulatorSettingsN[7].value;
    saturationmag=SimulatorSettingsN[6].value;
    OAGoffset=SimulatorSettingsN[10].value;    //  An oag is offset this much from center of scope position (arcminutes);

    nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8;
    nbuf += 512;
    PrimaryCCD.setFrameBufferSize(nbuf);

    GetFilterNames(FILTER_TAB);

    return true;
}
示例#9
0
bool ASICCD::setupParams()
{
    ASI_ERROR_CODE errCode = ASI_SUCCESS;
    int piNumberOfControls = 0;

    errCode = ASIGetNumOfControls(m_camInfo->CameraID, &piNumberOfControls);

    if (errCode != ASI_SUCCESS)
        DEBUGF(INDI::Logger::DBG_DEBUG, "ASIGetNumOfControls error (%d)", errCode);

  if (piNumberOfControls > 0)
  {
      if (ControlNP.nnp > 0)
          free(ControlN);

      if (ControlSP.nsp > 0)
          free(ControlS);

      createControls(piNumberOfControls);
  }

  // Set minimum ASI_BANDWIDTHOVERLOAD on ARM
  #ifdef LOW_USB_BANDWIDTH
  ASI_CONTROL_CAPS pCtrlCaps;
  for(int j = 0; j < piNumberOfControls; j++)
  {
      ASIGetControlCaps(m_camInfo->CameraID, j, &pCtrlCaps);
      if (pCtrlCaps.ControlType == ASI_BANDWIDTHOVERLOAD)
      {
          DEBUGF(INDI::Logger::DBG_DEBUG, "setupParams->set USB %d", pCtrlCaps.MinValue);
          ASISetControlValue(m_camInfo->CameraID, ASI_BANDWIDTHOVERLOAD, pCtrlCaps.MinValue, ASI_FALSE);
          break;
      }
  }
  #endif

  // Get Image Format
  int w=0, h=0, bin=0;
  ASI_IMG_TYPE imgType;
  ASIGetROIFormat(m_camInfo->CameraID, &w, &h, &bin, &imgType);

  DEBUGF(INDI::Logger::DBG_DEBUG, "CCD ID: %d Width: %d Height: %d Binning: %dx%d Image Type: %d", m_camInfo->CameraID, w, h, bin, bin, imgType);

  // Get video format and bit depth
  int bit_depth = 8;

  switch (imgType)
  {
    case ASI_IMG_RAW16:
      bit_depth = 16;

    default:
      break;
  }

  if (VideoFormatSP.nsp > 0)
      free(VideoFormatS);

  VideoFormatS = NULL;
  int nVideoFormats = 0;

  for (int i=0; i < 8; i++)
  {
        if (m_camInfo->SupportedVideoFormat[i] == ASI_IMG_END)
            break;

        nVideoFormats++;
        VideoFormatS = VideoFormatS == NULL ? (ISwitch *) malloc(sizeof(ISwitch)) : (ISwitch *) realloc(VideoFormatS, nVideoFormats * sizeof(ISwitch));

        ISwitch *oneVF = VideoFormatS + (nVideoFormats-1);

        switch (m_camInfo->SupportedVideoFormat[i])
        {
            case ASI_IMG_RAW8:
                IUFillSwitch(oneVF, "ASI_IMG_RAW8", "Raw 8 bit", (imgType == ASI_IMG_RAW8) ? ISS_ON : ISS_OFF);
                DEBUG(INDI::Logger::DBG_DEBUG, "Supported Video Format: ASI_IMG_RAW8");
                break;

            case ASI_IMG_RGB24:
                IUFillSwitch(oneVF, "ASI_IMG_RGB24", "RGB 24", (imgType == ASI_IMG_RGB24) ? ISS_ON : ISS_OFF);
                DEBUG(INDI::Logger::DBG_DEBUG, "Supported Video Format: ASI_IMG_RGB24");
                break;

            case ASI_IMG_RAW16:
                IUFillSwitch(oneVF, "ASI_IMG_RAW16", "Raw 16 bit", (imgType == ASI_IMG_RAW16) ? ISS_ON : ISS_OFF);
                DEBUG(INDI::Logger::DBG_DEBUG, "Supported Video Format: ASI_IMG_RAW16");
            break;

            case ASI_IMG_Y8:
                IUFillSwitch(oneVF, "ASI_IMG_Y8", "Luma", (imgType == ASI_IMG_Y8) ? ISS_ON : ISS_OFF);
                DEBUG(INDI::Logger::DBG_DEBUG, "Supported Video Format: ASI_IMG_Y8");
                break;

            default:
                DEBUGF(INDI::Logger::DBG_DEBUG, "Unknown video format (%d)", m_camInfo->SupportedVideoFormat[i]);
                break;
        }

        oneVF->aux = (void *) &m_camInfo->SupportedVideoFormat[i];
  }

  VideoFormatSP.nsp = nVideoFormats;
  VideoFormatSP.sp  = VideoFormatS;

  float x_pixel_size, y_pixel_size;
  int x_1, y_1, x_2, y_2;

  x_pixel_size = m_camInfo->PixelSize;
  y_pixel_size = m_camInfo->PixelSize;

   x_1 = y_1 = 0;
   x_2 = m_camInfo->MaxWidth;
   y_2 = m_camInfo->MaxHeight;

  SetCCDParams(x_2 - x_1, y_2 - y_1, bit_depth, x_pixel_size, y_pixel_size);

  // Let's calculate required buffer
  int nbuf;
  nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8;    //  this is pixel cameraCount
  //nbuf += 512;    //  leave a little extra at the end
  PrimaryCCD.setFrameBufferSize(nbuf);

  //if (HasCooler())
  //{
      long pValue = 0;
      ASI_BOOL isAuto= ASI_FALSE;

      if ( (errCode = ASIGetControlValue(m_camInfo->CameraID, ASI_TEMPERATURE, &pValue, &isAuto)) != ASI_SUCCESS)
          DEBUGF(INDI::Logger::DBG_DEBUG, "ASIGetControlValue temperature error (%d)", errCode);

      TemperatureN[0].value = pValue / 10.0;

      DEBUGF(INDI::Logger::DBG_SESSION,  "The CCD Temperature is %f", TemperatureN[0].value);
      IDSetNumber(&TemperatureNP, NULL);
  //}

  ASIStopVideoCapture(m_camInfo->CameraID);

  DEBUGF(INDI::Logger::DBG_DEBUG, "setupParams ASISetROIFormat (%dx%d,  bin %d, type %d)", m_camInfo->MaxWidth, m_camInfo->MaxHeight, 1, imgType);
  ASISetROIFormat(m_camInfo->CameraID, m_camInfo->MaxWidth, m_camInfo->MaxHeight, 1, imgType);

  #if !defined(OSX_EMBEDED_MODE) && !defined(__CYGWIN__)
  updateRecorderFormat();
  streamer->setRecorderSize(w,h);
  #endif

  return true;

}
示例#10
0
bool QSICCD::setupParams()
{
    string name,model;
    double temperature;
    double pixel_size_x,pixel_size_y;
    long sub_frame_x,sub_frame_y;
    try
    {
        QSICam.get_Name(name);
        QSICam.get_ModelNumber(model);
        QSICam.get_PixelSizeX(&pixel_size_x);
        QSICam.get_PixelSizeY(&pixel_size_y);
        QSICam.get_NumX(&sub_frame_x);
        QSICam.get_NumY(&sub_frame_y);
        QSICam.get_CCDTemperature(&temperature);
    } catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_ERROR, "Setup Params failed. %s.", err.what());
        return false;
    }

    DEBUGF(INDI::Logger::DBG_SESSION, "The CCD Temperature is %f.", temperature);

    TemperatureN[0].value = temperature;			/* CCD chip temperatre (degrees C) */
    IDSetNumber(&TemperatureNP, NULL);

    SetCCDParams(sub_frame_x, sub_frame_y, 16, pixel_size_x, pixel_size_y);

    imageWidth  = PrimaryCCD.getSubW();
    imageHeight = PrimaryCCD.getSubH();

    int nbuf;
    nbuf=PrimaryCCD.getXRes()*PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8;                 //  this is pixel count
    nbuf+=512;                      //  leave a little extra at the end
    PrimaryCCD.setFrameBufferSize(nbuf);

    try
    {
     QSICam.get_Name(name);
    } catch (std::runtime_error& err)
    {
        DEBUGF(INDI::Logger::DBG_ERROR, "get_Name() failed. %s.", err.what());
        return false;
    }
    DEBUGF(INDI::Logger::DBG_SESSION, "%s", name.c_str());

    int filter_count;
    try
    {
            QSICam.get_FilterCount(filter_count);
    } catch (std::runtime_error err)
    {
            DEBUGF(INDI::Logger::DBG_SESSION, "get_FilterCount() failed. %s.", err.what());
            return false;
    }

    DEBUGF(INDI::Logger::DBG_SESSION,"The filter count is %d", filter_count);


    FilterSlotN[0].max = filter_count;
    FilterSlotNP.s = IPS_OK;

    IUUpdateMinMax(&FilterSlotNP);
    IDSetNumber(&FilterSlotNP, NULL);

    FilterSP.s = IPS_OK;
    IDSetSwitch(&FilterSP,NULL);

    GetFilterNames(FILTER_TAB);

    double minDuration=0;

    try
    {
        QSICam.get_MinExposureTime(&minDuration);
    } catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_ERROR, "get_MinExposureTime() failed. %s.", err.what());
        return false;
    }

    PrimaryCCD.setMinMaxStep("CCD_EXPOSURE", "CCD_EXPOSURE_VALUE", minDuration, 3600, 1, true);

    bool coolerOn=false;

    try
    {
         QSICam.get_CoolerOn(&coolerOn);
    } catch (std::runtime_error err)
    {
            CoolerSP.s = IPS_IDLE;
            CoolerS[0].s = ISS_OFF;
            CoolerS[1].s = ISS_ON;
            DEBUGF(INDI::Logger::DBG_ERROR, "Error: CoolerOn() failed. %s.", err.what());
            IDSetSwitch(&CoolerSP, NULL);
            return false;
    }

    CoolerS[0].s = coolerOn ? ISS_ON : ISS_OFF;
    CoolerS[1].s = coolerOn ? ISS_OFF : ISS_ON;
    CoolerSP.s = IPS_OK;
    IDSetSwitch(&CoolerSP, NULL);

    QSICamera::CameraGain cGain = QSICamera::CameraGainAuto;
    canSetGain = false;

    QSICam.get_CanSetGain(&canSetGain);

    if (canSetGain)
    {
        try
        {
            QSICam.get_CameraGain(&cGain);
        }
        catch (std::runtime_error err)
        {
            DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not support gain. %s.", err.what());
            canSetGain = false;
        }

        if (canSetGain)
        {
            IUResetSwitch(&GainSP);
            GainS[cGain].s = ISS_ON;
            defineSwitch(&GainSP);
        }
    }

    QSICamera::AntiBloom cAB = QSICamera::AntiBloomNormal;
    canSetAB = true;

    try
    {
        QSICam.get_AntiBlooming(&cAB);
    }
    catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not support AntiBlooming control. %s.", err.what());
        canSetAB = false;
    }

    if (canSetAB)
    {
        IUResetSwitch(&ABSP);
        ABS[cAB].s = ISS_ON;
        defineSwitch(&ABSP);
    }


    QSICamera::FanMode fMode = QSICamera::fanOff;
    canControlFan = true;

    try
    {
        QSICam.get_FanMode(fMode);
    }
    catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not support fan control. %s.", err.what());
        canControlFan = false;
    }

    if (canControlFan)
    {
        IUResetSwitch(&FanSP);
        FanS[fMode].s = ISS_ON;
        defineSwitch(&FanSP);
    }

    canChangeReadoutSpeed = true;
    QSICamera::ReadoutSpeed cReadoutSpeed;

    try
    {
        QSICam.get_ReadoutSpeed(cReadoutSpeed);
    }
    catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not support changing readout speed. %s.", err.what());
        canChangeReadoutSpeed = false;
    }

    if (canChangeReadoutSpeed)
    {
        // get_ReadoutSpeed succeeds even if the camera does not support that, so the only way to make sure is to set it
        try
        {
            QSICam.put_ReadoutSpeed(cReadoutSpeed);
        }
        catch (std::runtime_error err)
        {
            DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not support changing readout speed. %s.", err.what());
            canChangeReadoutSpeed = false;
        }

        if (canChangeReadoutSpeed)
        {
            IUResetSwitch(&ReadOutSP);
            ReadOutS[cReadoutSpeed].s = ISS_ON;
            defineSwitch(&ReadOutSP);
        }
    }

    // Can flush
    canFlush = false;
    try
    {
        QSICam.put_PreExposureFlush(QSICamera::FlushNormal);
        canFlush = true;
    }
    catch (std::runtime_error err)
    {
        DEBUGF(INDI::Logger::DBG_DEBUG, "Camera does not pre-exposure flushing %s.", err.what());
        canFlush = false;
    }

    return true;
}
示例#11
0
文件: atik_ccd.cpp 项目: azwing/indi
bool ATIKCCD::setupParams()
{
    ARTEMISPROPERTIES pProp;

    int rc = ArtemisProperties(hCam, &pProp);

    if (rc != ARTEMIS_OK)
    {
        LOGF_ERROR("Failed to inquire camera properties (%d)", rc);
        return false;
    }

    // Camera & Pixel properties
    // FIXME is it always 16bit depth?
    SetCCDParams(pProp.nPixelsX, pProp.nPixelsY, 16, pProp.PixelMicronsX, pProp.PixelMicronsY);
    // Set frame buffer size
    PrimaryCCD.setFrameBufferSize(PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8, false);

    m_CameraFlags = pProp.cameraflags;
    LOGF_DEBUG("Camera flags: %d", m_CameraFlags);

    int binX = 1, binY = 1;

    rc = ArtemisGetMaxBin(hCam, &binX, &binY);

    if (rc != ARTEMIS_OK)
    {
        LOGF_ERROR("Failed to inquire camera max binning (%d)", rc);
    }

    PrimaryCCD.setMinMaxStep("CCD_EXPOSURE", "CCD_EXPOSURE_VALUE", 0.001, 3600, 1, false);
    PrimaryCCD.setMinMaxStep("CCD_BINNING", "HOR_BIN", 1, binX, 1, false);
    PrimaryCCD.setMinMaxStep("CCD_BINNING", "VER_BIN", 1, binY, 1, false);

    IUSaveText(&VersionInfoS[VERSION_FIRMWARE], std::to_string(pProp.Protocol).c_str());
    LOGF_INFO("Detected camera %s %s with firmware %s", pProp.Manufacturer, pProp.Description, std::to_string(pProp.Protocol).c_str());

    uint32_t cap = 0;

    // All Atik cameras can abort and subframe
    cap = CCD_CAN_ABORT | CCD_CAN_SUBFRAME;

    // Can we bin?
    if (binX > 1)
    {
        cap |= CCD_CAN_BIN;
        LOG_DEBUG("Camera can bin.");
    }

    // Do we have color or mono camera?
    ARTEMISCOLOURTYPE colorType;
    rc = ArtemisColourProperties(hCam, &colorType, &normalOffsetX, &normalOffsetY, &previewOffsetX, &previewOffsetY);

    if (rc != ARTEMIS_OK)
    {
        LOGF_ERROR("Failed to inquire camera color (%d). Assuming Mono.", rc);
    }
    if (colorType == ARTEMIS_COLOUR_RGGB)
    {
        cap |= CCD_HAS_BAYER;
        IUSaveText(&BayerT[0], std::to_string(normalOffsetX).c_str());
        IUSaveText(&BayerT[1], std::to_string(normalOffsetY).c_str());
    }

    LOGF_DEBUG("Camera is %s.", colorType == ARTEMIS_COLOUR_RGGB ? "Color" : "Mono");

    // Do we have temperature?
    rc = ArtemisTemperatureSensorInfo(hCam, 0, &m_TemperatureSensorsCount);
    LOGF_DEBUG("Camera has %d temperature sensor(s).", m_TemperatureSensorsCount);
    if (m_TemperatureSensorsCount > 0)
    {
        // Do we have cooler control?
        int flags, level, minlvl, maxlvl, setpoint;
        rc = ArtemisCoolingInfo(hCam, &flags, &level, &minlvl, &maxlvl, &setpoint);
        if (flags & 0x1)
        {
            LOG_DEBUG("Camera supports cooling control.");
            cap |= CCD_HAS_COOLER;
        }

        genTimerID = SetTimer(TEMP_TIMER_MS);
    }

    // Do we have mechanical shutter?
    if (m_CameraFlags & ARTEMIS_PROPERTIES_CAMERAFLAGS_HAS_SHUTTER)
    {
        LOG_DEBUG("Camera has mechanical shutter.");
        cap |= CCD_HAS_SHUTTER;
    }

    // Do we have guide port?
    if (m_CameraFlags & ARTEMIS_PROPERTIES_CAMERAFLAGS_HAS_GUIDE_PORT)
    {
        LOG_DEBUG("Camera has guide port.");
        cap |= CCD_HAS_ST4_PORT;
    }

    // Done with the capabilities!
    SetCCDCapability(cap);

    // Check if camra has internal filter wheel
    if (m_CameraFlags & ARTEMIS_PROPERTIES_CAMERAFLAGS_HAS_FILTERWHEEL)
    {
        int numFilters, moving, currentPos, targetPos;
        rc = ArtemisFilterWheelInfo(hCam, &numFilters, &moving, &currentPos, &targetPos);
        if (rc != ARTEMIS_OK)
        {
            LOGF_ERROR("Failed to inquire internal filter wheel info (%d). Filter wheel functions are disabled.", rc);
        }
        else
        {
            setDriverInterface(getDriverInterface() | FILTER_INTERFACE);

            FilterSlotN[0].min = 1;
            FilterSlotN[0].max = numFilters;

            LOGF_INFO("Detected %d-position internal filter wheel.", numFilters);
        }
    }

    // Check if we have Horizon camera
    m_isHorizon = ArtemisHasCameraSpecificOption(hCam, 1);
    if (m_isHorizon)
    {
        uint8_t data[2] = {0};
        int len = 0, index = 0;
        ArtemisCameraSpecificOptionGetData(hCam, ID_AtikHorizonGOPresetMode, data, 2, &len);
        index = *(reinterpret_cast<uint16_t*>(&data));
        LOGF_DEBUG("Horizon current GO mode: data[0] %d data[1] %d index %d", data[0], data[1], index);
        IUResetSwitch(&ControlPresetsSP);
        ControlPresetsS[index].s = ISS_ON;

        // Get Gain & Offset valuse
        ArtemisCameraSpecificOptionGetData(hCam, ID_AtikHorizonGOCustomGain, data, 2, &len);
        index = *(reinterpret_cast<uint16_t*>(&data));
        LOGF_DEBUG("Horizon current gain: data[0] %d data[1] %d value %d", data[0], data[1], index);

        ArtemisCameraSpecificOptionGetData(hCam, ID_AtikHorizonGOCustomOffset, data, 2, &len);
        index = *(reinterpret_cast<uint16_t*>(&data));
        LOGF_DEBUG("Horizon current offset: data[0] %d data[1] %d value %d", data[0], data[1], index);
    }

    // Create imaging thread
    threadRequest = StateIdle;
    threadState = StateNone;
    int stat = pthread_create(&imagingThread, nullptr, &imagingHelper, this);
    if (stat != 0)
    {
        LOGF_ERROR("Error creating imaging thread (%d)", stat);
        return false;
    }
    pthread_mutex_lock(&condMutex);
    while (threadState == StateNone)
    {
        pthread_cond_wait(&cv, &condMutex);
    }
    pthread_mutex_unlock(&condMutex);

    return true;
}