8#include "indicamerachip.h"
10#include "config-kstars.h"
12#include "indi_debug.h"
14#include "clientmanager.h"
20#include "fitsviewer/fitsdata.h"
21#include "fitsviewer/fitstab.h"
24#include <KNotifications/KNotification>
25#include "auxiliary/ksmessagebox.h"
26#include "ksnotification.h"
27#include <QImageReader>
30#include <QtConcurrent>
32#include <basedevice.h>
34const QStringList RAWFormats = {
"cr2",
"cr3",
"crw",
"nef",
"raf",
"dng",
"arw",
"orf" };
36const QString &getFITSModeStringString(FITSMode mode)
38 return FITSModes[mode];
44Camera::Camera(GenericDevice *parent) : ConcreteDevice(parent)
46 primaryChip.reset(
new CameraChip(
this, CameraChip::PRIMARY_CCD));
48 m_Media.reset(
new WSMedia(
this));
49 connect(m_Media.get(), &WSMedia::newFile,
this, &Camera::setWSBLOB);
57 if (m_ImageViewerWindow)
58 m_ImageViewerWindow->close();
59 if (fileWriteThread.isRunning())
60 fileWriteThread.waitForFinished();
61 if (fileWriteBuffer !=
nullptr)
62 delete [] fileWriteBuffer;
65void Camera::setBLOBManager(
const char *device, INDI::Property
prop)
67 if (!
prop.getRegistered())
70 if (getDeviceName() == device)
74void Camera::registerProperty(INDI::Property
prop)
76 if (
prop.isNameMatch(
"GUIDER_EXPOSURE"))
79 guideChip.reset(
new CameraChip(
this, CameraChip::GUIDE_CCD));
81 else if (
prop.isNameMatch(
"CCD_FRAME_TYPE"))
83 primaryChip->clearFrameTypes();
85 for (
auto &
it : *
prop.getSwitch())
86 primaryChip->addFrameLabel(
it.getLabel());
88 else if (
prop.isNameMatch(
"CCD_FRAME"))
90 auto np =
prop.getNumber();
91 if (np && np->getPermission() !=
IP_RO)
92 primaryChip->setCanSubframe(
true);
94 else if (
prop.isNameMatch(
"GUIDER_FRAME"))
96 auto np =
prop.getNumber();
97 if (np && np->getPermission() !=
IP_RO)
98 guideChip->setCanSubframe(
true);
100 else if (
prop.isNameMatch(
"CCD_BINNING"))
102 auto np =
prop.getNumber();
103 if (np && np->getPermission() !=
IP_RO)
104 primaryChip->setCanBin(
true);
106 else if (
prop.isNameMatch(
"GUIDER_BINNING"))
108 auto np =
prop.getNumber();
109 if (np && np->getPermission() !=
IP_RO)
110 guideChip->setCanBin(
true);
112 else if (
prop.isNameMatch(
"CCD_ABORT_EXPOSURE"))
114 auto sp =
prop.getSwitch();
115 if (sp && sp->getPermission() !=
IP_RO)
116 primaryChip->setCanAbort(
true);
118 else if (
prop.isNameMatch(
"GUIDER_ABORT_EXPOSURE"))
120 auto sp =
prop.getSwitch();
121 if (sp && sp->getPermission() !=
IP_RO)
122 guideChip->setCanAbort(
true);
124 else if (
prop.isNameMatch(
"CCD_TEMPERATURE"))
126 auto np =
prop.getNumber();
128 CanCool = (np->getPermission() !=
IP_RO);
130 emit newTemperatureValue(np->at(0)->getValue());
132 else if (
prop.isNameMatch(
"CCD_COOLER"))
135 HasCoolerControl =
true;
137 else if (
prop.isNameMatch(
"CCD_VIDEO_STREAM"))
140 HasVideoStream =
true;
142 else if (
prop.isNameMatch(
"CCD_CAPTURE_FORMAT"))
144 auto sp =
prop.getSwitch();
147 m_CaptureFormats.clear();
149 m_CaptureFormats <<
oneSwitch.getLabel();
151 m_CaptureFormatIndex = sp->findOnSwitchIndex();
154 else if (
prop.isNameMatch(
"CCD_TRANSFER_FORMAT"))
156 auto sp =
prop.getSwitch();
159 m_EncodingFormats.clear();
161 m_EncodingFormats <<
oneSwitch.getLabel();
163 auto format = sp->findOnSwitch();
165 m_EncodingFormat = format->label;
168 else if (
prop.isNameMatch(
"CCD_EXPOSURE_PRESETS"))
175 for (
const auto &
it : *
svp)
182 if (parts.
count() == 2)
195 m_ExposurePresets.insert(key, value);
197 double min = 1e6, max = 1e-6;
198 for (
auto oneValue : m_ExposurePresets.values())
209 else if (
prop.isNameMatch(
"CCD_FAST_TOGGLE"))
211 auto sp =
prop.getSwitch();
213 m_FastExposureEnabled = sp->findOnSwitchIndex() == 0;
215 m_FastExposureEnabled =
false;
217 else if (
prop.isNameMatch(
"TELESCOPE_TYPE"))
219 auto sp =
prop.getSwitch();
222 auto format = sp->findWidgetByName(
"TELESCOPE_PRIMARY");
223 if (format && format->getState() ==
ISS_ON)
224 telescopeType = TELESCOPE_PRIMARY;
226 telescopeType = TELESCOPE_GUIDE;
229 else if (
prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
231 auto np =
prop.getNumber();
232 m_Media->setURL(
QUrl(
QString(
"ws://%1:%2").arg(m_Parent->getClientManager()->getHost()).
arg(np->at(0)->getValue())));
233 m_Media->connectServer();
235 else if (
prop.isNameMatch(
"CCD1"))
237 primaryCCDBLOB =
prop;
240 else if ( (gainN ==
nullptr || offsetN ==
nullptr) &&
prop.getType() ==
INDI_NUMBER)
252 if (name ==
"gain" || label ==
"gain")
257 else if (name ==
"offset" || label ==
"offset")
266 ConcreteDevice::registerProperty(
prop);
269void Camera::removeProperty(INDI::Property
prop)
271 if (
prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
273 m_Media->disconnectServer();
277void Camera::processNumber(INDI::Property
prop)
280 if (
nvp->isNameMatch(
"CCD_EXPOSURE"))
282 auto np =
nvp->findWidgetByName(
"CCD_EXPOSURE_VALUE");
284 emit newExposureValue(primaryChip.get(), np->getValue(),
nvp->getState());
288 else if (
prop.isNameMatch(
"CCD_TEMPERATURE"))
291 auto np =
nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
293 emit newTemperatureValue(np->getValue());
295 else if (
prop.isNameMatch(
"GUIDER_EXPOSURE"))
297 auto np =
nvp->findWidgetByName(
"GUIDER_EXPOSURE_VALUE");
299 emit newExposureValue(guideChip.get(), np->getValue(),
nvp->getState());
301 else if (
prop.isNameMatch(
"FPS"))
303 emit newFPS(
nvp->at(0)->getValue(),
nvp->at(1)->getValue());
305 else if (
prop.isNameMatch(
"CCD_RAPID_GUIDE_DATA"))
309 emit newGuideStarData(primaryChip.get(), -1, -1, -1);
313 double dx = -1, dy = -1, fit = -1;
315 auto np =
nvp->findWidgetByName(
"GUIDESTAR_X");
318 np =
nvp->findWidgetByName(
"GUIDESTAR_Y");
321 np =
nvp->findWidgetByName(
"GUIDESTAR_FIT");
323 fit = np->getValue();
325 if (dx >= 0 && dy >= 0 && fit >= 0)
326 emit newGuideStarData(primaryChip.get(), dx, dy, fit);
329 else if (
prop.isNameMatch(
"GUIDER_RAPID_GUIDE_DATA"))
333 emit newGuideStarData(guideChip.get(), -1, -1, -1);
337 double dx = -1, dy = -1, fit = -1;
338 auto np =
nvp->findWidgetByName(
"GUIDESTAR_X");
341 np =
nvp->findWidgetByName(
"GUIDESTAR_Y");
344 np =
nvp->findWidgetByName(
"GUIDESTAR_FIT");
346 fit = np->getValue();
348 if (dx >= 0 && dy >= 0 && fit >= 0)
349 emit newGuideStarData(guideChip.get(), dx, dy, fit);
354void Camera::processSwitch(INDI::Property
prop)
358 if (
svp->isNameMatch(
"CCD_COOLER"))
361 HasCoolerControl =
true;
367 if (isBLOBEnabled() ==
false || m_StreamingEnabled ==
false)
370 HasVideoStream =
true;
372 if (!streamWindow &&
svp->sp[0].s ==
ISS_ON)
374 streamWindow.reset(
new StreamWG(
this));
377 INumber *w =
nullptr, *h =
nullptr;
393 auto rawBP = getBLOB(
"CCD1");
396 int x = 0, y = 0, w = 0, h = 0;
399 primaryChip->getFrame(&x, &y, &w, &h);
400 primaryChip->getBinning(&
binx, &
biny);
406 streamWindow->setSize(streamW, streamH);
414 streamWindow->enableStream(
svp->sp[0].s ==
ISS_ON);
418 else if (
svp->isNameMatch(
"CCD_CAPTURE_FORMAT"))
420 m_CaptureFormats.clear();
421 for (
int i = 0; i <
svp->nsp; i++)
423 m_CaptureFormats <<
svp->sp[i].label;
425 m_CaptureFormatIndex = i;
428 else if (
svp->isNameMatch(
"CCD_TRANSFER_FORMAT"))
432 m_EncodingFormat = format->label;
434 else if (
svp->isNameMatch(
"RECORD_STREAM"))
440 emit videoRecordToggled(
false);
441 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Stopped"), KSNotification::INDI);
445 emit videoRecordToggled(
true);
446 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Started"), KSNotification::INDI);
449 else if (
svp->isNameMatch(
"TELESCOPE_TYPE"))
452 if (format && format->s ==
ISS_ON)
453 telescopeType = TELESCOPE_PRIMARY;
455 telescopeType = TELESCOPE_GUIDE;
457 else if (!
strcmp(
svp->name,
"CCD_FAST_TOGGLE"))
461 else if (
svp->isNameMatch(
"CONNECTION"))
463 auto dSwitch =
svp->findWidgetByName(
"DISCONNECT");
469 streamWindow->enableStream(
false);
470 emit videoStreamToggled(
false);
471 streamWindow->close();
472 streamWindow.reset();
478 primaryCCDBLOB = INDI::Property();
483void Camera::processText(INDI::Property
prop)
486 if (
tvp->isNameMatch(
"CCD_FILE_PATH"))
488 auto filepath =
tvp->findWidgetByName(
"FILE_PATH");
499 auto bvp = primaryCCDBLOB.getBLOB();
500 auto bp =
bvp->at(0);
502 bp->setBlob(
const_cast<char *
>(message.
data()));
503 bp->setSize(message.
size());
505 processBLOB(primaryCCDBLOB);
508 bp->setBlob(
nullptr);
511void Camera::processStream(INDI::Property
prop)
513 if (!streamWindow || streamWindow->isStreamEnabled() ==
false)
517 INumber *w =
nullptr, *h =
nullptr;
532 int x = 0, y = 0, w = 0, h = 0;
535 primaryChip->getFrame(&x, &y, &w, &h);
536 primaryChip->getBinning(&
binx, &
biny);
541 streamWindow->setSize(streamW, streamH);
543 streamWindow->show();
544 streamWindow->newFrame(
prop);
550 *filename = placeholderPath.generateOutputFilename(
true,
batch_mode, nextSequenceID, extension,
"");
553 if (currentDir.
exists() ==
false)
560 *filename = placeholderPath.repairFilename(*filename);
564 qCWarning(
KSTARS_INDI) <<
"File over-write detected for" <<
oldFilename <<
"but could not correct filename";
575bool Camera::writeImageFile(
const QString &filename, INDI::Property
prop,
bool is_fits)
583 if (fileWriteThread.isRunning())
585 fileWriteThread.waitForFinished();
589 fileWriteFilename = filename;
594 auto bp =
prop.getBLOB()->at(0);
596 if (fileWriteBufferSize != bp->getBlobLen())
598 if (fileWriteBuffer !=
nullptr)
599 delete [] fileWriteBuffer;
600 fileWriteBufferSize = bp->getBlobLen();
601 fileWriteBuffer =
new char[fileWriteBufferSize];
606 memcpy(fileWriteBuffer, bp->getBlob(), bp->getBlobLen());
607 fileWriteThread =
QtConcurrent::run(
this, &ISD::Camera::WriteImageFileInternal, fileWriteFilename, fileWriteBuffer,
612 auto bp =
prop.getBLOB()->at(0);
613 if (!WriteImageFileInternal(filename,
static_cast<char*
>(bp->getBlob()), bp->getBlobLen()))
625 if (!m_FITSViewerWindow.isNull() && ! m_FITSViewerWindow.isNull())
626 return m_FITSViewerWindow;
629 normalTabID = calibrationTabID = focusTabID = guideTabID = alignTabID = -1;
634 connect(m_FITSViewerWindow.get(), &FITSViewer::closed,
this, [
this](
int tabIndex)
636 if (tabIndex == normalTabID)
638 else if (tabIndex == calibrationTabID)
639 calibrationTabID = -1;
640 else if (tabIndex == focusTabID)
642 else if (tabIndex == guideTabID)
644 else if (tabIndex == alignTabID)
649 connect(m_FITSViewerWindow.get(), &FITSViewer::terminated,
this, [
this]()
652 calibrationTabID = -1;
656 m_FITSViewerWindow.clear();
659 return m_FITSViewerWindow;
662bool Camera::processBLOB(INDI::Property
prop)
666 if (
bvp->getPermission() ==
IP_WO ||
bvp->at(0)->getSize() == 0)
671 auto bp =
bvp->at(0);
676 if (format.contains(
"stream"))
678 if (m_StreamingEnabled ==
false)
680 else if (streamWindow)
691 else if (format.contains(
"fits"))
693 else if (format.contains(
"xisf"))
698 if (BType == BLOB_OTHER)
700 emit newImage(
nullptr);
704 CameraChip *targetChip =
nullptr;
706 if (
bvp->isNameMatch(
"CCD2"))
707 targetChip = guideChip.get();
710 targetChip = primaryChip.get();
711 qCDebug(
KSTARS_INDI) <<
"Image received. Mode:" << getFITSModeStringString(targetChip->getCaptureMode()) <<
"Size:" <<
721 if (targetChip->isBatchMode() ==
false || targetChip->getCaptureMode() != FITS_NORMAL)
728 if (BType == BLOB_FITS)
734 if (targetChip->isBatchMode() && targetChip->getCaptureMode() != FITS_CALIBRATE)
738 if (!generateFilename(targetChip->isBatchMode(), format, &filename) ||
739 !writeImageFile(filename,
prop, BType == BLOB_FITS))
743 KSMessageBox::Instance()->disconnect(
this);
746 KSMessageBox::Instance()->error(
i18n(
"Failed writing image to %1\nPlease check folder, filename & permissions.",
748 i18n(
"Image Write Failed"), 30);
757 if (targetChip->getCaptureMode() == FITS_NORMAL && targetChip->isBatchMode() ==
true)
772 if (BType == BLOB_IMAGE || BType == BLOB_RAW)
775 (Options::useFITSViewer() || (Options::useDSLRImageViewer() ==
false && targetChip->isBatchMode() ==
false));
776 bool useDSLRViewer = (Options::useDSLRImageViewer() || targetChip->isBatchMode() ==
false);
800 if (targetChip->isBatchMode() ==
false)
812 if (BType == BLOB_RAW || targetChip->isBatchMode() ==
false)
820 FITSData *
blob_fits_data =
new FITSData(targetChip->getCaptureMode());
829 qCCritical(
KSTARS_INDI) <<
"failed reading FITS memory buffer";
838 if (m_ImageViewerWindow.isNull())
841 m_ImageViewerWindow->loadImage(filename);
858 if (targetChip->getCaptureMode() == FITS_NORMAL &&
859 Options::useFITSViewer() ==
false &&
860 Options::useSummaryPreview() ==
false &&
861 targetChip->isBatchMode())
864 emit newImage(
nullptr);
871 if (!imageData->loadFromBuffer(buffer,
shortFormat, filename))
877 handleImage(targetChip, filename,
prop, imageData);
881void Camera::handleImage(CameraChip *targetChip,
const QString &filename, INDI::Property
prop,
884 FITSMode captureMode = targetChip->getCaptureMode();
885 auto bp =
prop.getBLOB()->at(0);
888 data->setProperty(
"device", getDeviceName());
889 data->setProperty(
"blobVector",
prop.getName());
890 data->setProperty(
"blobElement", bp->getName());
891 data->setProperty(
"chip", targetChip->getType());
893 targetChip->setImageData(data);
900 if (Options::useFITSViewer())
907 bool success =
false;
909 int *
tabID = &normalTabID;
911 FITSScale captureFilter = targetChip->getCaptureFilter();
912 if (*
tabID == -1 || Options::singlePreviewFITS() ==
false)
918 if (Options::singlePreviewFITS())
922 if (Options::singleWindowCapturedFITS())
929 success = getFITSViewer()->loadData(data,
fileURL, &tabIndex, captureMode, captureFilter,
previewTitle);
932 auto tabs = getFITSViewer()->tabs();
933 if (tabIndex < tabs.size() && captureMode == FITS_NORMAL)
935 emit newView(tabs[tabIndex]->getView());
936 tabs[tabIndex]->disconnect(
this);
937 connect(tabs[tabIndex].
get(), &FITSTab::updated,
this, [
this]
940 emit newView(tab->getView());
945 success = getFITSViewer()->updateData(data,
fileURL, *
tabID, &tabIndex, captureFilter, captureMode);
951 qCCritical(
KSTARS_INDI) <<
"error adding/updating FITS";
956 if (Options::focusFITSOnNewImage())
957 getFITSViewer()->raise();
971void Camera::StreamWindowHidden()
976 auto streamSP = getSwitch(
"CCD_VIDEO_STREAM");
986 streamSP = getSwitch(
"VIDEO_STREAM");
996 streamSP = getSwitch(
"AUX_VIDEO_STREAM");
1008 streamWindow->disconnect();
1011bool Camera::hasGuideHead()
1013 return HasGuideHead;
1016bool Camera::hasCooler()
1021bool Camera::hasCoolerControl()
1023 return HasCoolerControl;
1026bool Camera::setCoolerControl(
bool enable)
1028 if (HasCoolerControl ==
false)
1031 auto coolerSP = getSwitch(
"CCD_COOLER");
1049CameraChip *Camera::getChip(CameraChip::ChipType
cType)
1053 case CameraChip::PRIMARY_CCD:
1054 return primaryChip.get();
1056 case CameraChip::GUIDE_CCD:
1057 return guideChip.get();
1063bool Camera::setRapidGuide(CameraChip *targetChip,
bool enable)
1068 if (targetChip == primaryChip.get())
1069 rapidSP = getSwitch(
"CCD_RAPID_GUIDE");
1071 rapidSP = getSwitch(
"GUIDER_RAPID_GUIDE");
1094bool Camera::configureRapidGuide(CameraChip *targetChip,
bool autoLoop,
bool sendImage,
bool showMarker)
1099 if (targetChip == primaryChip.get())
1100 rapidSP = getSwitch(
"CCD_RAPID_GUIDE_SETUP");
1102 rapidSP = getSwitch(
"GUIDER_RAPID_GUIDE_SETUP");
1154Camera::UploadMode Camera::getUploadMode()
1162 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
1163 return UPLOAD_CLIENT;
1172 return UPLOAD_CLIENT;
1175 return UPLOAD_LOCAL;
1182 return UPLOAD_CLIENT;
1185bool Camera::setUploadMode(UploadMode mode)
1193 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
1232bool Camera::getTemperature(
double *value)
1234 if (HasCooler ==
false)
1247bool Camera::setTemperature(
double value)
1249 auto nvp = getNumber(
"CCD_TEMPERATURE");
1254 auto np =
nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
1259 np->setValue(value);
1261 sendNewProperty(
nvp);
1266bool Camera::setEncodingFormat(
const QString &value)
1268 if (value.
isEmpty() || value == m_EncodingFormat)
1271 auto svp = getSwitch(
"CCD_TRANSFER_FORMAT");
1277 for (
int i = 0; i <
svp->nsp; i++)
1279 if (
svp->at(i)->getLabel() == value)
1286 m_EncodingFormat = value;
1287 sendNewProperty(
svp);
1291bool Camera::setTelescopeType(TelescopeType type)
1293 if (type == telescopeType)
1296 auto svp = getSwitch(
"TELESCOPE_TYPE");
1302 auto typeGuide =
svp->findWidgetByName(
"TELESCOPE_GUIDE");
1307 telescopeType =
type;
1314 sendNewProperty(
svp);
1315 setConfig(SAVE_CONFIG);
1321bool Camera::setVideoStreamEnabled(
bool enable)
1323 if (HasVideoStream ==
false)
1326 auto svp = getSwitch(
"CCD_VIDEO_STREAM");
1332 if ((enable &&
svp->at(0)->getState() ==
ISS_ON) || (!enable &&
svp->at(1)->getState() ==
ISS_ON))
1338 sendNewProperty(
svp);
1343bool Camera::resetStreamingFrame()
1345 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1357 if (!std::fabs(
xarg->getValue() -
xarg->getMin()) &&
1358 !std::fabs(
yarg->getValue() -
yarg->getMin()) &&
1359 !std::fabs(
warg->getValue() -
warg->getMax()) &&
1360 !std::fabs(
harg->getValue() -
harg->getMax()))
1375bool Camera::setStreamLimits(uint16_t maxBufferSize, uint16_t
maxPreviewFPS)
1400bool Camera::setStreamingFrame(
int x,
int y,
int w,
int h)
1402 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1414 if (!std::fabs(
xarg->getValue() - x) &&
1415 !std::fabs(
yarg->getValue() - y) &&
1416 !std::fabs(
warg->getValue() - w) &&
1417 !std::fabs(
harg->getValue() - h))
1433bool Camera::isStreamingEnabled()
1435 if (HasVideoStream ==
false || !streamWindow)
1438 return streamWindow->isStreamEnabled();
1441bool Camera::setSERNameDirectory(
const QString &filename,
const QString &directory)
1443 auto tvp = getText(
"RECORD_FILE");
1448 auto filenameT =
tvp->findWidgetByName(
"RECORD_FILE_NAME");
1449 auto dirT =
tvp->findWidgetByName(
"RECORD_FILE_DIR");
1457 sendNewProperty(
tvp);
1462bool Camera::getSERNameDirectory(
QString &filename,
QString &directory)
1464 auto tvp = getText(
"RECORD_FILE");
1469 auto filenameT =
tvp->findWidgetByName(
"RECORD_FILE_NAME");
1470 auto dirT =
tvp->findWidgetByName(
"RECORD_FILE_DIR");
1481bool Camera::startRecording()
1483 auto svp = getSwitch(
"RECORD_STREAM");
1488 auto recordON =
svp->findWidgetByName(
"RECORD_ON");
1499 sendNewProperty(
svp);
1504bool Camera::startDurationRecording(
double duration)
1506 auto nvp = getNumber(
"RECORD_OPTIONS");
1511 auto durationN =
nvp->findWidgetByName(
"RECORD_DURATION");
1516 auto svp = getSwitch(
"RECORD_STREAM");
1521 auto recordON =
svp->findWidgetByName(
"RECORD_DURATION_ON");
1530 sendNewProperty(
nvp);
1535 sendNewProperty(
svp);
1540bool Camera::startFramesRecording(uint32_t
frames)
1542 auto nvp = getNumber(
"RECORD_OPTIONS");
1547 auto frameN =
nvp->findWidgetByName(
"RECORD_FRAME_TOTAL");
1548 auto svp = getSwitch(
"RECORD_STREAM");
1553 auto recordON =
svp->findWidgetByName(
"RECORD_FRAME_ON");
1562 sendNewProperty(
nvp);
1567 sendNewProperty(
svp);
1572bool Camera::stopRecording()
1574 auto svp = getSwitch(
"RECORD_STREAM");
1591 sendNewProperty(
svp);
1598 auto tvp = getText(
"FITS_HEADER");
1601 if (!
tvp ||
tvp->count() < 3)
1604 for (
auto &record : values)
1606 tvp->at(0)->setText(record.key.toLatin1().constData());
1607 tvp->at(1)->setText(record.value.toString().toLatin1().constData());
1608 tvp->at(2)->setText(record.comment.toLatin1().constData());
1610 sendNewProperty(
tvp);
1616bool Camera::setGain(
double value)
1621 gainN->value = value;
1622 sendNewProperty(gainN->nvp);
1626bool Camera::getGain(
double *value)
1631 *value = gainN->value;
1636bool Camera::getGainMinMaxStep(
double *min,
double *max,
double *step)
1643 *step = gainN->step;
1648bool Camera::setOffset(
double value)
1653 offsetN->value = value;
1654 sendNewProperty(offsetN->nvp);
1658bool Camera::getOffset(
double *value)
1663 *value = offsetN->value;
1668bool Camera::getOffsetMinMaxStep(
double *min,
double *max,
double *step)
1673 *min = offsetN->min;
1674 *max = offsetN->max;
1675 *step = offsetN->step;
1680bool Camera::isBLOBEnabled()
1682 return (m_Parent->getClientManager()->isBLOBEnabled(getDeviceName(),
"CCD1"));
1685bool Camera::setBLOBEnabled(
bool enable,
const QString &
prop)
1687 m_Parent->getClientManager()->setBLOBEnabled(enable, getDeviceName(),
prop);
1692bool Camera::setFastExposureEnabled(
bool enable)
1695 m_FastExposureEnabled = enable;
1697 auto svp = getSwitch(
"CCD_FAST_TOGGLE");
1704 sendNewProperty(
svp);
1709bool Camera::setCaptureFormat(
const QString &format)
1711 auto svp = getSwitch(
"CCD_CAPTURE_FORMAT");
1718 sendNewProperty(
svp);
1722bool Camera::setFastCount(uint32_t count)
1724 auto nvp = getNumber(
"CCD_FAST_COUNT");
1729 nvp->at(0)->setValue(count);
1731 sendNewProperty(
nvp);
1736bool Camera::setStreamExposure(
double duration)
1738 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1743 nvp->at(0)->setValue(duration);
1745 sendNewProperty(
nvp);
1750bool Camera::getStreamExposure(
double *duration)
1752 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1757 *duration =
nvp->at(0)->getValue();
1762bool Camera::isCoolerOn()
1764 auto svp = getSwitch(
"CCD_COOLER");
1769 return (
svp->at(0)->getState() ==
ISS_ON);
1772bool Camera::getTemperatureRegulation(
double &
ramp,
double &threshold)
1779 threshold =
regulation.getNumber()->at(1)->getValue();
1783bool Camera::setTemperatureRegulation(
double ramp,
double threshold)
1790 regulation.getNumber()->at(1)->setValue(threshold);
1795bool Camera::setScopeInfo(
double focalLength,
double aperture)
1802 nvp->at(0)->setValue(focalLength);
1803 nvp->at(1)->setValue(aperture);
1804 sendNewProperty(
nvp);
1809bool Camera::WriteImageFileInternal(
const QString &filename,
char *buffer,
const size_t size)
1811 QFile file(filename);
1814 qCCritical(
KSTARS_INDI) <<
"ISD:CCD Error: Unable to open write file: " <<
1821 for (
size_t nr = 0;
nr < size;
nr += n)
1823 n =
out.writeRawData(buffer +
nr, size -
nr);
1830 ok = file.flush() &&
ok;
1839QString Camera::getCaptureFormat()
const
1841 if (m_CaptureFormatIndex < 0 || m_CaptureFormats.isEmpty() || m_CaptureFormatIndex >= m_CaptureFormats.size())
1844 return m_CaptureFormats[m_CaptureFormatIndex];
1847void Camera::setStretchValues(
double shadows,
double midtones,
double highlights)
1849 if (Options::useFITSViewer() ==
false || normalTabID < 0)
1852 auto tab = getFITSViewer()->tabs().at(normalTabID);
1857 tab->setStretchValues(shadows, midtones, highlights);
1860void Camera::setAutoStretch()
1862 if (Options::useFITSViewer() ==
false || normalTabID < 0)
1865 auto tab = getFITSViewer()->tabs().at(normalTabID);
1870 auto view = tab->getView();
1872 if (!view->getAutoStretch())
1873 view->setAutoStretchParams();
1876void Camera::toggleHiPSOverlay()
1878 if (Options::useFITSViewer() ==
false || normalTabID < 0)
1881 auto tab = getFITSViewer()->tabs().at(normalTabID);
1886 auto view = tab->getView();
1888 view->toggleHiPSOverlay();
static KNotification * event(const QString &eventId, const QString &text=QString(), const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
static KStars * Instance()
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
ISD is a collection of INDI Standard Devices.
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString label(StandardShortcut id)
QString name(StandardShortcut id)
QCA_EXPORT QVariant getProperty(const QString &name)
const char * constData() const const
QByteArray fromRawData(const char *data, qsizetype size)
qsizetype size() const const
QDateTime currentDateTime()
bool exists() const const
bool mkpath(const QString &dirPath) const const
QString path() const const
bool exists() const const
qsizetype count() const const
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
double toDouble(bool *ok) const const
QByteArray toLatin1() const const
QString toLower() const const
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)