23#include <libnova/julian_day.h>
43static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
44static pthread_mutex_t condMutex = PTHREAD_MUTEX_INITIALIZER;
46static std::unique_ptr<CCDSim> ccdsim(
new CCDSim());
113 pthread_mutex_lock(&condMutex);
116 pthread_cond_signal(&cv);
117 pthread_mutex_unlock(&condMutex);
124 return "CCD Simulator";
196 IUFillNumber(&
FWHMN[0],
"SIM_FWHM",
"FWHM (arcseconds)",
"%4.2f", 0, 60, 0, 7.5);
206 GainNP[0].
fill(
"GAIN",
"value",
"%.f", 0, 300, 10, 90);
210 OffsetNP[0].
fill(
"OFFSET",
"value",
"%.f", 0, 6000, 500, 0);
227 std::ostringstream ss;
238#ifdef USE_EQUATORIAL_PE
437 LOGF_DEBUG(
"Using cached planet render (%.1f minutes since last render)", elapsedMinutes);
526 if (timeleft <= 0.001)
537 nextTimer = timeleft * 1000;
553 if (timeleft <= 0.001)
566 nextTimer = timeleft * 1000;
578 nextTimer = timeleft * 1000;
586 constexpr double AMBIENT_TEMPERATURE = 25.0;
587 constexpr double MIN_TEC_TEMPERATURE = -15.0;
591 const double targetTemp = std::clamp(
TemperatureRequest, MIN_TEC_TEMPERATURE, AMBIENT_TEMPERATURE);
601 double newTemp = currentTemp;
603 if (targetTemp < newTemp)
606 newTemp = std::max(targetTemp, newTemp - 0.5);
608 else if (targetTemp > newTemp)
612 double deltaT = AMBIENT_TEMPERATURE - newTemp;
615 double warmingStep = deltaT * 0.2;
616 if (warmingStep < 0.02)
618 if (warmingStep > 0.5)
620 newTemp = std::min(targetTemp, newTemp + warmingStep);
649 uint16_t * ptr =
reinterpret_cast<uint16_t *
>(targetChip->
getFrameBuffer());
651 if (targetChip->
getXRes() == 500)
658 exposure_time *= (1 + sqrt(
GainNP[0].getValue()));
671 double timesince = difftime(now,
RunStart);
672 double PESpot = timesince /
m_PEPeriod * 2.0 * 3.14159;
673 PEOffset =
m_PEMax * std::sin(PESpot) / 3600.0f;
686#ifdef USE_EQUATORIAL_PE
694 static bool s_warnedNoSnoop =
false;
695 if (!s_warnedNoSnoop)
697 LOG_WARN(
"EQUATORIAL_PE not yet snooped -- rendering at raw EQUATORIAL_EOD_COORD (mount errors not active)");
698 s_warnedNoSnoop =
true;
717#ifdef USE_EQUATORIAL_PE
722 double ra_deg =
currentRA * 15.0 + PEOffset;
724 double decr = cameradec * 0.0174532925;
726 double dec_deg = cameradec + decDrift / 3600.0;
745 if (isLight || isFlat)
748 targetFocalLength, theta, exposure_time, isLight);
749 if (isLight && drawn < 0)
750 LOG_ERROR(
"Error launching gsc, is it installed with appropriate environment variables set?");
751 else if (isLight && drawn == 0)
752 LOG_WARN(
"No stars found in field -- check gsc catalog coverage for this region.");
770 for (
int x = 0; x < nbuf; x++)
785 gettimeofday(&now,
nullptr);
786 double const timesince = (now.tv_sec * 1000.0 + now.tv_usec / 1000.0)
787 - (start.tv_sec * 1000.0 + start.tv_usec / 1000.0);
788 return static_cast<float>(req - timesince / 1000.0);
806 c = c / 3600.0 / 15.0;
817 c = c / 3600.0 / 15.0;
825bool CCDSim::ISNewText(
const char * dev,
const char * name,
char * texts[],
char * names[],
int n)
1007 constexpr double AMBIENT_TEMPERATURE = 25.0;
1038 LOG_INFO(
"Directory-based images are disabled.");
1050 if (index >= 0 && index <
static_cast<int>(
Resolutions.size() - 1))
1087 rgbIndex =
static_cast<int>(i);
1116 monoIndex =
static_cast<int>(i);
1130 LOG_INFO(
"Planet simulation disabled. Returning to star field mode.");
1141 static const char* planetNames[] =
1143 "mercury",
"venus",
"mars",
"jupiter",
"saturn",
1144 "uranus",
"neptune",
"moon",
"sun"
1146 if (index >= 0 && index < 9)
1166 if (dirp ==
nullptr)
1175 if (directory[std::string(directory).length() - 1] !=
'/')
1179 static const std::vector<std::string> supportedExtensions =
1187 auto hasSupportedExtension = [](
const std::string &name)
1189 for (
const auto &extension : supportedExtensions)
1191 if (name.size() < extension.size())
1193 if (strcasecmp(name.c_str() + name.size() - extension.size(), extension.c_str()) == 0)
1199 while ((dp = readdir(dirp)) != NULL)
1201 if (hasSupportedExtension(dp->d_name))
1208 LOGF_ERROR(
"No supported image files (.fit, .fits%s) found in directory %s",
1221 LOGF_INFO(
"Directory-based images are enabled. Subsequent exposures will be loaded from directory %s",
1230#ifdef USE_EQUATORIAL_PE
1251 if (!strcmp(propName,
"ABS_FOCUS_POSITION"))
1257 if (!strcmp(name,
"FOCUS_ABSOLUTE_POSITION"))
1269 m_Seeing = 0.5625 * ticks * ticks + optimalFWHM;
1274 else if (!strcmp(propName,
"ABS_ROTATOR_ANGLE"))
1280 if (!strcmp(name,
"ANGLE"))
1290#ifdef USE_EQUATORIAL_PE
1291 if (!strcmp(propName,
"EQUATORIAL_PE"))
1293 int rc_ra = -1, rc_de = -1;
1294 double newra = 0, newdec = 0;
1300 if (!strcmp(elemName,
"RA_PE"))
1302 else if (!strcmp(elemName,
"DEC_PE"))
1306 if (rc_ra == 0 && rc_de == 0)
1310 raPE = J2000Pos.rightascension;
1311 decPE = J2000Pos.declination;
1316 if (!
usePE && strcmp(state,
"Ok") == 0)
1318 LOGF_INFO(
"EQUATORIAL_PE snoop active: JNow RA %.4f Dec %.4f -> J2000 RA %.4f Dec %.4f", newra, newdec,
raPE,
decPE);
1326 LOGF_DEBUG(
"Snooped EQUATORIAL_PE JNow RA %g Dec %g -> J2000 RA %g Dec %g", newra, newdec,
raPE,
decPE);
1372 std::random_device rd;
1373 std::mt19937 gen(rd());
1374 std::uniform_int_distribution<> dist(1500, 2000);
1375 std::this_thread::sleep_for(std::chrono::milliseconds(dist(gen)));
1403 pthread_mutex_lock(&condMutex);
1405 pthread_mutex_unlock(&condMutex);
1406 pthread_cond_signal(&cv);
1413 pthread_mutex_lock(&condMutex);
1415 pthread_mutex_unlock(&condMutex);
1416 pthread_cond_signal(&cv);
1426 bin_width = bin_width - (bin_width % 2);
1427 bin_height = bin_height - (bin_height % 2);
1429 Streamer->setSize(bin_width, bin_height);
1439 LOG_ERROR(
"Binning is not supported in planet mode.");
1445 LOGF_ERROR(
"%dx%d binning is not supported.", hor, ver);
1451 Streamer->setSize(bin_width, bin_height);
1460 LOGF_ERROR(
"%dx%d binning is not supported.", hor, ver);
1474 auto start = std::chrono::high_resolution_clock::now();
1478 pthread_mutex_lock(&condMutex);
1482 pthread_cond_wait(&cv, &condMutex);
1490 pthread_mutex_unlock(&condMutex);
1499 auto finish = std::chrono::high_resolution_clock::now();
1500 std::chrono::duration<double> elapsed = finish - start;
1513 auto finish = std::chrono::high_resolution_clock::now();
1514 std::chrono::duration<double> elapsed = finish - start;
1522 start = std::chrono::high_resolution_clock::now();
1525 pthread_mutex_unlock(&condMutex);
1540 if (focalLength <= 0)
1541 focalLength = 1000.0f;
1542 float arcsecPerPixelX = 206.265f * pixelSizeX / focalLength;
1543 float arcsecPerPixelY = 206.265f * pixelSizeY / focalLength;
1546 float planetDiameterArcsec = 0;
1555 planetDiameterArcsec = it->second;
1557 planetDiameterArcsec = 42.0f;
1561 float planetPixelsX = planetDiameterArcsec / arcsecPerPixelX;
1562 float planetPixelsY = planetDiameterArcsec / arcsecPerPixelY;
1563 float avgPlanetPixels = (planetPixelsX + planetPixelsY) / 2.0f;
1569 const int renderSize = 1024;
1570 const float planetRange = 0.05f;
1573 float planetDiamDeg = planetDiameterArcsec / 3600.0f;
1574 float planetFracOfFrame = planetDiamDeg / planetRange;
1575 float srcPlanetRadius = planetFracOfFrame * renderSize / 2.0f;
1576 if (srcPlanetRadius < 10.0f) srcPlanetRadius = 10.0f;
1580 std::string searchDir;
1582 if (configPos != std::string::npos)
1585 const char *pngPath =
"/tmp/indi_planet.png";
1587 const bool useCustomConfig = (
m_XPlanetConfig !=
"/usr/share/xplanet/config/default");
1589 if (!searchDir.empty() && useCustomConfig)
1591 snprintf(
cmd,
sizeof(
cmd),
1592 "%s -body %s -geometry %dx%d -range %.4f "
1593 "-num_times 1 -projection orthographic "
1594 "-config %s -searchdir %s "
1595 "-output %s 2>/dev/null",
1597 renderSize, renderSize,
static_cast<double>(planetRange),
1600 else if (!searchDir.empty())
1602 snprintf(
cmd,
sizeof(
cmd),
1603 "%s -body %s -geometry %dx%d -range %.4f "
1604 "-num_times 1 -projection orthographic "
1606 "-output %s 2>/dev/null",
1608 renderSize, renderSize,
static_cast<double>(planetRange),
1609 searchDir.c_str(), pngPath);
1613 snprintf(
cmd,
sizeof(
cmd),
1614 "%s -body %s -geometry %dx%d -range %.4f "
1615 "-num_times 1 -projection orthographic "
1616 "-output %s 2>/dev/null",
1618 renderSize, renderSize,
static_cast<double>(planetRange), pngPath);
1622 uint32_t rgbBufSize = width * height * 3 * 2;
1634 LOG_DEBUG(
"Cache params changed, re-rendering");
1644 int ret = system(
cmd);
1647 LOGF_ERROR(
"xplanet failed with exit code %d. Is xplanet installed?", ret);
1655 int planetRenderPixels =
static_cast<int>(avgPlanetPixels);
1656 if (planetRenderPixels < 1) planetRenderPixels = 1;
1657 snprintf(jpgCmd,
sizeof(jpgCmd),
1658 "convert %s -resize %dx%d -background black "
1659 "-gravity center -extent %dx%d -quality 90 /tmp/indi_planet.jpg 2>/dev/null",
1660 pngPath, planetRenderPixels, planetRenderPixels,
1661 static_cast<int>(width),
static_cast<int>(height));
1662 ret = system(jpgCmd);
1665 LOG_ERROR(
"Failed to generate CCD-resolution JPEG. Is ImageMagick installed?");
1671 FILE *jpgFile = fopen(
"/tmp/indi_planet.jpg",
"rb");
1674 fseek(jpgFile, 0, SEEK_END);
1675 long jpgSize = ftell(jpgFile);
1676 fseek(jpgFile, 0, SEEK_SET);
1683 ret = system(
"convert /tmp/indi_planet.png /tmp/indi_planet.ppm 2>/dev/null");
1686 LOG_ERROR(
"Failed to convert PNG to PPM. Is ImageMagick installed?");
1691 FILE *fp = fopen(
"/tmp/indi_planet.ppm",
"rb");
1694 LOG_ERROR(
"Failed to open /tmp/indi_planet.ppm");
1699 if (fscanf(fp,
"%2s\n", magic) != 1 || strcmp(magic,
"P6") != 0)
1701 LOG_ERROR(
"PPM file is not P6 format (binary RGB)");
1706 int ppmWidth, ppmHeight, maxVal;
1711 while (fgetc(fp) !=
'\n');
1715 if (fscanf(fp,
"%d %d\n%d\n", &ppmWidth, &ppmHeight, &maxVal) != 3)
1717 LOG_ERROR(
"Failed to parse PPM header");
1722 std::vector<uint8_t> rgbData(ppmWidth * ppmHeight * 3);
1723 size_t bytesRead = fread(rgbData.data(), 1, rgbData.size(), fp);
1726 if (bytesRead != rgbData.size())
1728 LOGF_ERROR(
"PPM read error: expected %zu bytes, got %zu", rgbData.size(), bytesRead);
1739 memset(buffer, 0, rgbBufSize);
1742 size_t planeSize =
static_cast<size_t>(width) *
static_cast<size_t>(height);
1743 uint16_t *rPlane = buffer;
1744 uint16_t *gPlane = buffer + planeSize;
1745 uint16_t *bPlane = buffer + planeSize * 2;
1748 float centerX = width / 2.0f;
1749 float centerY = height / 2.0f;
1752 float dstPlanetRadius = avgPlanetPixels / 2.0f;
1753 if (dstPlanetRadius < 1.0f)
1754 dstPlanetRadius = 1.0f;
1755 float scale = srcPlanetRadius / dstPlanetRadius;
1761 for (uint32_t y = 0; y < height; y++)
1763 for (uint32_t x = 0; x < width; x++)
1765 float sx = (x - centerX) * scale + ppmWidth / 2.0f;
1766 float sy = (y - centerY) * scale + ppmHeight / 2.0f;
1768 float dx = (sx - ppmWidth / 2.0f);
1769 float dy = (sy - ppmHeight / 2.0f);
1770 if (sqrtf(dx * dx + dy * dy) > srcPlanetRadius)
1773 int ix =
static_cast<int>(sx);
1774 int iy =
static_cast<int>(sy);
1775 if (ix < 0 || ix >= ppmWidth || iy < 0 || iy >= ppmHeight)
1778 int srcIdx = (iy * ppmWidth + ix) * 3;
1779 uint8_t r8 = rgbData[srcIdx];
1780 uint8_t g8 = rgbData[srcIdx + 1];
1781 uint8_t b8 = rgbData[srcIdx + 2];
1784 uint16_t r16 =
static_cast<uint16_t
>(r8) * 256;
1785 uint16_t g16 =
static_cast<uint16_t
>(g8) * 256;
1786 uint16_t b16 =
static_cast<uint16_t
>(b8) * 256;
1792 size_t px = y * width + x;
1819 LOGF_INFO(
"Rendered planet %s: diameter=%.1f arcsec, pixels=%.1f, scale=%.1f arcsec/px",
1820 m_SelectedPlanet.c_str(), planetDiameterArcsec, planetPixelsX, arcsecPerPixelX);
1830 fitsKeyword.push_back({
"GAIN",
GainNP[0].getValue(), 3,
"Gain"});
1834 fitsKeyword.emplace_back(
"OBJECT",
m_SelectedPlanet.c_str(),
"Target planet");
1835 fitsKeyword.emplace_back(
"XPLANET",
static_cast<int64_t
>(1),
"Generated by xplanet");
1836 fitsKeyword.emplace_back(
"COLORSPC",
"RGB",
"Color space");
1848 if (filename.size() >= 5 && strcasecmp(filename.c_str() + filename.size() - 5,
".xisf") == 0)
1849 return loadNextXISFImage(filename);
1857 char comment[512] = {0}, bayer_pattern[16] = {0};
1858 int status = 0, anynull = 0;
1859 double pixel_size = 5.2;
1860 int ndim {2}, bitpix {8};
1862 fitsfile *fptr =
nullptr;
1864 if (fits_open_diskfile(&fptr, filename.c_str(), READONLY, &status))
1866 char error_status[512] = {0};
1867 fits_get_errstatus(status, error_status);
1868 LOGF_WARN(
"Error opening file %s due to error %s", filename.c_str(), error_status);
1872 if (fits_get_img_param(fptr, 3, &bitpix, &ndim, naxes, &status))
1874 char error_status[512] = {0};
1875 fits_get_errstatus(status, error_status);
1876 LOGF_WARN(
"Error reading image parameters from %s due to error %s", filename.c_str(), error_status);
1877 fits_close_file(fptr, &status);
1885 int samples_per_channel = naxes[0] * naxes[1];
1886 int channels = naxes[2];
1887 int elements = samples_per_channel * channels;
1888 int size = elements * bitpix / 8;
1891 if (fits_read_img(fptr, bitpix == 8 ? TBYTE : TUSHORT, 1, elements, 0,
PrimaryCCD.
getFrameBuffer(), &anynull, &status))
1893 char error_status[512] = {0};
1894 fits_get_errstatus(status, error_status);
1895 LOGF_WARN(
"Error reading pixel data from %s due to error %s", filename.c_str(), error_status);
1896 fits_close_file(fptr, &status);
1904 if (fits_read_key_dbl(fptr,
"PIXSIZE1", &pixel_size, comment, &status))
1907 if (fits_read_key_dbl(fptr,
"XPIXSZ", &pixel_size, comment, &status))
1909 LOGF_DEBUG(
"No PIXSIZE1 or XPIXSZ keyword found in %s, defaulting pixel size to %.2f microns",
1910 filename.c_str(), pixel_size);
1915 if (fits_read_key_str(fptr,
"BAYERPAT", bayer_pattern, comment, &status))
1917 char error_status[512] = {0};
1918 fits_get_errstatus(status, error_status);
1919 LOGF_DEBUG(
"No BAYERPAT keyword found in %s (%s)", filename.c_str(), error_status);
1921 SetCCDParams(naxes[0], naxes[1], bitpix, pixel_size, pixel_size);
1924 if (channels == 1 && strlen(bayer_pattern) == 4)
1937 fits_close_file(fptr, &status);
1942bool CCDSim::loadNextXISFImage(
const std::string &filename)
1946 LibXISF::XISFReader reader;
1947 reader.open(filename);
1949 if (reader.imagesCount() < 1)
1951 LOGF_WARN(
"No images found in XISF file %s", filename.c_str());
1956 LibXISF::Image image = reader.getImage(0);
1958 const auto sampleFormat = image.sampleFormat();
1959 const bool isFloat = (sampleFormat == LibXISF::Image::Float32 || sampleFormat == LibXISF::Image::Float64);
1961 switch (sampleFormat)
1963 case LibXISF::Image::UInt8:
1966 case LibXISF::Image::UInt16:
1969 case LibXISF::Image::Float32:
1970 case LibXISF::Image::Float64:
1977 LOGF_WARN(
"Unsupported XISF sample format '%s' in %s. Only 8/16-bit integer and 32/64-bit "
1978 "normalized float samples are supported.",
1979 LibXISF::Image::sampleFormatString(sampleFormat).c_str(), filename.c_str());
1983 int channels =
static_cast<int>(image.channelCount());
1988 if (image.pixelStorage() != LibXISF::Image::Planar)
1989 image.convertPixelStorageTo(LibXISF::Image::Planar);
1991 const size_t elementCount = image.width() * image.height() * channels;
1996 auto scaleClamp = [](
double value) -> uint16_t
2002 return static_cast<uint16_t
>(std::lround(value * 65535.0));
2005 if (sampleFormat == LibXISF::Image::Float32)
2007 const float * src = image.imageData<
float>();
2008 for (
size_t i = 0; i < elementCount; i++)
2009 dest[i] = scaleClamp(src[i]);
2013 const double * src = image.imageData<
double>();
2014 for (
size_t i = 0; i < elementCount; i++)
2015 dest[i] = scaleClamp(src[i]);
2025 double pixel_size = 5.2;
2026 bool foundPixelSize =
false;
2027 for (
const auto &keyword : image.fitsKeywords())
2029 if (keyword.name ==
"PIXSIZE1" || keyword.name ==
"XPIXSZ")
2031 pixel_size = std::stod(keyword.value);
2032 foundPixelSize =
true;
2036 if (!foundPixelSize)
2037 LOGF_DEBUG(
"No PIXSIZE1 or XPIXSZ keyword found in %s, defaulting pixel size to %.2f microns",
2038 filename.c_str(), pixel_size);
2040 SetCCDParams(image.width(), image.height(), bitpix, pixel_size, pixel_size);
2043 const auto cfa = image.colorFilterArray();
2044 if (channels == 1 && cfa.pattern.size() == 4)
2056 catch (LibXISF::Error &error)
2058 LOGF_WARN(
"Error reading XISF file %s due to error: %s", filename.c_str(),
error.what());
2073 bool isRGB = (format.name ==
"INDI_RGB");
The CCDSim class provides an advanced simulator for a CCD that includes a dedicated on-board guide ch...
virtual bool UpdateCCDFrame(int x, int y, int w, int h) override
CCD calls this function when CCD Frame dimension needs to be updated in the hardware....
INDI::PropertyNumber TiltSimulationNP
uint32_t m_CachedPlanetHeight
bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
void setBayerEnabled(bool onOff)
INDI::PropertyNumber FocusSimulationNP
bool StartExposure(float duration) override
Start exposing primary CCD chip.
bool loadNextFITSImage(const std::string &filename)
virtual IPState GuideSouth(uint32_t) override
Guide southward for ms milliseconds.
INDI::PropertyText PlanetPathsTP
INDI::PropertyText DirectoryTP
INDI::PropertyNumber GainNP
static const constexpr char * SIMULATOR_TAB
std::string m_XPlanetConfig
float GuideRate
Guide rate is 7 arcseconds per second.
bool Disconnect() override
Disconnect from device.
INDI::PropertyNumber EqPENP
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool StartGuideExposure(float) override
Start exposing guide CCD chip.
std::vector< uint8_t > m_CachedPlanetBuffer
virtual bool SetCaptureFormat(uint8_t index) override
SetCaptureFormat Set Active Capture format.
INDI::PropertySwitch SimTestsSP
std::string m_XPlanetBinary
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual int SetTemperature(double temperature) override
Set CCD temperature.
static const std::map< std::string, float > PlanetAngularDiameter
uint32_t m_CachedPlanetWidth
const char * getDefaultName() override
std::deque< std::string > m_AllFiles
INDI::PropertySwitch CoolerSP
virtual bool StartStreaming() override
StartStreaming Start live video streaming.
INDI::PropertyNumber SimulatorSettingsNP
static void * streamVideoHelper(void *context)
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
float m_PlanetRefreshMinutes
virtual IPState GuideEast(uint32_t) override
Guide easward for ms milliseconds.
float m_PlanetSizeOverride
virtual IPState GuideWest(uint32_t) override
Guide westward for ms milliseconds.
int QueryFilter() override
Return current filter position.
virtual bool StopStreaming() override
StopStreaming Stop live video streaming.
float m_PEPeriod
PEPeriod in minutes.
bool SelectFilter(int) override
Select a new filter position.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
INDI::PropertyNumber OffsetNP
std::vector< uint8_t > m_CachedStreamBuffer
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool UpdateCCDBin(int hor, int ver) override
CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should ...
static const std::vector< std::pair< uint32_t, uint32_t > > Resolutions
INDI::PropertySwitch ResolutionSP
INumberVectorProperty FWHMNP
std::string m_SelectedPlanet
virtual IPState GuideNorth(uint32_t) override
Guide northward for ms milliseconds.
bool AbortExposure() override
Abort ongoing exposure.
INDI::PropertyNumber PlanetSettingsNP
INDI::PropertySwitch PlanetSelectSP
float m_CachedFocalLength
std::string m_CachedPlanet
double TemperatureRequest
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
INDI::PropertySwitch DirectorySP
virtual void activeDevicesUpdated() override
activeDevicesUpdated Inform children that ActiveDevices property was updated so they can snoop on the...
time_t m_LastPlanetRenderTime
std::deque< std::string > m_RemainingFiles
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
INDI::PropertySwitch PlanetModeSP
float CalcTimeLeft(timeval start, float req)
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save configuration items in XML file.
virtual bool UpdateGuiderBin(int hor, int ver) override
CCD calls this function when Guide head binning is updated by the client. Derived classes should impl...
bool m_LastRenderWasCacheHit
float GuideExposureRequest
virtual void addFITSKeywords(INDI::CCDChip *targetChip, std::vector< INDI::FITSRecord > &fitsKeyword) override
Generate FITS keywords that will be added to FIST/XISF file.
bool AbortGuideExposure() override
Abort ongoing exposure.
int DrawCcdFrame(INDI::CCDChip *targetChip)
Provides interface to implement Filter Wheel functionality.
INDI::PropertyText getText(const char *name) const
The CCDChip class provides functionality of a CCD Chip within a CCD.
void setExposureDuration(double duration)
setExposureDuration Set desired CCD frame exposure duration for next exposure. You must call this fun...
int getSubH() const
getSubH Get the height of the frame
int getBPP() const
getBPP Get CCD Chip depth (bits per pixel).
CCD_FRAME getFrameType() const
isInterlaced
int getBinY() const
getBinY Get vertical binning of the CCD chip.
int getXRes() const
getXRes Get the horizontal resolution in pixels of the CCD Chip.
int getBinX() const
getBinX Get horizontal binning of the CCD chip.
uint8_t * getFrameBuffer()
getFrameBuffer Get raw frame buffer of the CCD chip.
void setExposureLeft(double duration)
setExposureLeft Update exposure time left. Inform the client of the new exposure time left value.
int getSubW() const
getSubW Get the width of the frame
void setFrameBufferSize(uint32_t nbuf, bool allocMem=true)
setFrameBufferSize Set desired frame buffer size. The function will allocate memory accordingly....
int getFrameBufferSize() const
getFrameBufferSize Get allocated frame buffer size to hold the CCD image frame.
int getYRes() const
Get the vertical resolution in pixels of the CCD Chip.
void binFrame()
binFrame Perform software binning on the CCD frame. Only use this function if hardware binning is not...
void setNAxis(int value)
setNAxis Set FITS number of axis
uint32_t GetCCDCapability() const
GetCCDCapability returns the CCD capabilities.
std::unique_ptr< StreamManager > Streamer
INDI::Timer m_TemperatureCheckTimer
INDI::PropertyText ActiveDeviceTP
ActiveDeviceTP defines 4 devices the camera driver can listen to (snoop) for properties of interest s...
virtual bool UpdateCCDFrame(int x, int y, int w, int h)
CCD calls this function when CCD Frame dimension needs to be updated in the hardware....
virtual void addFITSKeywords(CCDChip *targetChip, std::vector< FITSRecord > &fitsKeywords)
Generate FITS keywords that will be added to FIST/XISF file.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool ExposureComplete(CCDChip *targetChip)
Uploads target Chip exposed buffer as FITS to the client. Derived classes should class this function ...
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
INDI::PropertyNumber TemperatureNP
TemperatureNP Camera Temperature in Celcius.
INDI::PropertyNumber ScopeInfoNP
virtual bool UpdateCCDBin(int hor, int ver)
CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should ...
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
INDI::PropertyText BayerTP
BayerTP Bayer pattern offset and type.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual void addCaptureFormat(const CaptureFormat &format)
addCaptureFormat Add a supported camera native capture format (e.g. Mono, Bayer8.....
virtual void SetGuiderParams(int x, int y, int bpp, float xf, float yf)
Setup CCD parameters for guide head CCD. Child classes call this function to update CCD parameters.
INDI::ElapsedTimer m_TemperatureElapsedTimer
virtual bool UpdateGuiderBin(int hor, int ver)
CCD calls this function when Guide head binning is updated by the client. Derived classes should impl...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save configuration items in XML file.
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
INDI::PropertySwitch CaptureFormatSP
Specifies Camera NATIVE capture format (e.g. Mono, RGB, RAW8..etc).
void SetCCDCapability(uint32_t cap)
SetCCDCapability Set the CCD capabilities. All fields must be initialized.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual void SetCCDParams(int x, int y, int bpp, float xf, float yf)
Setup CCD parameters for primary CCD. Child classes call this function to update CCD parameters.
double snoopedFocalLength
std::vector< CaptureFormat > m_CaptureFormats
double m_TargetTemperature
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
uint32_t getDriverInterface() const
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
void start()
Starts this timer. Once started, a timer value can be checked with elapsed().
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process text properties.
INDI::PropertyNumber FilterSlotNP
bool updateProperties()
updateProperties Defines or Delete properties based on default device connection status
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process number properties.
void SelectFilterDone(int newpos)
The child class calls this function when the hardware successfully finished selecting a new filter wh...
void initProperties(const char *groupName)
Initialize filter wheel properties. It is recommended to call this function within initProperties() o...
bool saveConfigItems(FILE *fp)
saveConfigItems save Filter Names in config file
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
const char * getName() const
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
int findOnSwitchIndex() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
INDI::PropertyViewText * getText() const
void start()
Starts or restarts the timer with the timeout specified in interval.
bool processText(const char *name, char *texts[], char *names[], int n)
void updateProperties(INDI::DefaultDevice *device, bool connected)
double julianDate() const
void initProperties(const char *deviceName, const char *group)
int renderFrame(INDI::CCDChip *chip, double ra_j2000_deg, double dec_j2000_deg, double focal_length_mm, double rotation_deg, float exposure_s, bool renderStars=true, double minSearchRadiusArcmin=0)
void applyReadoutNoise(INDI::CCDChip *chip, int bias, int maxNoise)
void setConfig(const RenderConfig &cfg)
const char * FILTER_TAB
FILTER_TAB Where all the properties for filter wheels are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Implementations for common driver routines.
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
int IUSnoopNumber(XMLEle *root, INumberVectorProperty *nvp)
Update a snooped number vector property from the given XML root element.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Namespace to encapsulate INDI client, drivers, and mediator classes.
void ObservedToJ2000(IEquatorialCoordinates *observed, double jd, IEquatorialCoordinates *J2000pos)
ObservedToJ2000 converts an observed position to a J2000 catalogue position removes aberration,...
@ error
throw a parse_error exception in case of a tag
char device[MAXINDIDEVICE]