1 /*
2     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "indistd.h"
10 #include "wsmedia.h"
11 #include "auxiliary/imageviewer.h"
12 #include "fitsviewer/fitscommon.h"
13 #include "fitsviewer/fitsview.h"
14 #include "fitsviewer/fitsviewer.h"
15 #include "ekos/capture/placeholderpath.h"
16 
17 #include <QStringList>
18 #include <QPointer>
19 #include <QtConcurrent>
20 
21 #include <memory>
22 
23 class FITSData;
24 class FITSView;
25 class QTimer;
26 class StreamWG;
27 
28 /**
29  * \namespace ISD
30  *
31  *  ISD is a collection of INDI Standard Devices. It encapsulates common types of INDI devices such as telescopes and CCDs.
32  *
33  */
34 namespace ISD
35 {
36 class CCD;
37 
38 /**
39  * @class CCDChip
40  * CCDChip class controls a particular chip in CCD device. While most amateur CCDs only have a single chip on the CCD, some
41  * CCDs have additional chips targetted for guiding purposes.
42  */
43 class CCDChip
44 {
45     public:
46         typedef enum { PRIMARY_CCD, GUIDE_CCD } ChipType;
47 
48         CCDChip(ISD::CCD *ccd, ChipType cType);
49 
50         FITSView *getImageView(FITSMode imageType);
51         void setImageView(FITSView *image, FITSMode imageType);
setCaptureMode(FITSMode mode)52         void setCaptureMode(FITSMode mode)
53         {
54             captureMode = mode;
55         }
setCaptureFilter(FITSScale fType)56         void setCaptureFilter(FITSScale fType)
57         {
58             captureFilter = fType;
59         }
60 
61         // Common commands
62         bool getFrame(int *x, int *y, int *w, int *h);
63         bool getFrameMinMax(int *minX, int *maxX, int *minY, int *maxY, int *minW, int *maxW, int *minH, int *maxH);
64         bool setFrame(int x, int y, int w, int h, bool force = false);
65 
66         bool resetFrame();
67         bool capture(double exposure);
68         bool setFrameType(CCDFrameType fType);
69         bool setFrameType(const QString &name);
70         CCDFrameType getFrameType();
71         bool setBinning(int bin_x, int bin_y);
72         bool setBinning(CCDBinType binType);
73         CCDBinType getBinning();
74         bool getBinning(int *bin_x, int *bin_y);
75         bool getMaxBin(int *max_xbin, int *max_ybin);
getType()76         ChipType getType() const
77         {
78             return type;
79         }
getCCD()80         ISD::CCD *getCCD()
81         {
82             return parentCCD;
83         }
84 
85         // Set Image Info
86         bool setImageInfo(uint16_t width, uint16_t height, double pixelX, double pixelY, uint8_t bitdepth);
87         // Get Image Info
88         bool getImageInfo(uint16_t &width, uint16_t &height, double &pixelX, double &pixelY, uint8_t &bitdepth);
89         // Bayer Info
90         bool getBayerInfo(uint16_t &offsetX, uint16_t &offsetY, QString &pattern);
91 
92         bool isCapturing();
93         bool abortExposure();
94 
getCaptureMode()95         FITSMode getCaptureMode() const
96         {
97             return captureMode;
98         }
getCaptureFilter()99         FITSScale getCaptureFilter() const
100         {
101             return captureFilter;
102         }
isBatchMode()103         bool isBatchMode() const
104         {
105             return batchMode;
106         }
setBatchMode(bool enable)107         void setBatchMode(bool enable)
108         {
109             batchMode = enable;
110         }
getFrameTypes()111         QStringList getFrameTypes() const
112         {
113             return frameTypes;
114         }
addFrameLabel(const QString & label)115         void addFrameLabel(const QString &label)
116         {
117             frameTypes << label;
118         }
clearFrameTypes()119         void clearFrameTypes()
120         {
121             frameTypes.clear();
122         }
123 
124         bool canBin() const;
125         void setCanBin(bool value);
126 
127         bool canSubframe() const;
128         void setCanSubframe(bool value);
129 
130         bool canAbort() const;
131         void setCanAbort(bool value);
132 
133         const QSharedPointer<FITSData> &getImageData() const;
setImageData(const QSharedPointer<FITSData> & data)134         void setImageData(const QSharedPointer<FITSData> &data)
135         {
136             imageData = data;
137         }
138 
139         int getISOIndex() const;
140         bool setISOIndex(int value);
141 
142         QStringList getISOList() const;
143 
144     private:
145         QPointer<FITSView> normalImage, focusImage, guideImage, calibrationImage, alignImage;
146         QSharedPointer<FITSData> imageData { nullptr };
147         FITSMode captureMode { FITS_NORMAL };
148         FITSScale captureFilter { FITS_NONE };
149         INDI::BaseDevice *baseDevice { nullptr };
150         ClientManager *clientManager { nullptr };
151         ChipType type;
152         bool batchMode { false };
153         QStringList frameTypes;
154         bool CanBin { false };
155         bool CanSubframe { false };
156         bool CanAbort { false };
157         ISD::CCD *parentCCD { nullptr };
158 };
159 
160 /**
161  * @class CCD
162  * CCD class controls an INDI CCD device. It can be used to issue and abort capture commands, receive and process BLOBs,
163  * and return information on the capabilities of the CCD.
164  *
165  * @author Jasem Mutlaq
166  */
167 class CCD : public DeviceDecorator
168 {
169         Q_OBJECT
170 
171     public:
172         explicit CCD(GDInterface *iPtr);
173         virtual ~CCD() override;
174 
175         typedef enum { UPLOAD_CLIENT, UPLOAD_LOCAL, UPLOAD_BOTH } UploadMode;
176         typedef enum { FORMAT_FITS, FORMAT_NATIVE } TransferFormat;
177         enum BlobType
178         {
179             BLOB_IMAGE,
180             BLOB_FITS,
181             BLOB_RAW,
182             BLOB_OTHER
183         } BType;
184         typedef enum { TELESCOPE_PRIMARY, TELESCOPE_GUIDE, TELESCOPE_UNKNOWN } TelescopeType;
185         typedef enum
186         {
187             ERROR_CAPTURE,              /** INDI Camera error */
188             ERROR_SAVE,                 /** Saving to disk error */
189             ERROR_LOAD,                 /** Loading image buffer error */
190             ERROR_VIEWER                /** Loading in FITS Viewer Error */
191         } ErrorType;
192 
193         void registerProperty(INDI::Property prop) override;
194         void removeProperty(const QString &name) override;
195         void processSwitch(ISwitchVectorProperty *svp) override;
196         void processText(ITextVectorProperty *tvp) override;
197         void processNumber(INumberVectorProperty *nvp) override;
198         void processLight(ILightVectorProperty *lvp) override;
199         void processBLOB(IBLOB *bp) override;
200 
getType()201         DeviceFamily getType() override
202         {
203             return dType;
204         }
205 
206         // Does it an on-chip dedicated guide head?
207         bool hasGuideHead();
208         // Does it report temperature?
209         bool hasCooler();
210         // Can temperature be controlled?
canCool()211         bool canCool()
212         {
213             return CanCool;
214         }
215         // Does it have active cooler on/off controls?
216         bool hasCoolerControl();
217         bool setCoolerControl(bool enable);
218         bool isCoolerOn();
219         // Does it have a video stream?
hasVideoStream()220         bool hasVideoStream()
221         {
222             return HasVideoStream;
223         }
224 
225         // Temperature controls
226         bool getTemperature(double *value);
227         bool setTemperature(double value);
228 
229         // Temperature Regulation
230         bool getTemperatureRegulation(double &ramp, double &threshold);
231         bool setTemperatureRegulation(double ramp, double threshold);
232 
233         // Utility functions
setISOMode(bool enable)234         void setISOMode(bool enable)
235         {
236             ISOMode = enable;
237         }
setSeqPrefix(const QString & preFix)238         void setSeqPrefix(const QString &preFix)
239         {
240             seqPrefix = preFix;
241         }
setPlaceholderPath(Ekos::PlaceholderPath php)242         void setPlaceholderPath(Ekos::PlaceholderPath php)
243         {
244             placeholderPath = php;
245         }
setNextSequenceID(int count)246         void setNextSequenceID(int count)
247         {
248             nextSequenceID = count;
249         }
250 
251         // Gain controls
hasGain()252         bool hasGain()
253         {
254             return gainN != nullptr;
255         }
256         bool getGain(double *value);
getGainPermission()257         IPerm getGainPermission() const
258         {
259             return gainPerm;
260         }
261         bool setGain(double value);
262         bool getGainMinMaxStep(double *min, double *max, double *step);
263 
264         // offset controls
hasOffset()265         bool hasOffset()
266         {
267             return offsetN != nullptr;
268         }
269         bool getOffset(double *value);
getOffsetPermission()270         IPerm getOffsetPermission() const
271         {
272             return offsetPerm;
273         }
274         bool setOffset(double value);
275         bool getOffsetMinMaxStep(double *min, double *max, double *step);
276 
277         // Rapid Guide
278         bool configureRapidGuide(CCDChip *targetChip, bool autoLoop, bool sendImage = false, bool showMarker = false);
279         bool setRapidGuide(CCDChip *targetChip, bool enable);
280 
281         // Upload Settings
282         void updateUploadSettings(const QString &remoteDir);
283         UploadMode getUploadMode();
284         bool setUploadMode(UploadMode mode);
285 
286         // Transfer Format
getTransferFormat()287         TransferFormat getTransferFormat()
288         {
289             return transferFormat;
290         }
291         bool setTransformFormat(CCD::TransferFormat format);
292 
293         // BLOB control
294         bool isBLOBEnabled();
295         bool setBLOBEnabled(bool enable, const QString &prop = QString());
296 
297         // Video Stream
298         bool setVideoStreamEnabled(bool enable);
299         bool resetStreamingFrame();
300         bool setStreamingFrame(int x, int y, int w, int h);
301         bool isStreamingEnabled();
302         bool setStreamExposure(double duration);
303         bool getStreamExposure(double *duration);
304         bool setStreamLimits(uint16_t maxBufferSize, uint16_t maxPreviewFPS);
305 
306         // Video Recording
307         bool setSERNameDirectory(const QString &filename, const QString &directory);
308         bool getSERNameDirectory(QString &filename, QString &directory);
309         bool startRecording();
310         bool startDurationRecording(double duration);
311         bool startFramesRecording(uint32_t frames);
312         bool stopRecording();
313 
314         // Telescope type
getTelescopeType()315         TelescopeType getTelescopeType()
316         {
317             return telescopeType;
318         }
319         bool setTelescopeType(TelescopeType type);
320 
321         // Update FITS Header
322         bool setFITSHeader(const QMap<QString, QString> &values);
323 
324         CCDChip *getChip(CCDChip::ChipType cType);
325 
326         TransferFormat getTargetTransferFormat() const;
327         void setTargetTransferFormat(const TransferFormat &value);
328 
329         bool setFastExposureEnabled(bool enable);
isFastExposureEnabled()330         bool isFastExposureEnabled() const
331         {
332             return m_FastExposureEnabled;
333         }
334         bool setFastCount(uint32_t count);
335 
getExposurePresets()336         const QMap<QString, double> &getExposurePresets() const
337         {
338             return m_ExposurePresets;
339         }
getExposurePresetsMinMax()340         const QPair<double, double> getExposurePresetsMinMax() const
341         {
342             return m_ExposurePresetsMinMax;
343         }
344 
345     public slots:
346         //void FITSViewerDestroyed();
347         void StreamWindowHidden();
348         // Blob manager
349         void setBLOBManager(const char *device, INDI::Property prop);
350 
351     protected slots:
352         void setWSBLOB(const QByteArray &message, const QString &extension);
353 
354     signals:
355         void newTemperatureValue(double value);
356         void newExposureValue(ISD::CCDChip *chip, double value, IPState state);
357         void newGuideStarData(ISD::CCDChip *chip, double dx, double dy, double fit);
358         void newBLOBManager(INDI::Property prop);
359         void newRemoteFile(QString);
360         void videoStreamToggled(bool enabled);
361         void videoRecordToggled(bool enabled);
362         void newFPS(double instantFPS, double averageFPS);
363         void newVideoFrame(const QSharedPointer<QImage> &frame);
364         void coolerToggled(bool enabled);
365         void ready();
366         void error(ErrorType type);
367         void newImage(const QSharedPointer<FITSData> &data);
368 
369     private:
370         void processStream(IBLOB *bp);
371         void loadImageInView(ISD::CCDChip *targetChip, const QSharedPointer<FITSData> &data);
372         bool generateFilename(bool batch_mode, const QString &extension, QString *filename);
373         // Saves an image to disk on a separate thread.
374         bool writeImageFile(const QString &filename, IBLOB *bp, bool is_fits);
375         bool WriteImageFileInternal(const QString &filename, char *buffer, const size_t size);
376         // Creates or finds the FITSViewer.
377         QPointer<FITSViewer> getFITSViewer();
378         void handleImage(CCDChip *targetChip, const QString &filename, IBLOB *bp, QSharedPointer<FITSData> data);
379 
380         bool ISOMode { true };
381         bool HasGuideHead { false };
382         bool HasCooler { false };
383         bool CanCool { false };
384         bool HasCoolerControl { false };
385         bool HasVideoStream { false };
386         bool m_FastExposureEnabled { false };
387         QString seqPrefix;
388         Ekos::PlaceholderPath placeholderPath;
389 
390         int nextSequenceID { 0 };
391         std::unique_ptr<StreamWG> streamWindow;
392         int streamW { 0 };
393         int streamH { 0 };
394         int normalTabID { -1 };
395         int calibrationTabID { -1 };
396         int focusTabID { -1 };
397         int guideTabID { -1 };
398         int alignTabID { -1 };
399 
400         //char BLOBFilename[MAXINDIFILENAME + 1];
401         IBLOB *primaryCCDBLOB { nullptr };
402 
403         std::unique_ptr<QTimer> readyTimer;
404         std::unique_ptr<CCDChip> primaryChip;
405         std::unique_ptr<CCDChip> guideChip;
406         std::unique_ptr<WSMedia> m_Media;
407         TransferFormat transferFormat { FORMAT_FITS };
408         TransferFormat targetTransferFormat { FORMAT_FITS };
409         TelescopeType telescopeType { TELESCOPE_UNKNOWN };
410 
411         // Gain, since it is spread among different vector properties, let's try to find the property itself.
412         INumber *gainN { nullptr };
413         IPerm gainPerm { IP_RO };
414 
415         INumber *offsetN { nullptr };
416         IPerm offsetPerm { IP_RO };
417 
418         QPointer<FITSViewer> m_FITSViewerWindow;
419         QPointer<ImageViewer> m_ImageViewerWindow;
420 
421         QDateTime m_LastNotificationTS;
422 
423         // Typically for DSLRs
424         QMap<QString, double> m_ExposurePresets;
425         QPair<double, double> m_ExposurePresetsMinMax;
426 
427         // Used when writing the image fits file to disk in a separate thread.
428         char *fileWriteBuffer { nullptr };
429         int fileWriteBufferSize { 0 };
430         QString fileWriteFilename;
431         QFuture<void> fileWriteThread;
432 };
433 }
434