Instrument Neutral Distributed Interface INDI 2.2.5
indi_alpaca_ccd.h
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2025 Jasem Mutlaq. All rights reserved.
4 ASCOM Alpaca Camera INDI Driver
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 The full GNU General Public License is included in this distribution in the
22 file called LICENSE.
23*******************************************************************************/
24
25#pragma once
26
27#include "indiccd.h"
28#include <string>
29#include <functional>
30#include <vector>
31#include <limits>
32#include <httplib.h>
33#include <indielapsedtimer.h>
35#include <inditimer.h>
36
37#ifdef _USE_SYSTEM_JSONLIB
38#include <nlohmann/json.hpp>
39#else
40#include <indijson.hpp>
41#endif
42
50
51class AlpacaCCD : public INDI::CCD
52{
53 public:
54 AlpacaCCD();
55 virtual ~AlpacaCCD() = default;
56
57 virtual bool initProperties() override;
58 const char *getDefaultName() override;
59 void ISGetProperties(const char *dev) override;
60 bool updateProperties() override;
61 virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override;
62 virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override;
63 virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override;
64 virtual bool saveConfigItems(FILE *fp) override;
65
66 protected:
67 bool Connect() override;
68 bool Disconnect() override;
69
70 void TimerHit() override;
71
72 virtual bool StartExposure(float duration) override;
73 virtual bool AbortExposure() override;
74 virtual int SetTemperature(double temperature) override;
75 virtual bool UpdateCCDFrame(int x, int y, int w, int h) override;
76 virtual bool UpdateCCDBin(int hor, int ver) override;
77 virtual bool SetCaptureFormat(uint8_t index) override;
78 virtual IPState GuideNorth(uint32_t ms) override;
79 virtual IPState GuideSouth(uint32_t ms) override;
80 virtual IPState GuideEast(uint32_t ms) override;
81 virtual IPState GuideWest(uint32_t ms) override;
82
83 // ImageBytes metadata structure (44 bytes) as per ASCOM Alpaca API v10 section 8.7.1
85 {
86 int32_t MetadataVersion; // Bytes 0-3: Should be 1
87 int32_t ErrorNumber; // Bytes 4-7: 0 for success
88 uint32_t ClientTransactionID; // Bytes 8-11
89 uint32_t ServerTransactionID; // Bytes 12-15
90 int32_t DataStart; // Bytes 16-19: Offset to image data
91 int32_t ImageElementType; // Bytes 20-23: Source array element type
92 int32_t TransmissionElementType;// Bytes 24-27: Network transmission type
93 int32_t Rank; // Bytes 28-31: 2 or 3 dimensions
94 int32_t Dimension1; // Bytes 32-35: Width
95 int32_t Dimension2; // Bytes 36-39: Height
96 int32_t Dimension3; // Bytes 40-43: Planes (0 for 2D)
97 } __attribute__((packed));
98
99 // Alpaca customization hooks for derived drivers.
100 virtual std::string buildAlpacaFormData(const nlohmann::json &request);
101 virtual bool parseImageBytesMetadata(ImageBytesMetadata *metadata, size_t body_size);
102 uint32_t getTransactionId();
103 void setDefaultServerAddress(const char *host, const char *port, bool force = false);
104
105 private:
106 // Config-loaded values (empty = no saved config, mirrors TCP plugin pattern)
107 std::string m_ConfigHost;
108 std::string m_ConfigPort;
109
110 // Internal state variables
111 bool m_ExposureInProgress {false};
112 std::string m_CurrentReadoutModeName {"0"}; // Default to mode 0
113 int m_CurrentReadoutModeIndex {0};
114 uint32_t m_MaxADU { 0 };
115 uint8_t m_SensorType { 0 };
116 int m_CameraXSize {1}, m_CameraYSize {1};
117 double m_PixelSizeX {1.0}, m_PixelSizeY {1.0};
118 std::string m_Description, m_DriverInfo, m_DriverVersion, m_CameraName;
119 double m_GainMin {0}, m_GainMax {0};
120 uint8_t m_BayerOffsetX {0}, m_BayerOffsetY {0};
121 double m_ElectronsPerADU {0};
122 double m_FullWellCapacity {0};
123
124 // Alpaca Communication
125 std::unique_ptr<httplib::Client> httpClient; // Declared here
126 bool sendAlpacaGET(const std::string &endpoint, nlohmann::json &response);
127 bool sendAlpacaPUT(const std::string &endpoint, const nlohmann::json &request, nlohmann::json &response);
128 std::string getAlpacaURL(const std::string &endpoint);
129 uint32_t m_ClientTransactionID {1};
130
131 // Extended image metadata for FITS headers
132 struct ImageMetadata
133 {
134 uint8_t type; // ASCOM type code
135 uint8_t rank; // Number of dimensions
136 uint32_t width; // Pixel width
137 uint32_t height; // Pixel height
138 uint32_t planes; // Color planes (0=mono)
139 uint32_t max_adu; // Maximum pixel value
140 uint8_t sensor_type; // Mono/Color/Bayer type
141 uint8_t bayer_offset_x; // Bayer pattern X offset
142 uint8_t bayer_offset_y; // Bayer pattern Y offset
143 };
144
145 ImageMetadata m_CurrentImage;
146 bool alpacaGetImageReady(); // Declared here
147 bool alpacaGetImageArrayImageBytes(uint8_t** buffer, size_t* buffer_size, ImageBytesMetadata* metadata);
148 bool alpacaGetImageArrayJSON(ImageMetadata &meta, uint8_t** buffer, size_t* buffer_size);
149 bool downloadImage();
150 bool processImageBytesData(uint8_t* buffer, size_t buffer_size, const ImageBytesMetadata &metadata);
151 bool processMonoImage(uint8_t* buffer);
152 bool processColorImage(uint8_t* buffer); // Placeholder for color image processing
153
154 // ImageBytes data conversion helpers
155 void convertImageBytesToINDI2D(uint8_t* src_buffer, uint16_t* dst_buffer, uint32_t width, uint32_t height,
156 int32_t transmission_type);
157 void convertImageBytesToINDI3D(uint8_t* src_buffer, uint16_t* dst_buffer, uint32_t width, uint32_t height, uint32_t planes,
158 int32_t transmission_type);
159
160 // Data Translation
161 void translateCoordinates(uint8_t* buffer, const ImageMetadata &meta);
162 virtual void addFITSKeywords(INDI::CCDChip * targetChip, std::vector<INDI::FITSRecord> &fitsKeywords) override;
163
164 // Worker thread for exposure handling
166 void workerExposure(const std::atomic_bool &isAboutToQuit, float duration);
167
168 void updateStatus();
169 void updateCoolerStatus();
170 void updateCameraState();
171 void updateReadoutModes();
172 void updateCameraCapabilities();
173
174 bool sendPulseGuide(ALPACA_GUIDE_DIRECTION direction, long duration);
175 std::string getSensorTypeString(uint8_t sensorType);
176
177 INDI::PropertyText ServerAddressTP {2}; // Host and port
178 INDI::PropertyNumber DeviceNumberNP {1}; // Alpaca device number
179 INDI::PropertyNumber ConnectionSettingsNP {3}; // Timeout, Retries, Retry Delay
180
181 INDI::PropertyNumber GainNP {1}; // CCD_GAIN
182 INDI::PropertyNumber OffsetNP {1}; // CCD_OFFSET
183 INDI::PropertyNumber CoolerPowerNP {1}; // Cooler power percentage
184
185 // Gain/Offset as named presets (used instead of GainNP/OffsetNP when the device
186 // reports a non-empty Gains/Offsets list rather than a Min/Max numeric range)
187 INDI::PropertySwitch GainSP {0};
188 INDI::PropertySwitch OffsetSP {0};
189 bool m_GainIsList {false};
190 bool m_OffsetIsList {false};
191
192 // Fast readout mode (only defined if the device reports canfastreadout=true)
193 INDI::PropertySwitch FastReadoutSP {2};
194 enum { FAST_READOUT_ENABLE, FAST_READOUT_DISABLE };
195 bool m_HasFastReadout {false};
196
197 INDI::PropertyText DeviceInfoTP {4}; // Description, DriverInfo, DriverVersion, Name
198
199 INDI::PropertySwitch CoolerSP {2}; // Declared here
200 INDI::PropertyText CameraStateTP {1}; // Declared here
201 INDI::PropertySwitch ReadoutModeSP {0}; // Readout mode selection
202
203 bool m_HasGain {false}; // Flag to track if device supports Gain
204 bool m_HasOffset {false}; // Flag to track if device supports Offset
205 bool m_CanPulseGuide {false}; // Flag to track if device supports pulse guiding
206 bool m_CanAbortExposure {false}; // Flag to track if device supports aborting (discarding) an exposure
207 bool m_CanStopExposure {false}; // Flag to track if device supports stopping (reading out) an exposure
208 bool m_CanAsymmetricBin {false}; // Flag to track if device supports different X/Y binning factors
209 bool m_HasCoolerPower {false}; // Flag to track if device can report cooler power
210 bool m_HasPercentCompleted {true};
211 bool m_HasLastExposureDuration {true};
212
213 // Pulse guiding state (tracks an in-progress /pulseguide command)
214 bool m_PulseGuiding {false};
215 INDI_EQ_AXIS m_PulseGuideAxis {AXIS_RA};
216
217 // Temperature and cooler monitoring
218 INDI::Timer mTimerTemperature;
219 void temperatureTimerTimeout();
220 double m_CurrentTemperature {0};
221 double m_TargetTemperature {std::numeric_limits<double>::quiet_NaN()};
222
223 static const constexpr char* CONNECTION_TAB = "Connection";
224 static constexpr int TEMP_TIMER_MS = 10000;
225 // Differential temperature threshold (C)
226 static constexpr double TEMP_THRESHOLD = 0.25;
227};
double temperature
virtual bool SetCaptureFormat(uint8_t index) override
SetCaptureFormat Set Active Capture format.
virtual bool UpdateCCDFrame(int x, int y, int w, int h) override
CCD calls this function when CCD Frame dimension needs to be updated in the hardware....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool AbortExposure() override
Abort ongoing exposure.
const char * getDefaultName() override
virtual IPState GuideNorth(uint32_t ms) override
Guide northward for ms milliseconds.
virtual IPState GuideEast(uint32_t ms) override
Guide easward for ms milliseconds.
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
uint32_t getTransactionId()
void setDefaultServerAddress(const char *host, const char *port, bool force=false)
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool parseImageBytesMetadata(ImageBytesMetadata *metadata, size_t body_size)
virtual int SetTemperature(double temperature) override
Set CCD temperature.
virtual bool StartExposure(float duration) override
Start exposing primary CCD chip.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual IPState GuideSouth(uint32_t ms) override
Guide southward for ms milliseconds.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual ~AlpacaCCD()=default
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool UpdateCCDBin(int hor, int ver) override
CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should ...
bool Disconnect() override
Disconnect from device.
virtual std::string buildAlpacaFormData(const nlohmann::json &request)
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save configuration items in XML file.
virtual IPState GuideWest(uint32_t ms) override
Guide westward for ms milliseconds.
The CCDChip class provides functionality of a CCD Chip within a CCD.
Definition indiccdchip.h:39
Class to provide general functionality of CCD cameras with a single CCD sensor, or a primary CCD sens...
Definition indiccd.h:108
The Timer class provides repetitive and single-shot timers.
Definition inditimer.h:41
a class to store JSON values
ALPACA_GUIDE_DIRECTION
@ ALPACA_GUIDE_SOUTH
@ ALPACA_GUIDE_WEST
@ ALPACA_GUIDE_EAST
@ ALPACA_GUIDE_NORTH
ISState
Switch state.
Definition indiapi.h:148
IPState
Property state.
Definition indiapi.h:158
INDI_EQ_AXIS
@ AXIS_RA
uint16_t type
Definition pwc-ioctl.h:0