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 <KNotifications/KNotification>
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];
43Camera::Camera(GenericDevice *parent) : ConcreteDevice(parent)
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_TRANSFER_FORMAT"))
155 auto sp = prop.getSwitch();
158 m_EncodingFormats.clear();
159 for (
const auto &oneSwitch : *sp)
160 m_EncodingFormats << oneSwitch.getLabel();
162 auto format = sp->findOnSwitch();
164 m_EncodingFormat = format->label;
167 else if (prop.isNameMatch(
"CCD_EXPOSURE_PRESETS"))
169 auto svp = prop.getSwitch();
174 for (
const auto &it : *svp)
181 if (parts.
count() == 2)
183 bool numOk =
false, denOk =
false;
184 double numerator = parts[0].toDouble(&numOk);
185 double denominator = parts[1].toDouble(&denOk);
186 if (numOk && denOk && denominator > 0)
189 value = numerator / denominator;
194 m_ExposurePresets.insert(key, value);
196 double min = 1e6, max = 1e-6;
197 for (
auto oneValue : m_ExposurePresets.values())
204 m_ExposurePresetsMinMax = qMakePair<double, double>(min, max);
208 else if (prop.isNameMatch(
"CCD_FAST_TOGGLE"))
210 auto sp = prop.getSwitch();
212 m_FastExposureEnabled = sp->findOnSwitchIndex() == 0;
214 m_FastExposureEnabled =
false;
216 else if (prop.isNameMatch(
"TELESCOPE_TYPE"))
218 auto sp = prop.getSwitch();
221 auto format = sp->findWidgetByName(
"TELESCOPE_PRIMARY");
222 if (format && format->getState() == ISS_ON)
223 telescopeType = TELESCOPE_PRIMARY;
225 telescopeType = TELESCOPE_GUIDE;
228 else if (prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
230 auto np = prop.getNumber();
231 m_Media->setURL(
QUrl(
QString(
"ws://%1:%2").arg(m_Parent->getClientManager()->getHost()).
arg(np->at(0)->getValue())));
232 m_Media->connectServer();
234 else if (prop.isNameMatch(
"CCD1"))
236 primaryCCDBLOB = prop;
239 else if ( (gainN ==
nullptr || offsetN ==
nullptr) && prop.getType() == INDI_NUMBER)
243 auto controlNP = prop.getNumber();
246 for (
auto &it : *controlNP)
251 if (name ==
"gain" || label ==
"gain")
254 gainPerm = controlNP->getPermission();
256 else if (name ==
"offset" || label ==
"offset")
259 offsetPerm = controlNP->getPermission();
265 ConcreteDevice::registerProperty(prop);
268void Camera::removeProperty(INDI::Property prop)
270 if (prop.isNameMatch(
"CCD_WEBSOCKET_SETTINGS"))
272 m_Media->disconnectServer();
276void Camera::processNumber(INDI::Property prop)
278 auto nvp = prop.getNumber();
279 if (nvp->isNameMatch(
"CCD_EXPOSURE"))
281 auto np = nvp->findWidgetByName(
"CCD_EXPOSURE_VALUE");
283 emit newExposureValue(primaryChip.get(), np->getValue(), nvp->getState());
284 if (nvp->getState() == IPS_ALERT)
285 emit
error(ERROR_CAPTURE);
287 else if (prop.isNameMatch(
"CCD_TEMPERATURE"))
290 auto np = nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
292 emit newTemperatureValue(np->getValue());
294 else if (prop.isNameMatch(
"GUIDER_EXPOSURE"))
296 auto np = nvp->findWidgetByName(
"GUIDER_EXPOSURE_VALUE");
298 emit newExposureValue(guideChip.get(), np->getValue(), nvp->getState());
300 else if (prop.isNameMatch(
"FPS"))
302 emit newFPS(nvp->at(0)->getValue(), nvp->at(1)->getValue());
304 else if (prop.isNameMatch(
"CCD_RAPID_GUIDE_DATA"))
306 if (nvp->getState() == IPS_ALERT)
308 emit newGuideStarData(primaryChip.get(), -1, -1, -1);
312 double dx = -1, dy = -1, fit = -1;
314 auto np = nvp->findWidgetByName(
"GUIDESTAR_X");
317 np = nvp->findWidgetByName(
"GUIDESTAR_Y");
320 np = nvp->findWidgetByName(
"GUIDESTAR_FIT");
322 fit = np->getValue();
324 if (dx >= 0 && dy >= 0 && fit >= 0)
325 emit newGuideStarData(primaryChip.get(), dx, dy, fit);
328 else if (prop.isNameMatch(
"GUIDER_RAPID_GUIDE_DATA"))
330 if (nvp->getState() == IPS_ALERT)
332 emit newGuideStarData(guideChip.get(), -1, -1, -1);
336 double dx = -1, dy = -1, fit = -1;
337 auto np = nvp->findWidgetByName(
"GUIDESTAR_X");
340 np = nvp->findWidgetByName(
"GUIDESTAR_Y");
343 np = nvp->findWidgetByName(
"GUIDESTAR_FIT");
345 fit = np->getValue();
347 if (dx >= 0 && dy >= 0 && fit >= 0)
348 emit newGuideStarData(guideChip.get(), dx, dy, fit);
353void Camera::processSwitch(INDI::Property prop)
355 auto svp = prop.getSwitch();
357 if (svp->isNameMatch(
"CCD_COOLER"))
360 HasCoolerControl =
true;
361 emit coolerToggled(svp->sp[0].s == ISS_ON);
366 if (isBLOBEnabled() ==
false || m_StreamingEnabled ==
false)
369 HasVideoStream =
true;
371 if (!streamWindow && svp->sp[0].s == ISS_ON)
373 streamWindow.reset(
new StreamWG(
this));
375 INumberVectorProperty *streamFrame = getNumber(
"CCD_STREAM_FRAME");
376 INumber *w =
nullptr, *h =
nullptr;
380 w = IUFindNumber(streamFrame,
"WIDTH");
381 h = IUFindNumber(streamFrame,
"HEIGHT");
392 auto rawBP = getBLOB(
"CCD1");
395 int x = 0, y = 0, w = 0, h = 0;
396 int binx = 0, biny = 0;
398 primaryChip->getFrame(&x, &y, &w, &h);
399 primaryChip->getBinning(&binx, &biny);
405 streamWindow->setSize(streamW, streamH);
413 streamWindow->enableStream(svp->sp[0].s == ISS_ON);
414 emit videoStreamToggled(svp->sp[0].s == ISS_ON);
417 else if (svp->isNameMatch(
"CCD_CAPTURE_FORMAT"))
419 m_CaptureFormats.clear();
420 for (
int i = 0; i < svp->nsp; i++)
422 m_CaptureFormats << svp->sp[i].label;
423 if (svp->sp[i].s == ISS_ON)
424 m_CaptureFormatIndex = i;
427 else if (svp->isNameMatch(
"CCD_TRANSFER_FORMAT"))
429 ISwitch *format = IUFindOnSwitch(svp);
431 m_EncodingFormat = format->label;
433 else if (svp->isNameMatch(
"RECORD_STREAM"))
435 ISwitch *recordOFF = IUFindSwitch(svp,
"RECORD_OFF");
437 if (recordOFF && recordOFF->s == ISS_ON)
439 emit videoRecordToggled(
false);
440 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Stopped"), KSNotification::INDI);
444 emit videoRecordToggled(
true);
445 KSNotification::event(
QLatin1String(
"IndiServerMessage"),
i18n(
"Video Recording Started"), KSNotification::INDI);
448 else if (svp->isNameMatch(
"TELESCOPE_TYPE"))
450 ISwitch *format = IUFindSwitch(svp,
"TELESCOPE_PRIMARY");
451 if (format && format->s == ISS_ON)
452 telescopeType = TELESCOPE_PRIMARY;
454 telescopeType = TELESCOPE_GUIDE;
456 else if (!strcmp(svp->name,
"CCD_FAST_TOGGLE"))
458 m_FastExposureEnabled = IUFindOnSwitchIndex(svp) == 0;
460 else if (svp->isNameMatch(
"CONNECTION"))
462 auto dSwitch = svp->findWidgetByName(
"DISCONNECT");
464 if (dSwitch && dSwitch->getState() == ISS_ON)
468 streamWindow->enableStream(
false);
469 emit videoStreamToggled(
false);
470 streamWindow->close();
471 streamWindow.reset();
477 primaryCCDBLOB = INDI::Property();
482void Camera::processText(INDI::Property prop)
484 auto tvp = prop.getText();
485 if (tvp->isNameMatch(
"CCD_FILE_PATH"))
487 auto filepath = tvp->findWidgetByName(
"FILE_PATH");
489 emit newRemoteFile(
QString(filepath->getText()));
498 auto bvp = primaryCCDBLOB.getBLOB();
499 auto bp = bvp->at(0);
501 bp->setBlob(
const_cast<char *
>(message.
data()));
502 bp->setSize(message.
size());
504 processBLOB(primaryCCDBLOB);
507 bp->setBlob(
nullptr);
510void Camera::processStream(INDI::Property prop)
512 if (!streamWindow || streamWindow->isStreamEnabled() ==
false)
515 INumberVectorProperty *streamFrame = getNumber(
"CCD_STREAM_FRAME");
516 INumber *w =
nullptr, *h =
nullptr;
520 w = IUFindNumber(streamFrame,
"WIDTH");
521 h = IUFindNumber(streamFrame,
"HEIGHT");
531 int x = 0, y = 0, w = 0, h = 0;
532 int binx = 1, biny = 1;
534 primaryChip->getFrame(&x, &y, &w, &h);
535 primaryChip->getBinning(&binx, &biny);
540 streamWindow->setSize(streamW, streamH);
542 streamWindow->show();
543 streamWindow->newFrame(prop);
546void ISD::Camera::updateFileBuffer(INDI::Property prop,
bool is_fits)
561 auto bp = prop.getBLOB()->at(0);
563 if (fileWriteBufferSize != bp->getBlobLen())
565 if (fileWriteBuffer !=
nullptr)
566 delete [] fileWriteBuffer;
567 fileWriteBufferSize = bp->getBlobLen();
568 fileWriteBuffer =
new char[fileWriteBufferSize];
573 memcpy(fileWriteBuffer, bp->getBlob(), bp->getBlobLen());
580 if (BType == BLOB_FITS)
590 fileWriteThread =
QtConcurrent::run(
this, &ISD::Camera::WriteImageFileInternal, filename, fileWriteBuffer,
591 fileWriteBufferSize);
593 else if (!WriteImageFileInternal(filename,
static_cast<char*
>(fileWriteBuffer), fileWriteBufferSize))
599bool Camera::processBLOB(INDI::Property prop)
601 auto bvp = prop.getBLOB();
603 if (bvp->getPermission() == IP_WO || bvp->at(0)->getSize() == 0)
608 auto bp = bvp->at(0);
613 if (format.contains(
"stream"))
615 if (m_StreamingEnabled ==
false)
617 else if (streamWindow)
628 else if (format.contains(
"fits"))
630 else if (format.contains(
"xisf"))
632 else if (RAWFormats.
contains(shortFormat))
635 if (BType == BLOB_OTHER)
638 CameraChip *targetChip =
nullptr;
640 if (bvp->isNameMatch(
"CCD2"))
641 targetChip = guideChip.get();
644 targetChip = primaryChip.get();
645 qCDebug(KSTARS_INDI) <<
"Image received. Mode:" << getFITSModeStringString(targetChip->getCaptureMode()) <<
"Size:" <<
653 updateFileBuffer(prop, BType == BLOB_FITS);
665 imageData->setExtension(shortFormat);
666 if (!imageData->loadFromBuffer(buffer))
673 imageData->setProperty(
"device", getDeviceName());
674 imageData->setProperty(
"blobVector", prop.getName());
675 imageData->setProperty(
"blobElement", bp->getName());
676 imageData->setProperty(
"chip", targetChip->getType());
679 targetChip->setImageData(imageData);
680 emit propertyUpdated(prop);
686void Camera::StreamWindowHidden()
691 auto streamSP =
getSwitch(
"CCD_VIDEO_STREAM");
695 streamSP->at(0)->setState(ISS_OFF);
696 streamSP->at(1)->setState(ISS_ON);
697 streamSP->setState(IPS_IDLE);
705 streamSP->at(0)->setState(ISS_OFF);
706 streamSP->at(1)->setState(ISS_ON);
707 streamSP->setState(IPS_IDLE);
711 streamSP =
getSwitch(
"AUX_VIDEO_STREAM");
715 streamSP->at(0)->setState(ISS_OFF);
716 streamSP->at(1)->setState(ISS_ON);
717 streamSP->setState(IPS_IDLE);
723 streamWindow->disconnect();
726bool Camera::hasGuideHead()
731bool Camera::hasCooler()
736bool Camera::hasCoolerControl()
738 return HasCoolerControl;
741bool Camera::setCoolerControl(
bool enable)
743 if (HasCoolerControl ==
false)
752 auto coolerON = coolerSP->findWidgetByName(
"COOLER_ON");
753 auto coolerOFF = coolerSP->findWidgetByName(
"COOLER_OFF");
754 if (!coolerON || !coolerOFF)
757 coolerON->setState(enable ? ISS_ON : ISS_OFF);
758 coolerOFF->setState(enable ? ISS_OFF : ISS_ON);
764CameraChip *Camera::getChip(CameraChip::ChipType cType)
768 case CameraChip::PRIMARY_CCD:
769 return primaryChip.get();
771 case CameraChip::GUIDE_CCD:
772 return guideChip.get();
778bool Camera::setRapidGuide(CameraChip *targetChip,
bool enable)
780 ISwitchVectorProperty *rapidSP =
nullptr;
781 ISwitch *enableS =
nullptr;
783 if (targetChip == primaryChip.get())
786 rapidSP =
getSwitch(
"GUIDER_RAPID_GUIDE");
788 if (rapidSP ==
nullptr)
791 enableS = IUFindSwitch(rapidSP,
"ENABLE");
793 if (enableS ==
nullptr)
797 if ((enable && enableS->s == ISS_ON) || (!enable && enableS->s == ISS_OFF))
800 IUResetSwitch(rapidSP);
801 rapidSP->sp[0].s = enable ? ISS_ON : ISS_OFF;
802 rapidSP->sp[1].s = enable ? ISS_OFF : ISS_ON;
809bool Camera::configureRapidGuide(CameraChip *targetChip,
bool autoLoop,
bool sendImage,
bool showMarker)
811 ISwitchVectorProperty *rapidSP =
nullptr;
812 ISwitch *autoLoopS =
nullptr, *sendImageS =
nullptr, *showMarkerS =
nullptr;
814 if (targetChip == primaryChip.get())
815 rapidSP =
getSwitch(
"CCD_RAPID_GUIDE_SETUP");
817 rapidSP =
getSwitch(
"GUIDER_RAPID_GUIDE_SETUP");
819 if (rapidSP ==
nullptr)
822 autoLoopS = IUFindSwitch(rapidSP,
"AUTO_LOOP");
823 sendImageS = IUFindSwitch(rapidSP,
"SEND_IMAGE");
824 showMarkerS = IUFindSwitch(rapidSP,
"SHOW_MARKER");
826 if (!autoLoopS || !sendImageS || !showMarkerS)
830 if (((autoLoop && autoLoopS->s == ISS_ON) || (!autoLoop && autoLoopS->s == ISS_OFF)) &&
831 ((sendImage && sendImageS->s == ISS_ON) || (!sendImage && sendImageS->s == ISS_OFF)) &&
832 ((showMarker && showMarkerS->s == ISS_ON) || (!showMarker && showMarkerS->s == ISS_OFF)))
835 autoLoopS->s = autoLoop ? ISS_ON : ISS_OFF;
836 sendImageS->s = sendImage ? ISS_ON : ISS_OFF;
837 showMarkerS->s = showMarker ? ISS_ON : ISS_OFF;
844void Camera::updateUploadSettings(
const QString &uploadDirectory,
const QString &uploadFile)
846 ITextVectorProperty *uploadSettingsTP =
nullptr;
847 IText *uploadT =
nullptr;
849 uploadSettingsTP =
getText(
"UPLOAD_SETTINGS");
850 if (uploadSettingsTP)
852 uploadT = IUFindText(uploadSettingsTP,
"UPLOAD_DIR");
853 if (uploadT && uploadDirectory.
isEmpty() ==
false)
855 auto posixDirectory = uploadDirectory;
858 IUSaveText(uploadT, posixDirectory.toLatin1().constData());
861 uploadT = IUFindText(uploadSettingsTP,
"UPLOAD_PREFIX");
869Camera::UploadMode Camera::getUploadMode()
871 ISwitchVectorProperty *uploadModeSP =
nullptr;
875 if (uploadModeSP ==
nullptr)
877 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
878 return UPLOAD_CLIENT;
883 ISwitch *modeS =
nullptr;
885 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_CLIENT");
886 if (modeS && modeS->s == ISS_ON)
887 return UPLOAD_CLIENT;
888 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_LOCAL");
889 if (modeS && modeS->s == ISS_ON)
891 modeS = IUFindSwitch(uploadModeSP,
"UPLOAD_BOTH");
892 if (modeS && modeS->s == ISS_ON)
897 return UPLOAD_CLIENT;
900bool Camera::setUploadMode(UploadMode mode)
902 ISwitch *modeS =
nullptr;
904 auto uploadModeSP =
getSwitch(
"UPLOAD_MODE");
908 qWarning() <<
"No UPLOAD_MODE in CCD driver. Please update driver to INDI compliant CCD driver.";
915 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_CLIENT");
918 if (modeS->s == ISS_ON)
923 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_BOTH");
926 if (modeS->s == ISS_ON)
931 modeS = uploadModeSP->findWidgetByName(
"UPLOAD_LOCAL");
934 if (modeS->s == ISS_ON)
939 uploadModeSP->reset();
947bool Camera::getTemperature(
double *value)
949 if (HasCooler ==
false)
952 auto temperatureNP = getNumber(
"CCD_TEMPERATURE");
957 *value = temperatureNP->at(0)->getValue();
962bool Camera::setTemperature(
double value)
964 auto nvp = getNumber(
"CCD_TEMPERATURE");
969 auto np = nvp->findWidgetByName(
"CCD_TEMPERATURE_VALUE");
981bool Camera::setEncodingFormat(
const QString &value)
983 if (value.
isEmpty() || value == m_EncodingFormat)
986 auto svp =
getSwitch(
"CCD_TRANSFER_FORMAT");
992 for (
int i = 0; i < svp->nsp; i++)
994 if (svp->at(i)->getLabel() == value)
996 svp->at(i)->setState(ISS_ON);
1001 m_EncodingFormat = value;
1006bool Camera::setTelescopeType(TelescopeType type)
1008 if (type == telescopeType)
1016 auto typePrimary = svp->findWidgetByName(
"TELESCOPE_PRIMARY");
1017 auto typeGuide = svp->findWidgetByName(
"TELESCOPE_GUIDE");
1019 if (!typePrimary || !typeGuide)
1022 telescopeType =
type;
1024 if ( (telescopeType == TELESCOPE_PRIMARY && typePrimary->getState() == ISS_OFF) ||
1025 (telescopeType == TELESCOPE_GUIDE && typeGuide->getState() == ISS_OFF))
1027 typePrimary->setState(telescopeType == TELESCOPE_PRIMARY ? ISS_ON : ISS_OFF);
1028 typeGuide->setState(telescopeType == TELESCOPE_PRIMARY ? ISS_OFF : ISS_ON);
1030 setConfig(SAVE_CONFIG);
1036bool Camera::setVideoStreamEnabled(
bool enable)
1038 if (HasVideoStream ==
false)
1041 auto svp =
getSwitch(
"CCD_VIDEO_STREAM");
1047 if ((enable && svp->at(0)->getState() == ISS_ON) || (!enable && svp->at(1)->getState() == ISS_ON))
1050 svp->at(0)->setState(enable ? ISS_ON : ISS_OFF);
1051 svp->at(1)->setState(enable ? ISS_OFF : ISS_ON);
1058bool Camera::resetStreamingFrame()
1060 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1065 auto xarg = frameProp->findWidgetByName(
"X");
1066 auto yarg = frameProp->findWidgetByName(
"Y");
1067 auto warg = frameProp->findWidgetByName(
"WIDTH");
1068 auto harg = frameProp->findWidgetByName(
"HEIGHT");
1070 if (xarg && yarg && warg && harg)
1072 if (!std::fabs(xarg->getValue() - xarg->getMin()) &&
1073 !std::fabs(yarg->getValue() - yarg->getMin()) &&
1074 !std::fabs(warg->getValue() - warg->getMax()) &&
1075 !std::fabs(harg->getValue() - harg->getMax()))
1078 xarg->setValue(xarg->getMin());
1079 yarg->setValue(yarg->getMin());
1080 warg->setValue(warg->getMax());
1081 harg->setValue(harg->getMax());
1090bool Camera::setStreamLimits(uint16_t maxBufferSize, uint16_t maxPreviewFPS)
1092 auto limitsProp = getNumber(
"LIMITS");
1097 auto bufferMax = limitsProp->findWidgetByName(
"LIMITS_BUFFER_MAX");
1098 auto previewFPS = limitsProp->findWidgetByName(
"LIMITS_PREVIEW_FPS");
1100 if (bufferMax && previewFPS)
1102 if(std::fabs(bufferMax->getValue() - maxBufferSize) > 0 || std::fabs(previewFPS->getValue() - maxPreviewFPS) > 0)
1104 bufferMax->setValue(maxBufferSize);
1105 previewFPS->setValue(maxPreviewFPS);
1115bool Camera::setStreamingFrame(
int x,
int y,
int w,
int h)
1117 auto frameProp = getNumber(
"CCD_STREAM_FRAME");
1122 auto xarg = frameProp->findWidgetByName(
"X");
1123 auto yarg = frameProp->findWidgetByName(
"Y");
1124 auto warg = frameProp->findWidgetByName(
"WIDTH");
1125 auto harg = frameProp->findWidgetByName(
"HEIGHT");
1127 if (xarg && yarg && warg && harg)
1129 if (!std::fabs(xarg->getValue() - x) &&
1130 !std::fabs(yarg->getValue() - y) &&
1131 !std::fabs(warg->getValue() - w) &&
1132 !std::fabs(harg->getValue() - h))
1136 xarg->value = qBound(xarg->getMin(),
static_cast<double>(x) + xarg->getValue(), xarg->getMax());
1137 yarg->value = qBound(yarg->getMin(),
static_cast<double>(y) + yarg->getValue(), yarg->getMax());
1138 warg->value = qBound(warg->getMin(),
static_cast<double>(w), warg->getMax());
1139 harg->value = qBound(harg->getMin(),
static_cast<double>(h), harg->getMax());
1148bool Camera::isStreamingEnabled()
1150 if (HasVideoStream ==
false || !streamWindow)
1153 return streamWindow->isStreamEnabled();
1156bool Camera::setSERNameDirectory(
const QString &filename,
const QString &directory)
1158 auto tvp =
getText(
"RECORD_FILE");
1163 auto filenameT = tvp->findWidgetByName(
"RECORD_FILE_NAME");
1164 auto dirT = tvp->findWidgetByName(
"RECORD_FILE_DIR");
1166 if (!filenameT || !dirT)
1177bool Camera::getSERNameDirectory(
QString &filename,
QString &directory)
1179 auto tvp =
getText(
"RECORD_FILE");
1184 auto filenameT = tvp->findWidgetByName(
"RECORD_FILE_NAME");
1185 auto dirT = tvp->findWidgetByName(
"RECORD_FILE_DIR");
1187 if (!filenameT || !dirT)
1190 filename =
QString(filenameT->getText());
1191 directory =
QString(dirT->getText());
1196bool Camera::startRecording()
1203 auto recordON = svp->findWidgetByName(
"RECORD_ON");
1208 if (recordON->getState() == ISS_ON)
1212 recordON->setState(ISS_ON);
1219bool Camera::startDurationRecording(
double duration)
1221 auto nvp = getNumber(
"RECORD_OPTIONS");
1226 auto durationN = nvp->findWidgetByName(
"RECORD_DURATION");
1236 auto recordON = svp->findWidgetByName(
"RECORD_DURATION_ON");
1241 if (recordON->getState() == ISS_ON)
1244 durationN->setValue(duration);
1248 recordON->setState(ISS_ON);
1255bool Camera::startFramesRecording(uint32_t frames)
1257 auto nvp = getNumber(
"RECORD_OPTIONS");
1262 auto frameN = nvp->findWidgetByName(
"RECORD_FRAME_TOTAL");
1265 if (!frameN || !svp)
1268 auto recordON = svp->findWidgetByName(
"RECORD_FRAME_ON");
1273 if (recordON->getState() == ISS_ON)
1276 frameN->setValue(frames);
1280 recordON->setState(ISS_ON);
1287bool Camera::stopRecording()
1294 auto recordOFF = svp->findWidgetByName(
"RECORD_OFF");
1300 if (recordOFF->getState() == ISS_ON)
1304 recordOFF->setState(ISS_ON);
1313 auto tvp =
getText(
"FITS_HEADER");
1316 if (!tvp || tvp->count() < 3)
1319 for (
auto &record : values)
1321 tvp->at(0)->setText(record.key.toLatin1().constData());
1322 tvp->at(1)->setText(record.value.toString().toLatin1().constData());
1323 tvp->at(2)->setText(record.comment.toLatin1().constData());
1331bool Camera::setGain(
double value)
1336 gainN->value = value;
1341bool Camera::getGain(
double *value)
1346 *value = gainN->value;
1351bool Camera::getGainMinMaxStep(
double *min,
double *max,
double *step)
1358 *step = gainN->step;
1363bool Camera::setOffset(
double value)
1368 offsetN->value = value;
1373bool Camera::getOffset(
double *value)
1378 *value = offsetN->value;
1383bool Camera::getOffsetMinMaxStep(
double *min,
double *max,
double *step)
1388 *min = offsetN->min;
1389 *max = offsetN->max;
1390 *step = offsetN->step;
1395bool Camera::isBLOBEnabled()
1397 return (m_Parent->getClientManager()->isBLOBEnabled(getDeviceName(),
"CCD1"));
1400bool Camera::setBLOBEnabled(
bool enable,
const QString &prop)
1402 m_Parent->getClientManager()->setBLOBEnabled(enable, getDeviceName(), prop);
1407bool Camera::setFastExposureEnabled(
bool enable)
1410 m_FastExposureEnabled = enable;
1412 auto svp =
getSwitch(
"CCD_FAST_TOGGLE");
1417 svp->at(0)->setState(enable ? ISS_ON : ISS_OFF);
1418 svp->at(1)->setState(enable ? ISS_OFF : ISS_ON);
1424bool Camera::setCaptureFormat(
const QString &format)
1426 auto svp =
getSwitch(
"CCD_CAPTURE_FORMAT");
1430 for (
auto &oneSwitch : *svp)
1431 oneSwitch.setState(oneSwitch.label == format ? ISS_ON : ISS_OFF);
1437bool Camera::setFastCount(uint32_t count)
1439 auto nvp = getNumber(
"CCD_FAST_COUNT");
1444 nvp->at(0)->setValue(count);
1451bool Camera::setStreamExposure(
double duration)
1453 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1458 nvp->at(0)->setValue(duration);
1465bool Camera::getStreamExposure(
double *duration)
1467 auto nvp = getNumber(
"STREAMING_EXPOSURE");
1472 *duration = nvp->at(0)->getValue();
1477bool Camera::isCoolerOn()
1484 return (svp->at(0)->getState() == ISS_ON);
1487bool Camera::getTemperatureRegulation(
double &ramp,
double &threshold)
1489 auto regulation = getProperty(
"CCD_TEMP_RAMP");
1490 if (!regulation.isValid())
1493 ramp = regulation.getNumber()->at(0)->getValue();
1494 threshold = regulation.getNumber()->at(1)->getValue();
1498bool Camera::setTemperatureRegulation(
double ramp,
double threshold)
1500 auto regulation = getProperty(
"CCD_TEMP_RAMP");
1501 if (!regulation.isValid())
1504 regulation.getNumber()->at(0)->setValue(ramp);
1505 regulation.getNumber()->at(1)->setValue(threshold);
1510bool Camera::setScopeInfo(
double focalLength,
double aperture)
1512 auto scopeInfo = getProperty(
"SCOPE_INFO");
1513 if (!scopeInfo.isValid())
1516 auto nvp = scopeInfo.getNumber();
1517 nvp->at(0)->setValue(focalLength);
1518 nvp->at(1)->setValue(aperture);
1524bool Camera::WriteImageFileInternal(
const QString &filename,
char *buffer,
const size_t size)
1526 QFile file(filename);
1529 qCCritical(KSTARS_INDI) <<
"ISD:CCD Error: Unable to open write file: " <<
1536 for (
size_t nr = 0; nr < size; nr += n)
1538 n = out.writeRawData(buffer + nr, size - nr);
1545 ok = file.flush() &&
ok;
1554QString Camera::getCaptureFormat()
const
1556 if (m_CaptureFormatIndex < 0 || m_CaptureFormats.
isEmpty() || m_CaptureFormatIndex >= m_CaptureFormats.
size())
1559 return m_CaptureFormats[m_CaptureFormatIndex];
@ ERROR_LOAD
Saving to disk error.
bool saveCurrentImage(QString &filename)
saveCurrentImage save the image that is currently in the image data buffer
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
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()
bool isRunning() const const
qsizetype count() const const
bool isEmpty() const const
qsizetype size() 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
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)