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";
194 IUFillNumber(&
FWHMN[0],
"SIM_FWHM",
"FWHM (arcseconds)",
"%4.2f", 0, 60, 0, 7.5);
204 GainNP[0].
fill(
"GAIN",
"value",
"%.f", 0, 300, 10, 90);
208 OffsetNP[0].
fill(
"OFFSET",
"value",
"%.f", 0, 6000, 500, 0);
225 std::ostringstream ss;
236#ifdef USE_EQUATORIAL_PE
433 LOGF_DEBUG(
"Using cached planet render (%.1f minutes since last render)", elapsedMinutes);
522 if (timeleft <= 0.001)
533 nextTimer = timeleft * 1000;
549 if (timeleft <= 0.001)
562 nextTimer = timeleft * 1000;
574 nextTimer = timeleft * 1000;
582 constexpr double AMBIENT_TEMPERATURE = 25.0;
583 constexpr double MIN_TEC_TEMPERATURE = -15.0;
587 const double targetTemp = std::clamp(
TemperatureRequest, MIN_TEC_TEMPERATURE, AMBIENT_TEMPERATURE);
597 double newTemp = currentTemp;
599 if (targetTemp < newTemp)
602 newTemp = std::max(targetTemp, newTemp - 0.5);
604 else if (targetTemp > newTemp)
608 double deltaT = AMBIENT_TEMPERATURE - newTemp;
611 double warmingStep = deltaT * 0.2;
612 if (warmingStep < 0.02)
614 if (warmingStep > 0.5)
616 newTemp = std::min(targetTemp, newTemp + warmingStep);
645 uint16_t * ptr =
reinterpret_cast<uint16_t *
>(targetChip->
getFrameBuffer());
647 if (targetChip->
getXRes() == 500)
654 exposure_time *= (1 + sqrt(
GainNP[0].getValue()));
667 double timesince = difftime(now,
RunStart);
668 double PESpot = timesince /
m_PEPeriod * 2.0 * 3.14159;
669 PEOffset =
m_PEMax * std::sin(PESpot) / 3600.0f;
682#ifdef USE_EQUATORIAL_PE
690 static bool s_warnedNoSnoop =
false;
691 if (!s_warnedNoSnoop)
693 LOG_WARN(
"EQUATORIAL_PE not yet snooped -- rendering at raw EQUATORIAL_EOD_COORD (mount errors not active)");
694 s_warnedNoSnoop =
true;
713#ifdef USE_EQUATORIAL_PE
718 double ra_deg =
currentRA * 15.0 + PEOffset;
720 double decr = cameradec * 0.0174532925;
722 double dec_deg = cameradec + decDrift / 3600.0;
741 if (isLight || isFlat)
744 targetFocalLength, theta, exposure_time, isLight);
745 if (isLight && drawn < 0)
746 LOG_ERROR(
"Error launching gsc, is it installed with appropriate environment variables set?");
747 else if (isLight && drawn == 0)
748 LOG_WARN(
"No stars found in field -- check gsc catalog coverage for this region.");
766 for (
int x = 0; x < nbuf; x++)
781 gettimeofday(&now,
nullptr);
782 double const timesince = (now.tv_sec * 1000.0 + now.tv_usec / 1000.0)
783 - (start.tv_sec * 1000.0 + start.tv_usec / 1000.0);
784 return static_cast<float>(req - timesince / 1000.0);
802 c = c / 3600.0 / 15.0;
813 c = c / 3600.0 / 15.0;
821bool CCDSim::ISNewText(
const char * dev,
const char * name,
char * texts[],
char * names[],
int n)
1000 constexpr double AMBIENT_TEMPERATURE = 25.0;
1031 LOG_INFO(
"Directory-based images are disabled.");
1043 if (index >= 0 && index <
static_cast<int>(
Resolutions.size() - 1))
1080 rgbIndex =
static_cast<int>(i);
1109 monoIndex =
static_cast<int>(i);
1123 LOG_INFO(
"Planet simulation disabled. Returning to star field mode.");
1134 static const char* planetNames[] =
1136 "mercury",
"venus",
"mars",
"jupiter",
"saturn",
1137 "uranus",
"neptune",
"moon",
"sun"
1139 if (index >= 0 && index < 9)
1159 if (dirp ==
nullptr)
1168 if (directory[std::string(directory).length() - 1] !=
'/')
1172 static const std::vector<std::string> supportedExtensions =
1180 auto hasSupportedExtension = [](
const std::string &name)
1182 for (
const auto &extension : supportedExtensions)
1184 if (name.size() < extension.size())
1186 if (strcasecmp(name.c_str() + name.size() - extension.size(), extension.c_str()) == 0)
1192 while ((dp = readdir(dirp)) != NULL)
1194 if (hasSupportedExtension(dp->d_name))
1201 LOGF_ERROR(
"No supported image files (.fit, .fits%s) found in directory %s",
1214 LOGF_INFO(
"Directory-based images are enabled. Subsequent exposures will be loaded from directory %s",
1223#ifdef USE_EQUATORIAL_PE
1244 if (!strcmp(propName,
"ABS_FOCUS_POSITION"))
1250 if (!strcmp(name,
"FOCUS_ABSOLUTE_POSITION"))
1262 m_Seeing = 0.5625 * ticks * ticks + optimalFWHM;
1267 else if (!strcmp(propName,
"ABS_ROTATOR_ANGLE"))
1273 if (!strcmp(name,
"ANGLE"))
1283#ifdef USE_EQUATORIAL_PE
1284 if (!strcmp(propName,
"EQUATORIAL_PE"))
1286 int rc_ra = -1, rc_de = -1;
1287 double newra = 0, newdec = 0;
1293 if (!strcmp(elemName,
"RA_PE"))
1295 else if (!strcmp(elemName,
"DEC_PE"))
1299 if (rc_ra == 0 && rc_de == 0)
1303 raPE = J2000Pos.rightascension;
1304 decPE = J2000Pos.declination;
1309 if (!
usePE && strcmp(state,
"Ok") == 0)
1311 LOGF_INFO(
"EQUATORIAL_PE snoop active: JNow RA %.4f Dec %.4f -> J2000 RA %.4f Dec %.4f", newra, newdec,
raPE,
decPE);
1319 LOGF_DEBUG(
"Snooped EQUATORIAL_PE JNow RA %g Dec %g -> J2000 RA %g Dec %g", newra, newdec,
raPE,
decPE);
1365 std::random_device rd;
1366 std::mt19937 gen(rd());
1367 std::uniform_int_distribution<> dist(1500, 2000);
1368 std::this_thread::sleep_for(std::chrono::milliseconds(dist(gen)));
1396 pthread_mutex_lock(&condMutex);
1398 pthread_mutex_unlock(&condMutex);
1399 pthread_cond_signal(&cv);
1406 pthread_mutex_lock(&condMutex);
1408 pthread_mutex_unlock(&condMutex);
1409 pthread_cond_signal(&cv);
1419 bin_width = bin_width - (bin_width % 2);
1420 bin_height = bin_height - (bin_height % 2);
1422 Streamer->setSize(bin_width, bin_height);
1432 LOG_ERROR(
"Binning is not supported in planet mode.");
1438 LOGF_ERROR(
"%dx%d binning is not supported.", hor, ver);
1444 Streamer->setSize(bin_width, bin_height);
1453 LOGF_ERROR(
"%dx%d binning is not supported.", hor, ver);
1467 auto start = std::chrono::high_resolution_clock::now();
1471 pthread_mutex_lock(&condMutex);
1475 pthread_cond_wait(&cv, &condMutex);
1483 pthread_mutex_unlock(&condMutex);
1492 auto finish = std::chrono::high_resolution_clock::now();
1493 std::chrono::duration<double> elapsed = finish - start;
1506 auto finish = std::chrono::high_resolution_clock::now();
1507 std::chrono::duration<double> elapsed = finish - start;
1515 start = std::chrono::high_resolution_clock::now();
1518 pthread_mutex_unlock(&condMutex);
1533 if (focalLength <= 0)
1534 focalLength = 1000.0f;
1535 float arcsecPerPixelX = 206.265f * pixelSizeX / focalLength;
1536 float arcsecPerPixelY = 206.265f * pixelSizeY / focalLength;
1539 float planetDiameterArcsec = 0;
1548 planetDiameterArcsec = it->second;
1550 planetDiameterArcsec = 42.0f;
1554 float planetPixelsX = planetDiameterArcsec / arcsecPerPixelX;
1555 float planetPixelsY = planetDiameterArcsec / arcsecPerPixelY;
1556 float avgPlanetPixels = (planetPixelsX + planetPixelsY) / 2.0f;
1562 const int renderSize = 1024;
1563 const float planetRange = 0.05f;
1566 float planetDiamDeg = planetDiameterArcsec / 3600.0f;
1567 float planetFracOfFrame = planetDiamDeg / planetRange;
1568 float srcPlanetRadius = planetFracOfFrame * renderSize / 2.0f;
1569 if (srcPlanetRadius < 10.0f) srcPlanetRadius = 10.0f;
1573 std::string searchDir;
1575 if (configPos != std::string::npos)
1578 const char *pngPath =
"/tmp/indi_planet.png";
1580 const bool useCustomConfig = (
m_XPlanetConfig !=
"/usr/share/xplanet/config/default");
1582 if (!searchDir.empty() && useCustomConfig)
1584 snprintf(
cmd,
sizeof(
cmd),
1585 "%s -body %s -geometry %dx%d -range %.4f "
1586 "-num_times 1 -projection orthographic "
1587 "-config %s -searchdir %s "
1588 "-output %s 2>/dev/null",
1590 renderSize, renderSize,
static_cast<double>(planetRange),
1593 else if (!searchDir.empty())
1595 snprintf(
cmd,
sizeof(
cmd),
1596 "%s -body %s -geometry %dx%d -range %.4f "
1597 "-num_times 1 -projection orthographic "
1599 "-output %s 2>/dev/null",
1601 renderSize, renderSize,
static_cast<double>(planetRange),
1602 searchDir.c_str(), pngPath);
1606 snprintf(
cmd,
sizeof(
cmd),
1607 "%s -body %s -geometry %dx%d -range %.4f "
1608 "-num_times 1 -projection orthographic "
1609 "-output %s 2>/dev/null",
1611 renderSize, renderSize,
static_cast<double>(planetRange), pngPath);
1615 uint32_t rgbBufSize = width * height * 3 * 2;
1627 LOG_DEBUG(
"Cache params changed, re-rendering");
1637 int ret = system(
cmd);
1640 LOGF_ERROR(
"xplanet failed with exit code %d. Is xplanet installed?", ret);
1648 int planetRenderPixels =
static_cast<int>(avgPlanetPixels);
1649 if (planetRenderPixels < 1) planetRenderPixels = 1;
1650 snprintf(jpgCmd,
sizeof(jpgCmd),
1651 "convert %s -resize %dx%d -background black "
1652 "-gravity center -extent %dx%d -quality 90 /tmp/indi_planet.jpg 2>/dev/null",
1653 pngPath, planetRenderPixels, planetRenderPixels,
1654 static_cast<int>(width),
static_cast<int>(height));
1655 ret = system(jpgCmd);
1658 LOG_ERROR(
"Failed to generate CCD-resolution JPEG. Is ImageMagick installed?");
1664 FILE *jpgFile = fopen(
"/tmp/indi_planet.jpg",
"rb");
1667 fseek(jpgFile, 0, SEEK_END);
1668 long jpgSize = ftell(jpgFile);
1669 fseek(jpgFile, 0, SEEK_SET);
1676 ret = system(
"convert /tmp/indi_planet.png /tmp/indi_planet.ppm 2>/dev/null");
1679 LOG_ERROR(
"Failed to convert PNG to PPM. Is ImageMagick installed?");
1684 FILE *fp = fopen(
"/tmp/indi_planet.ppm",
"rb");
1687 LOG_ERROR(
"Failed to open /tmp/indi_planet.ppm");
1692 if (fscanf(fp,
"%2s\n", magic) != 1 || strcmp(magic,
"P6") != 0)
1694 LOG_ERROR(
"PPM file is not P6 format (binary RGB)");
1699 int ppmWidth, ppmHeight, maxVal;
1704 while (fgetc(fp) !=
'\n');
1708 if (fscanf(fp,
"%d %d\n%d\n", &ppmWidth, &ppmHeight, &maxVal) != 3)
1710 LOG_ERROR(
"Failed to parse PPM header");
1715 std::vector<uint8_t> rgbData(ppmWidth * ppmHeight * 3);
1716 size_t bytesRead = fread(rgbData.data(), 1, rgbData.size(), fp);
1719 if (bytesRead != rgbData.size())
1721 LOGF_ERROR(
"PPM read error: expected %zu bytes, got %zu", rgbData.size(), bytesRead);
1732 memset(buffer, 0, rgbBufSize);
1735 size_t planeSize =
static_cast<size_t>(width) *
static_cast<size_t>(height);
1736 uint16_t *rPlane = buffer;
1737 uint16_t *gPlane = buffer + planeSize;
1738 uint16_t *bPlane = buffer + planeSize * 2;
1741 float centerX = width / 2.0f;
1742 float centerY = height / 2.0f;
1745 float dstPlanetRadius = avgPlanetPixels / 2.0f;
1746 if (dstPlanetRadius < 1.0f)
1747 dstPlanetRadius = 1.0f;
1748 float scale = srcPlanetRadius / dstPlanetRadius;
1754 for (uint32_t y = 0; y < height; y++)
1756 for (uint32_t x = 0; x < width; x++)
1758 float sx = (x - centerX) * scale + ppmWidth / 2.0f;
1759 float sy = (y - centerY) * scale + ppmHeight / 2.0f;
1761 float dx = (sx - ppmWidth / 2.0f);
1762 float dy = (sy - ppmHeight / 2.0f);
1763 if (sqrtf(dx * dx + dy * dy) > srcPlanetRadius)
1766 int ix =
static_cast<int>(sx);
1767 int iy =
static_cast<int>(sy);
1768 if (ix < 0 || ix >= ppmWidth || iy < 0 || iy >= ppmHeight)
1771 int srcIdx = (iy * ppmWidth + ix) * 3;
1772 uint8_t r8 = rgbData[srcIdx];
1773 uint8_t g8 = rgbData[srcIdx + 1];
1774 uint8_t b8 = rgbData[srcIdx + 2];
1777 uint16_t r16 =
static_cast<uint16_t
>(r8) * 256;
1778 uint16_t g16 =
static_cast<uint16_t
>(g8) * 256;
1779 uint16_t b16 =
static_cast<uint16_t
>(b8) * 256;
1785 size_t px = y * width + x;
1812 LOGF_INFO(
"Rendered planet %s: diameter=%.1f arcsec, pixels=%.1f, scale=%.1f arcsec/px",
1813 m_SelectedPlanet.c_str(), planetDiameterArcsec, planetPixelsX, arcsecPerPixelX);
1823 fitsKeyword.push_back({
"GAIN",
GainNP[0].getValue(), 3,
"Gain"});
1827 fitsKeyword.emplace_back(
"OBJECT",
m_SelectedPlanet.c_str(),
"Target planet");
1828 fitsKeyword.emplace_back(
"XPLANET",
static_cast<int64_t
>(1),
"Generated by xplanet");
1829 fitsKeyword.emplace_back(
"COLORSPC",
"RGB",
"Color space");
1841 if (filename.size() >= 5 && strcasecmp(filename.c_str() + filename.size() - 5,
".xisf") == 0)
1842 return loadNextXISFImage(filename);
1850 char comment[512] = {0}, bayer_pattern[16] = {0};
1851 int status = 0, anynull = 0;
1852 double pixel_size = 5.2;
1853 int ndim {2}, bitpix {8};
1855 fitsfile *fptr =
nullptr;
1857 if (fits_open_diskfile(&fptr, filename.c_str(), READONLY, &status))
1859 char error_status[512] = {0};
1860 fits_get_errstatus(status, error_status);
1861 LOGF_WARN(
"Error opening file %s due to error %s", filename.c_str(), error_status);
1865 if (fits_get_img_param(fptr, 3, &bitpix, &ndim, naxes, &status))
1867 char error_status[512] = {0};
1868 fits_get_errstatus(status, error_status);
1869 LOGF_WARN(
"Error reading image parameters from %s due to error %s", filename.c_str(), error_status);
1870 fits_close_file(fptr, &status);
1878 int samples_per_channel = naxes[0] * naxes[1];
1879 int channels = naxes[2];
1880 int elements = samples_per_channel * channels;
1881 int size = elements * bitpix / 8;
1884 if (fits_read_img(fptr, bitpix == 8 ? TBYTE : TUSHORT, 1, elements, 0,
PrimaryCCD.
getFrameBuffer(), &anynull, &status))
1886 char error_status[512] = {0};
1887 fits_get_errstatus(status, error_status);
1888 LOGF_WARN(
"Error reading pixel data from %s due to error %s", filename.c_str(), error_status);
1889 fits_close_file(fptr, &status);
1897 if (fits_read_key_dbl(fptr,
"PIXSIZE1", &pixel_size, comment, &status))
1900 if (fits_read_key_dbl(fptr,
"XPIXSZ", &pixel_size, comment, &status))
1902 LOGF_DEBUG(
"No PIXSIZE1 or XPIXSZ keyword found in %s, defaulting pixel size to %.2f microns",
1903 filename.c_str(), pixel_size);
1908 if (fits_read_key_str(fptr,
"BAYERPAT", bayer_pattern, comment, &status))
1910 char error_status[512] = {0};
1911 fits_get_errstatus(status, error_status);
1912 LOGF_DEBUG(
"No BAYERPAT keyword found in %s (%s)", filename.c_str(), error_status);
1914 SetCCDParams(naxes[0], naxes[1], bitpix, pixel_size, pixel_size);
1917 if (channels == 1 && strlen(bayer_pattern) == 4)
1930 fits_close_file(fptr, &status);
1935bool CCDSim::loadNextXISFImage(
const std::string &filename)
1939 LibXISF::XISFReader reader;
1940 reader.open(filename);
1942 if (reader.imagesCount() < 1)
1944 LOGF_WARN(
"No images found in XISF file %s", filename.c_str());
1949 LibXISF::Image image = reader.getImage(0);
1951 const auto sampleFormat = image.sampleFormat();
1952 const bool isFloat = (sampleFormat == LibXISF::Image::Float32 || sampleFormat == LibXISF::Image::Float64);
1954 switch (sampleFormat)
1956 case LibXISF::Image::UInt8:
1959 case LibXISF::Image::UInt16:
1962 case LibXISF::Image::Float32:
1963 case LibXISF::Image::Float64:
1970 LOGF_WARN(
"Unsupported XISF sample format '%s' in %s. Only 8/16-bit integer and 32/64-bit "
1971 "normalized float samples are supported.",
1972 LibXISF::Image::sampleFormatString(sampleFormat).c_str(), filename.c_str());
1976 int channels =
static_cast<int>(image.channelCount());
1981 if (image.pixelStorage() != LibXISF::Image::Planar)
1982 image.convertPixelStorageTo(LibXISF::Image::Planar);
1984 const size_t elementCount = image.width() * image.height() * channels;
1989 auto scaleClamp = [](
double value) -> uint16_t
1995 return static_cast<uint16_t
>(std::lround(value * 65535.0));
1998 if (sampleFormat == LibXISF::Image::Float32)
2000 const float * src = image.imageData<
float>();
2001 for (
size_t i = 0; i < elementCount; i++)
2002 dest[i] = scaleClamp(src[i]);
2006 const double * src = image.imageData<
double>();
2007 for (
size_t i = 0; i < elementCount; i++)
2008 dest[i] = scaleClamp(src[i]);
2018 double pixel_size = 5.2;
2019 bool foundPixelSize =
false;
2020 for (
const auto &keyword : image.fitsKeywords())
2022 if (keyword.name ==
"PIXSIZE1" || keyword.name ==
"XPIXSZ")
2024 pixel_size = std::stod(keyword.value);
2025 foundPixelSize =
true;
2029 if (!foundPixelSize)
2030 LOGF_DEBUG(
"No PIXSIZE1 or XPIXSZ keyword found in %s, defaulting pixel size to %.2f microns",
2031 filename.c_str(), pixel_size);
2033 SetCCDParams(image.width(), image.height(), bitpix, pixel_size, pixel_size);
2036 const auto cfa = image.colorFilterArray();
2037 if (channels == 1 && cfa.pattern.size() == 4)
2049 catch (LibXISF::Error &error)
2051 LOGF_WARN(
"Error reading XISF file %s due to error: %s", filename.c_str(),
error.what());
2066 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.
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 * 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]