8#include "indicamerachip.h"
10#include "config-kstars.h"
12#include "indi_debug.h"
14#include "clientmanager.h"
20#include "fitsviewer/fitsdata.h"
23#include <knotification.h>
24#include "auxiliary/ksmessagebox.h"
25#include "ksnotification.h"
26#include <QImageReader>
29#include <QtConcurrent>
31#include <basedevice.h>
33const QStringList RAWFormats = {
"cr2",
"cr3",
"crw",
"nef",
"raf",
"dng",
"arw",
"orf" };
35const QString getFITSModeStringString(FITSMode mode)
37 return FITSModes[mode].toString();
45 primaryChip.reset(
new CameraChip(
this, CameraChip::PRIMARY_CCD));
47 m_Media.reset(
new WSMedia(
this));
48 connect(m_Media.get(), &WSMedia::newFile,
this, &Camera::setWSBLOB);
56 if (m_ImageViewerWindow)
57 m_ImageViewerWindow->close();
58 if (fileWriteThread.isRunning())
59 fileWriteThread.waitForFinished();
60 if (fileWriteBuffer !=
nullptr)
61 delete [] fileWriteBuffer;
64void Camera::setBLOBManager(
const char *device, INDI::Property prop)
66 if (!prop.getRegistered())
69 if (getDeviceName() == device)
70 emit newBLOBManager(prop);
73void Camera::registerProperty(INDI::Property prop)
75 if (prop.isNameMatch(
"GUIDER_EXPOSURE"))
78 guideChip.reset(
new CameraChip(
this, CameraChip::GUIDE_CCD));
80 else if (prop.isNameMatch(
"CCD_FRAME_TYPE"))
82 primaryChip->clearFrameTypes();
84 for (
auto &it : *prop.getSwitch())
85 primaryChip->addFrameLabel(it.getLabel());
87 else if (prop.isNameMatch(
"CCD_FRAME"))
89 auto np = prop.getNumber();
90 if (np && np->getPermission() != IP_RO)
91 primaryChip->setCanSubframe(
true);
93 else if (prop.isNameMatch(
"GUIDER_FRAME"))
95 auto np = prop.getNumber();
96 if (np && np->getPermission() != IP_RO)
97 guideChip->setCanSubframe(
true);
99 else if (prop.isNameMatch(
"CCD_BINNING"))
101 auto np = prop.getNumber();
102 if (np && np->getPermission() != IP_RO)
103 primaryChip->setCanBin(
true);
105 else if (prop.isNameMatch(
"GUIDER_BINNING"))
107 auto np = prop.getNumber();
108 if (np && np->getPermission() != IP_RO)
109 guideChip->setCanBin(
true);
111 else if (prop.isNameMatch(
"CCD_ABORT_EXPOSURE"))
113 auto sp = prop.getSwitch();
114 if (sp && sp->getPermission() != IP_RO)
115 primaryChip->setCanAbort(
true);
117 else if (prop.isNameMatch(
"GUIDER_ABORT_EXPOSURE"))
119 auto sp = prop.getSwitch();
120 if (sp && sp->getPermission() != IP_RO)
121 guideChip->setCanAbort(
true);
123 else if (prop.isNameMatch(
"CCD_TEMPERATURE"))
125 auto np = prop.getNumber();
127 CanCool = (np->getPermission() != IP_RO);
129 emit newTemperatureValue(np->at(0)->getValue());
131 else if (prop.isNameMatch(
"CCD_COOLER"))
134 HasCoolerControl =
true;
136 else if (prop.isNameMatch(
"CCD_VIDEO_STREAM"))
139 HasVideoStream =
true;
141 else if (prop.isNameMatch(
"CCD_CAPTURE_FORMAT"))
143 auto sp = prop.getSwitch();
146 m_CaptureFormats.clear();
147 for (
const auto &oneSwitch : *sp)
148 m_CaptureFormats << oneSwitch.getLabel();
150 m_CaptureFormatIndex = sp->findOnSwitchIndex();
153 else if (prop.isNameMatch(
"CCD_STREAM_ENCODER"))
155 auto sp = prop.getSwitch();
158 m_StreamEncodings.clear();
159 for (
const auto &oneSwitch : *sp)
160 m_StreamEncodings << oneSwitch.getLabel();
162 auto format = sp->findOnSwitch();
164 m_StreamEncoding = format->label;
167 else if (prop.isNameMatch(
"CCD_TRANSFER_FORMAT"))
169 auto sp = prop.getSwitch();
172 m_EncodingFormats.clear();
173 for (
const auto &oneSwitch : *sp)
174 m_EncodingFormats << oneSwitch.getLabel();
176 auto format = sp->findOnSwitch();
178 m_EncodingFormat = format->label;
181 else if (prop.isNameMatch(
"CCD_STREAM_RECORDER"))
183 auto sp = prop.getSwitch();
186 m_VideoFormats.clear();
187 for (
const auto &oneSwitch : *sp)
188 m_VideoFormats << oneSwitch.getLabel();
190 auto format = sp->findOnSwitch();
192 m_StreamRecording = format->label;
195 else if (prop.isNameMatch(
"CCD_EXPOSURE_PRESETS"))
197 auto svp = prop.getSwitch();
202 for (
const auto &it : *svp)
209 if (parts.
count() == 2)
211 bool numOk =
false, denOk =
false;
212 double numerator = parts[0].toDouble(&numOk);
213 double denominator = parts[1].toDouble(&denOk);
214 if (numOk && denOk && denominator > 0)
217 value = numerator / denominator;
222 m_ExposurePresets.insert(key, value);
224 double min = 1e6, max = 1e-6;
225 for (
auto oneValue : m_ExposurePresets.values())
232 m_ExposurePresetsMinMax = qMakePair(min, max);
236 else if (prop.isNameMatch(
"CCD_FAST_TOGGLE"))
238 auto sp = prop.getSwitch();
240 m_FastExposureEnabled = sp->findOnSwitchIndex() == 0;
242 m_FastExposureEnabled =
false;
244 else if (prop.isNameMatch(
"TELESCOPE_TYPE"))
246 auto sp = prop.getSwitch();
249 auto format = sp->findWidgetByName(
"TELESCOPE_PRIMARY");
250 if (format && format->getState() == ISS_ON)
251 telescopeType = TELESCOPE_PRIMARY;
253 telescopeType = TELESCOPE_GUIDE;
256 else if (prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
258 auto np = prop.getNumber();
259 m_Media->setURL(
QUrl(
QString(
"ws://%1:%2").arg(m_Parent->getClientManager()->getHost()).
arg(np->at(0)->getValue())));
260 m_Media->connectServer();
262 else if (prop.isNameMatch(
"CCD1"))
264 primaryCCDBLOB = prop;
267 else if ( (gainN ==
nullptr || offsetN ==
nullptr) && prop.getType() == INDI_NUMBER)
271 auto controlNP = prop.getNumber();
274 for (
auto &it : *controlNP)
279 if (name ==
"gain" || label ==
"gain")
282 gainPerm = controlNP->getPermission();
284 else if (name ==
"offset" || label ==
"offset")
287 offsetPerm = controlNP->getPermission();
293 ConcreteDevice::registerProperty(prop);
296void Camera::removeProperty(INDI::Property prop)
298 if (prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
300 m_Media->disconnectServer();
304void Camera::processNumber(INDI::Property prop)
306 auto nvp = prop.getNumber();
307 if (nvp->isNameMatch(
"CCD_EXPOSURE"))
309 auto np = nvp->findWidgetByName(
"CCD_EXPOSURE_VALUE");
311 emit newExposureValue(primaryChip.get(), np->getValue(), nvp->getState());
312 if (nvp->getState() == IPS_ALERT)
313 emit
error(ERROR_CAPTURE);
315 else if (prop.isNameMatch(
"CCD_TEMPERATURE"))
318 auto np = nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
320 emit newTemperatureValue(np->getValue());
322 else if (prop.isNameMatch(
"GUIDER_EXPOSURE"))
324 auto np = nvp->findWidgetByName(
"GUIDER_EXPOSURE_VALUE");
326 emit newExposureValue(guideChip.get(), np->getValue(), nvp->getState());
328 else if (prop.isNameMatch(
"FPS"))
330 emit newFPS(nvp->at(0)->getValue(), nvp->at(1)->getValue());
332 else if (prop.isNameMatch(
"CCD_RAPID_GUIDE_DATA"))
334 if (nvp->getState() == IPS_ALERT)
336 emit newGuideStarData(primaryChip.get(), -1, -1, -1);
340 double dx = -1, dy = -1, fit = -1;
342 auto np = nvp->findWidgetByName(
"GUIDESTAR_X");
345 np = nvp->findWidgetByName(
"GUIDESTAR_Y");
348 np = nvp->findWidgetByName(
"GUIDESTAR_FIT");
350 fit = np->getValue();
352 if (dx >= 0 && dy >= 0 && fit >= 0)
353 emit newGuideStarData(primaryChip.get(), dx, dy, fit);
356 else if (prop.isNameMatch(
"GUIDER_RAPID_GUIDE_DATA"))
358 if (nvp->getState() == IPS_ALERT)
360 emit newGuideStarData(guideChip.get(), -1, -1, -1);
364 double dx = -1, dy = -1, fit = -1;
365 auto np = nvp->findWidgetByName(
"GUIDESTAR_X");
368 np = nvp->findWidgetByName(
"GUIDESTAR_Y");
371 np = nvp->findWidgetByName(
"GUIDESTAR_FIT");
373 fit = np->getValue();
375 if (dx >= 0 && dy >= 0 && fit >= 0)
376 emit newGuideStarData(guideChip.get(), dx, dy, fit);
381void Camera::processSwitch(INDI::Property prop)
383 auto svp = prop.getSwitch();
385 if (svp->isNameMatch(
"CCD_COOLER"))
388 HasCoolerControl =
true;
389 emit coolerToggled(svp->sp[0].s == ISS_ON);
394 if (isBLOBEnabled() ==
false || m_StreamingEnabled ==
false)
397 HasVideoStream =
true;
399 if (svp->sp[0].s == ISS_ON)
401 INumberVectorProperty *streamFrame = getNumber(
"CCD_STREAM_FRAME");
402 INumber *w =
nullptr, *h =
nullptr;
406 w = IUFindNumber(streamFrame,
"WIDTH");
407 h = IUFindNumber(streamFrame,
"HEIGHT");
418 auto rawBP = getBLOB(
"CCD1");
421 int x = 0, y = 0, w = 0, h = 0;
422 int binx = 0, biny = 0;
424 primaryChip->getFrame(&x, &y, &w, &h);
425 primaryChip->getBinning(&binx, &biny);
431 emit updateVideoWindow(streamW, streamH, svp->sp[0].s == ISS_ON);
434 m_isStreamEnabled = (svp->sp[0].s == ISS_ON);
435 emit videoStreamToggled(m_isStreamEnabled);
437 else if (svp->isNameMatch(
"CCD_CAPTURE_FORMAT"))
439 m_CaptureFormats.clear();
440 for (
int i = 0; i < svp->nsp; i++)
442 m_CaptureFormats << svp->sp[i].label;
443 if (svp->sp[i].s == ISS_ON)
444 m_CaptureFormatIndex = i;
447 else if (svp->isNameMatch(
"CCD_TRANSFER_FORMAT"))
449 ISwitch *format = IUFindOnSwitch(svp);
451 m_EncodingFormat = format->label;
453 else if (svp->isNameMatch(
"RECORD_STREAM"))
455 ISwitch *recordOFF = IUFindSwitch(svp,
"RECORD_OFF");
457 if (recordOFF && recordOFF->s == ISS_ON)
459 emit videoRecordToggled(
false);
460 if (m_isStreamEnabled)
462 m_isStreamEnabled =
false;
463 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Stopped"), KSNotification::INDI);
466 else if (m_isStreamEnabled ==
false)
468 emit videoRecordToggled(
true);
469 m_isStreamEnabled =
true;
470 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Started"), KSNotification::INDI);
473 else if (svp->isNameMatch(
"TELESCOPE_TYPE"))
475 ISwitch *format = IUFindSwitch(svp,
"TELESCOPE_PRIMARY");
476 if (format && format->s == ISS_ON)
477 telescopeType = TELESCOPE_PRIMARY;
479 telescopeType = TELESCOPE_GUIDE;
481 else if (!strcmp(svp->name,
"CCD_FAST_TOGGLE"))
483 m_FastExposureEnabled = IUFindOnSwitchIndex(svp) == 0;
485 else if (svp->isNameMatch(
"CONNECTION"))
487 auto dSwitch = svp->findWidgetByName(
"DISCONNECT");
489 if (dSwitch && dSwitch->getState() == ISS_ON)
491 emit videoStreamToggled(
false);
492 emit closeVideoWindow();
497 primaryCCDBLOB = INDI::Property();
502void Camera::processText(INDI::Property prop)
504 auto tvp = prop.getText();
505 if (tvp->isNameMatch(
"CCD_FILE_PATH"))
507 auto filepath = tvp->findWidgetByName(
"FILE_PATH");
509 emit newRemoteFile(
QString(filepath->getText()));
518 auto bvp = primaryCCDBLOB.getBLOB();
519 auto bp = bvp->at(0);
521 bp->setBlob(
const_cast<char *
>(message.
data()));
522 bp->setSize(message.
size());
524 processBLOB(primaryCCDBLOB);
527 bp->setBlob(
nullptr);
530void Camera::processStream(INDI::Property prop)
532 if (m_isStreamEnabled ==
false)
535 INumberVectorProperty *streamFrame = getNumber(
"CCD_STREAM_FRAME");
536 INumber *w =
nullptr, *h =
nullptr;
540 w = IUFindNumber(streamFrame,
"WIDTH");
541 h = IUFindNumber(streamFrame,
"HEIGHT");
551 int x = 0, y = 0, w = 0, h = 0;
552 int binx = 1, biny = 1;
554 primaryChip->getFrame(&x, &y, &w, &h);
555 primaryChip->getBinning(&binx, &biny);
560 emit showVideoFrame(prop, streamW, streamH);
563void ISD::Camera::updateFileBuffer(INDI::Property prop,
bool is_fits)
569 if (fileWriteThread.isRunning())
571 fileWriteThread.waitForFinished();
578 auto bp = prop.getBLOB()->at(0);
580 if (fileWriteBufferSize != bp->getBlobLen())
582 if (fileWriteBuffer !=
nullptr)
583 delete [] fileWriteBuffer;
584 fileWriteBufferSize = bp->getBlobLen();
585 fileWriteBuffer =
new char[fileWriteBufferSize];
590 memcpy(fileWriteBuffer, bp->getBlob(), bp->getBlobLen());
597 if (BType == BLOB_FITS)
601 if (fileWriteThread.isRunning())
603 fileWriteThread.waitForFinished();
607#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
608 fileWriteThread =
QtConcurrent::run(&ISD::Camera::WriteImageFileInternal,
this, filename, fileWriteBuffer,
609 fileWriteBufferSize);
611 fileWriteThread =
QtConcurrent::run(
this, &ISD::Camera::WriteImageFileInternal, filename, fileWriteBuffer,
612 fileWriteBufferSize);
615 else if (!WriteImageFileInternal(filename,
static_cast<char*
>(fileWriteBuffer), fileWriteBufferSize))
621bool Camera::processBLOB(INDI::Property prop)
623 auto bvp = prop.getBLOB();
625 if (bvp->getPermission() == IP_WO || bvp->at(0)->getSize() == 0)
630 auto bp = bvp->at(0);
635 if (format.contains(
"stream"))
637 if (m_StreamingEnabled ==
false)
650 else if (format.contains(
"fits"))
652 else if (format.contains(
"xisf"))
654 else if (RAWFormats.contains(shortFormat))
657 if (BType == BLOB_OTHER)
660 CameraChip *targetChip =
nullptr;
662 if (bvp->isNameMatch(
"CCD2"))
663 targetChip = guideChip.get();
666 targetChip = primaryChip.get();
667 qCDebug(KSTARS_INDI) <<
"Image received. Mode:" << getFITSModeStringString(targetChip->getCaptureMode()) <<
"Size:" <<
675 updateFileBuffer(prop, BType == BLOB_FITS);
685 QSharedPointer<FITSData> imageData;
687 imageData->setExtension(shortFormat);
692 if ((Options::useFITSViewer() || Options::useSummaryPreview() || targetChip->getCaptureMode() != FITS_NORMAL
693 || !targetChip->isBatchMode()) &&
694 !imageData->loadFromBuffer(buffer))
701 imageData->setProperty(
"device", getDeviceName());
702 imageData->setProperty(
"blobVector", prop.getName());
703 imageData->setProperty(
"blobElement", bp->getName());
704 imageData->setProperty(
"chip", targetChip->getType());
707 targetChip->setImageData(imageData);
708 emit propertyUpdated(prop);
709 emit newImage(imageData, QString(bp->getFormat()).toLower());
714void Camera::StreamWindowHidden()
719 auto streamSP =
getSwitch(
"CCD_VIDEO_STREAM");
723 streamSP->at(0)->setState(ISS_OFF);
724 streamSP->at(1)->setState(ISS_ON);
725 streamSP->setState(IPS_IDLE);
733 streamSP->at(0)->setState(ISS_OFF);
734 streamSP->at(1)->setState(ISS_ON);
735 streamSP->setState(IPS_IDLE);
739 streamSP =
getSwitch(
"AUX_VIDEO_STREAM");
743 streamSP->at(0)->setState(ISS_OFF);
744 streamSP->at(1)->setState(ISS_ON);
745 streamSP->setState(IPS_IDLE);
751bool Camera::hasGuideHead()
756bool Camera::hasCooler()
761bool Camera::hasCoolerControl()
763 return HasCoolerControl;
766bool Camera::setCoolerControl(
bool enable)
768 if (HasCoolerControl ==
false)
777 auto coolerON = coolerSP->findWidgetByName(
"COOLER_ON");
778 auto coolerOFF = coolerSP->findWidgetByName(
"COOLER_OFF");
779 if (!coolerON || !coolerOFF)
782 coolerON->setState(enable ? ISS_ON : ISS_OFF);
783 coolerOFF->setState(enable ? ISS_OFF : ISS_ON);
789CameraChip *Camera::getChip(CameraChip::ChipType cType)
793 case CameraChip::PRIMARY_CCD:
794 return primaryChip.get();
796 case CameraChip::GUIDE_CCD:
797 return guideChip.get();
803bool Camera::setRapidGuide(
CameraChip *targetChip,
bool enable)
805 ISwitchVectorProperty *rapidSP =
nullptr;
806 ISwitch *enableS =
nullptr;
808 if (targetChip == primaryChip.get())
811 rapidSP =
getSwitch(
"GUIDER_RAPID_GUIDE");
813 if (rapidSP ==
nullptr)
816 enableS = IUFindSwitch(rapidSP,
"ENABLE");
818 if (enableS ==
nullptr)
822 if ((enable && enableS->s == ISS_ON) || (!enable && enableS->s == ISS_OFF))
825 IUResetSwitch(rapidSP);
826 rapidSP->sp[0].s = enable ? ISS_ON : ISS_OFF;
827 rapidSP->sp[1].s = enable ? ISS_OFF : ISS_ON;
834bool Camera::configureRapidGuide(
CameraChip *targetChip,
bool autoLoop,
bool sendImage,
bool showMarker)
836 ISwitchVectorProperty *rapidSP =
nullptr;
837 ISwitch *autoLoopS =
nullptr, *sendImageS =
nullptr, *showMarkerS =
nullptr;
839 if (targetChip == primaryChip.get())
840 rapidSP =
getSwitch(
"CCD_RAPID_GUIDE_SETUP");
842 rapidSP =
getSwitch(
"GUIDER_RAPID_GUIDE_SETUP");
844 if (rapidSP ==
nullptr)
847 autoLoopS = IUFindSwitch(rapidSP,
"AUTO_LOOP");
848 sendImageS = IUFindSwitch(rapidSP,
"SEND_IMAGE");
849 showMarkerS = IUFindSwitch(rapidSP,
"SHOW_MARKER");
851 if (!autoLoopS || !sendImageS || !showMarkerS)
855 if (((autoLoop && autoLoopS->s == ISS_ON) || (!autoLoop && autoLoopS->s == ISS_OFF)) &&
856 ((sendImage && sendImageS->s == ISS_ON) || (!sendImage && sendImageS->s == ISS_OFF)) &&
857 ((showMarker && showMarkerS->s == ISS_ON) || (!showMarker && showMarkerS->s == ISS_OFF)))
860 autoLoopS->s = autoLoop ? ISS_ON : ISS_OFF;
861 sendImageS->s = sendImage ? ISS_ON : ISS_OFF;
862 showMarkerS->s = showMarker ? ISS_ON : ISS_OFF;
869void Camera::updateUploadSettings(
const QString &uploadDirectory,
const QString &uploadFile)
871 ITextVectorProperty *uploadSettingsTP =
nullptr;
872 IText *uploadT =
nullptr;
874 uploadSettingsTP =
getText(
"UPLOAD_SETTINGS");
875 if (uploadSettingsTP)
877 uploadT = IUFindText(uploadSettingsTP,
"UPLOAD_DIR");
878 if (uploadT && uploadDirectory.
isEmpty() ==
false)
880 auto posixDirectory = uploadDirectory;
883 IUSaveText(uploadT, posixDirectory.toLatin1().constData());
886 uploadT = IUFindText(uploadSettingsTP,
"UPLOAD_PREFIX");
894Camera::UploadMode Camera::getUploadMode()
896 ISwitchVectorProperty *uploadModeSP =
nullptr;
900 if (uploadModeSP ==
nullptr)
902 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
903 return UPLOAD_CLIENT;
908 ISwitch *modeS =
nullptr;
910 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_CLIENT");
911 if (modeS && modeS->s == ISS_ON)
912 return UPLOAD_CLIENT;
913 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_LOCAL");
914 if (modeS && modeS->s == ISS_ON)
915 return UPLOAD_REMOTE;
916 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_BOTH");
917 if (modeS && modeS->s == ISS_ON)
922 return UPLOAD_CLIENT;
925bool Camera::setUploadMode(UploadMode mode)
927 ISwitch *modeS =
nullptr;
929 auto uploadModeSP =
getSwitch(
"UPLOAD_MODE");
933 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
940 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_CLIENT");
943 if (modeS->s == ISS_ON)
948 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_BOTH");
951 if (modeS->s == ISS_ON)
956 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_LOCAL");
959 if (modeS->s == ISS_ON)
964 uploadModeSP->reset();
972bool Camera::getTemperature(
double *value)
974 if (HasCooler ==
false)
977 auto temperatureNP = getNumber(
"CCD_TEMPERATURE");
982 *value = temperatureNP->at(0)->getValue();
987bool Camera::setTemperature(
double value)
989 auto nvp = getNumber(
"CCD_TEMPERATURE");
994 auto np = nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
1006bool Camera::setEncodingFormat(
const QString &value)
1008 if (value.
isEmpty() || value == m_EncodingFormat)
1011 auto svp =
getSwitch(
"CCD_TRANSFER_FORMAT");
1017 for (
int i = 0; i < svp->nsp; i++)
1019 if (svp->at(i)->getLabel() == value)
1021 svp->at(i)->setState(ISS_ON);
1026 m_EncodingFormat = value;
1031bool Camera::setStreamEncoding(
const QString &value)
1033 if (value.
isEmpty() || value == m_StreamEncoding)
1036 auto svp =
getSwitch(
"CCD_STREAM_ENCODER");
1042 for (
int i = 0; i < svp->nsp; i++)
1044 if (svp->at(i)->getLabel() == value)
1046 svp->at(i)->setState(ISS_ON);
1051 m_StreamEncoding = value;
1056bool Camera::setStreamRecording(
const QString &value)
1058 if (value.
isEmpty() || value == m_StreamRecording)
1061 auto svp =
getSwitch(
"CCD_STREAM_RECORDER");
1067 for (
int i = 0; i < svp->nsp; i++)
1069 if (svp->at(i)->getLabel() == value)
1071 svp->at(i)->setState(ISS_ON);
1076 m_StreamRecording = value;
1081bool Camera::setTelescopeType(TelescopeType type)
1083 if (type == telescopeType)
1091 auto typePrimary = svp->findWidgetByName(
"TELESCOPE_PRIMARY");
1092 auto typeGuide = svp->findWidgetByName(
"TELESCOPE_GUIDE");
1094 if (!typePrimary || !typeGuide)
1097 telescopeType =
type;
1099 if ( (telescopeType == TELESCOPE_PRIMARY && typePrimary->getState() == ISS_OFF) ||
1100 (telescopeType == TELESCOPE_GUIDE && typeGuide->getState() == ISS_OFF))
1102 typePrimary->setState(telescopeType == TELESCOPE_PRIMARY ? ISS_ON : ISS_OFF);
1103 typeGuide->setState(telescopeType == TELESCOPE_PRIMARY ? ISS_OFF : ISS_ON);
1105 setConfig(SAVE_CONFIG);
1111bool Camera::setVideoStreamEnabled(
bool enable)
1113 if (HasVideoStream ==
false)
1116 m_isStreamEnabled = enable;
1118 auto svp =
getSwitch(
"CCD_VIDEO_STREAM");
1124 if ((enable && svp->at(0)->getState() == ISS_ON) || (!enable && svp->at(1)->getState() == ISS_ON))
1127 svp->at(0)->setState(enable ? ISS_ON : ISS_OFF);
1128 svp->at(1)->setState(enable ? ISS_OFF : ISS_ON);
1135bool Camera::resetStreamingFrame()
1137 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1142 auto xarg = frameProp->findWidgetByName(
"X");
1143 auto yarg = frameProp->findWidgetByName(
"Y");
1144 auto warg = frameProp->findWidgetByName(
"WIDTH");
1145 auto harg = frameProp->findWidgetByName(
"HEIGHT");
1147 if (xarg && yarg && warg && harg)
1149 if (!std::fabs(xarg->getValue() - xarg->getMin()) &&
1150 !std::fabs(yarg->getValue() - yarg->getMin()) &&
1151 !std::fabs(warg->getValue() - warg->getMax()) &&
1152 !std::fabs(harg->getValue() - harg->getMax()))
1155 xarg->setValue(xarg->getMin());
1156 yarg->setValue(yarg->getMin());
1157 warg->setValue(warg->getMax());
1158 harg->setValue(harg->getMax());
1167bool Camera::setStreamLimits(uint16_t maxBufferSize, uint16_t maxPreviewFPS)
1169 auto limitsProp = getNumber(
"LIMITS");
1174 auto bufferMax = limitsProp->findWidgetByName(
"LIMITS_BUFFER_MAX");
1175 auto previewFPS = limitsProp->findWidgetByName(
"LIMITS_PREVIEW_FPS");
1177 if (bufferMax && previewFPS)
1179 if(std::fabs(bufferMax->getValue() - maxBufferSize) > 0 || std::fabs(previewFPS->getValue() - maxPreviewFPS) > 0)
1181 bufferMax->setValue(maxBufferSize);
1182 previewFPS->setValue(maxPreviewFPS);
1192bool Camera::setStreamingFrame(
int x,
int y,
int w,
int h)
1194 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1199 auto xarg = frameProp->findWidgetByName(
"X");
1200 auto yarg = frameProp->findWidgetByName(
"Y");
1201 auto warg = frameProp->findWidgetByName(
"WIDTH");
1202 auto harg = frameProp->findWidgetByName(
"HEIGHT");
1204 if (xarg && yarg && warg && harg)
1206 if (!std::fabs(xarg->getValue() - x) &&
1207 !std::fabs(yarg->getValue() - y) &&
1208 !std::fabs(warg->getValue() - w) &&
1209 !std::fabs(harg->getValue() - h))
1213 xarg->value = qBound(xarg->getMin(),
static_cast<double>(x) + xarg->getValue(), xarg->getMax());
1214 yarg->value = qBound(yarg->getMin(),
static_cast<double>(y) + yarg->getValue(), yarg->getMax());
1215 warg->value = qBound(warg->getMin(),
static_cast<double>(w), warg->getMax());
1216 harg->value = qBound(harg->getMin(),
static_cast<double>(h), harg->getMax());
1225bool Camera::isStreamingEnabled()
1227 return (HasVideoStream && m_isStreamEnabled);
1230bool Camera::setSERNameDirectory(
const QString &filename,
const QString &directory)
1232 auto tvp =
getText(
"RECORD_FILE");
1237 auto filenameT = tvp->findWidgetByName(
"RECORD_FILE_NAME");
1238 auto dirT = tvp->findWidgetByName(
"RECORD_FILE_DIR");
1240 if (!filenameT || !dirT)
1251bool Camera::getSERNameDirectory(QString &filename, QString &directory)
1253 auto tvp =
getText(
"RECORD_FILE");
1258 auto filenameT = tvp->findWidgetByName(
"RECORD_FILE_NAME");
1259 auto dirT = tvp->findWidgetByName(
"RECORD_FILE_DIR");
1261 if (!filenameT || !dirT)
1264 filename = QString(filenameT->getText());
1265 directory = QString(dirT->getText());
1270bool Camera::startRecording()
1277 auto recordON = svp->findWidgetByName(
"RECORD_ON");
1282 if (recordON->getState() == ISS_ON)
1286 recordON->setState(ISS_ON);
1293bool Camera::startDurationRecording(
double duration)
1295 auto nvp = getNumber(
"RECORD_OPTIONS");
1300 auto durationN = nvp->findWidgetByName(
"RECORD_DURATION");
1310 auto recordON = svp->findWidgetByName(
"RECORD_DURATION_ON");
1315 if (recordON->getState() == ISS_ON)
1318 durationN->setValue(duration);
1322 recordON->setState(ISS_ON);
1329bool Camera::startFramesRecording(uint32_t frames)
1331 auto nvp = getNumber(
"RECORD_OPTIONS");
1336 auto frameN = nvp->findWidgetByName(
"RECORD_FRAME_TOTAL");
1339 if (!frameN || !svp)
1342 auto recordON = svp->findWidgetByName(
"RECORD_FRAME_ON");
1347 if (recordON->getState() == ISS_ON)
1350 frameN->setValue(frames);
1354 recordON->setState(ISS_ON);
1361bool Camera::stopRecording()
1368 auto recordOFF = svp->findWidgetByName(
"RECORD_OFF");
1374 if (recordOFF->getState() == ISS_ON)
1378 recordOFF->setState(ISS_ON);
1385bool Camera::setFITSHeaders(
const QList<FITSData::Record> &values)
1387 auto tvp =
getText(
"FITS_HEADER");
1390 if (!tvp || tvp->count() < 3)
1393 for (
auto &record : values)
1395 tvp->at(0)->setText(record.key.toLatin1().constData());
1396 tvp->at(1)->setText(record.value.toString().toLatin1().constData());
1397 tvp->at(2)->setText(record.comment.toLatin1().constData());
1405bool Camera::setGain(
double value)
1410 gainN->value = value;
1415bool Camera::getGain(
double *value)
1420 *value = gainN->value;
1425bool Camera::getGainMinMaxStep(
double *min,
double *max,
double *step)
1432 *step = gainN->step;
1437bool Camera::setOffset(
double value)
1442 offsetN->value = value;
1447bool Camera::getOffset(
double *value)
1452 *value = offsetN->value;
1457bool Camera::getOffsetMinMaxStep(
double *min,
double *max,
double *step)
1462 *min = offsetN->min;
1463 *max = offsetN->max;
1464 *step = offsetN->step;
1469bool Camera::isBLOBEnabled()
1471 return (m_Parent->getClientManager()->isBLOBEnabled(getDeviceName(),
"CCD1"));
1474bool Camera::setBLOBEnabled(
bool enable,
const QString &prop)
1476 m_Parent->getClientManager()->setBLOBEnabled(enable, getDeviceName(), prop);
1481bool Camera::setFastExposureEnabled(
bool enable)
1484 m_FastExposureEnabled = enable;
1486 auto svp =
getSwitch(
"CCD_FAST_TOGGLE");
1491 svp->at(0)->setState(enable ? ISS_ON : ISS_OFF);
1492 svp->at(1)->setState(enable ? ISS_OFF : ISS_ON);
1498bool Camera::setCaptureFormat(
const QString &format)
1500 auto svp =
getSwitch(
"CCD_CAPTURE_FORMAT");
1504 for (
auto &oneSwitch : *svp)
1505 oneSwitch.setState(oneSwitch.label == format ? ISS_ON : ISS_OFF);
1511bool Camera::setFastCount(uint32_t count)
1513 auto nvp = getNumber(
"CCD_FAST_COUNT");
1518 nvp->at(0)->setValue(count);
1525bool Camera::setStreamExposure(
double duration)
1527 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1532 nvp->at(0)->setValue(duration);
1539bool Camera::getStreamExposure(
double *duration)
1541 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1546 *duration = nvp->at(0)->getValue();
1551bool Camera::isCoolerOn()
1558 return (svp->at(0)->getState() == ISS_ON);
1561bool Camera::getTemperatureRegulation(
double &ramp,
double &threshold)
1563 auto regulation = getProperty(
"CCD_TEMP_RAMP");
1564 if (!regulation.isValid())
1567 ramp = regulation.getNumber()->at(0)->getValue();
1568 threshold = regulation.getNumber()->at(1)->getValue();
1572bool Camera::setTemperatureRegulation(
double ramp,
double threshold)
1574 auto regulation = getProperty(
"CCD_TEMP_RAMP");
1575 if (!regulation.isValid())
1578 regulation.getNumber()->at(0)->setValue(ramp);
1579 regulation.getNumber()->at(1)->setValue(threshold);
1584bool Camera::setScopeInfo(
double focalLength,
double aperture)
1586 auto scopeInfo = getProperty(
"SCOPE_INFO");
1587 if (!scopeInfo.isValid())
1590 auto nvp = scopeInfo.getNumber();
1591 nvp->at(0)->setValue(focalLength);
1592 nvp->at(1)->setValue(aperture);
1598bool Camera::WriteImageFileInternal(
const QString &filename,
char *buffer,
const size_t size)
1600 QFile file(filename);
1603 qCCritical(KSTARS_INDI) <<
"ISD:CCD Error: Unable to open write file: " <<
1608 QDataStream out(&file);
1610 for (
size_t nr = 0; nr < size; nr += n)
1612 n = out.writeRawData(buffer + nr, size - nr);
1619 ok = file.flush() &&
ok;
1628QString Camera::getCaptureFormat()
const
1630 if (m_CaptureFormatIndex < 0 || m_CaptureFormats.isEmpty() || m_CaptureFormatIndex >= m_CaptureFormats.size())
1631 return QLatin1String(
"NA");
1633 return m_CaptureFormats[m_CaptureFormatIndex];
CameraChip class controls a particular chip in camera.
@ ERROR_LOAD
Saving to disk error.
bool saveCurrentImage(QString &filename)
saveCurrentImage save the image that is currently in the image data buffer
The ConcreteDevice class.
void sendNewProperty(INDI::Property prop)
Send new property command to server.
INDI::PropertyView< IText > * getText(const QString &name) const
INDI::PropertyView< ISwitch > * getSwitch(const QString &name) const
GenericDevice is the Generic Device for INDI devices.
static KNotification * event(const QString &eventId, const QString &text=QString(), const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
QString i18n(const char *text, const TYPE &arg...)
ISD is a collection of INDI Standard Devices.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardAction id)
QString label(StandardShortcut id)
const char * constData() const const
QByteArray fromRawData(const char *data, qsizetype size)
qsizetype size() const const
QDateTime currentDateTime()
qsizetype count() const const
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
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)