1 /*
2     SPDX-FileCopyrightText: 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "../guideinterface.h"
10 #include "fitsviewer/fitsview.h"
11 
12 #include <QAbstractSocket>
13 #include <QJsonArray>
14 #include <QJsonObject>
15 #include <QPointer>
16 #include <QTimer>
17 
18 class QTcpSocket;
19 
20 namespace Ekos
21 {
22 /**
23  * @class  PHD2
24  * Uses external PHD2 for guiding.
25  *
26  * @author Jasem Mutlaq
27  * @version 1.1
28  */
29 class PHD2 : public GuideInterface
30 {
31         Q_OBJECT
32 
33     public:
34         enum PHD2Event
35         {
36             Version,
37             LockPositionSet,
38             Calibrating,
39             CalibrationComplete,
40             StarSelected,
41             StartGuiding,
42             Paused,
43             StartCalibration,
44             AppState,
45             CalibrationFailed,
46             CalibrationDataFlipped,
47             LoopingExposures,
48             LoopingExposuresStopped,
49             SettleBegin,
50             Settling,
51             SettleDone,
52             StarLost,
53             GuidingStopped,
54             Resumed,
55             GuideStep,
56             GuidingDithered,
57             LockPositionLost,
58             Alert,
59             GuideParamChange,
60             ConfigurationChange
61 
62         };
63         enum PHD2State
64         {
65             // these are the states exposed by phd2
66             STOPPED,
67             SELECTED,
68             CALIBRATING,
69             GUIDING,
70             LOSTLOCK,
71             PAUSED,
72             LOOPING,
73         };
74         enum PHD2Connection
75         {
76             DISCONNECTED,
77             CONNECTED,
78             EQUIPMENT_DISCONNECTED,
79             EQUIPMENT_CONNECTED,
80             CONNECTING,
81             DISCONNECTING,
82         };
83         enum PHD2MessageType
84         {
85             PHD2_UNKNOWN,
86             PHD2_RESULT,
87             PHD2_EVENT,
88             PHD2_ERROR,
89         };
90 
91         // These are the PHD2 Results and the commands they are associated with
92         enum PHD2ResultType
93         {
94             NO_RESULT,
95             CAPTURE_SINGLE_FRAME,                   //capture_single_frame
96             CLEAR_CALIBRATION_COMMAND_RECEIVED,     //clear_calibration
97             DITHER_COMMAND_RECEIVED,                //dither
98             //find_star
99             //flip_calibration
100             //get_algo_param_names
101             //get_algo_param
102             APP_STATE_RECEIVED,                     //get_app_state
103             //get_calibrated
104             //get_calibration_data
105             IS_EQUIPMENT_CONNECTED,                 //get_connected
106             //get_cooler_status
107             GET_CURRENT_EQUIPMENT,                  //get_current_equipment
108             DEC_GUIDE_MODE,                         //get_dec_guide_mode
109             EXPOSURE_TIME,                          //get_exposure
110             EXPOSURE_DURATIONS,                     //get_exposure_durations
111             LOCK_POSITION,                          //get_lock_position
112             //get_lock_shift_enabled
113             //get_lock_shift_params
114             //get_paused
115             PIXEL_SCALE,                            //get_pixel_scale
116             //get_profile
117             //get_profiles
118             //get_search_region
119             //get_sensor_temperature
120             STAR_IMAGE,                             //get_star_image
121             //get_use_subframes
122             GUIDE_COMMAND_RECEIVED,                 //guide
123             //guide_pulse
124             LOOP,                                   //loop
125             //save_image
126             //set_algo_param
127             CONNECTION_RESULT,                      //set_connected
128             SET_DEC_GUIDE_MODE_COMMAND_RECEIVED,    //set_dec_guide_mode
129             SET_EXPOSURE_COMMAND_RECEIVED,          //set_exposure
130             SET_LOCK_POSITION,                      //set_lock_position
131             //set_lock_shift_enabled
132             //set_lock_shift_params
133             SET_PAUSED_COMMAND_RECEIVED,            //set_paused
134             //set_profile
135             //shutdown
136             STOP_CAPTURE_COMMAND_RECEIVED           //stop_capture
137         };
138 
139         PHD2();
140         ~PHD2();
141 
142         //These are the connection methods to connect the external guide program PHD2
143         bool Connect() override;
144         bool Disconnect() override;
isConnected()145         bool isConnected() override
146         {
147             return (connection == CONNECTED || connection == EQUIPMENT_CONNECTED);
148         }
149 
150         //These are the PHD2 Methods.  Only some are implemented in Ekos.
151 
152         void captureSingleFrame();              //capture_single_frame
153         bool clearCalibration() override;       //clear_calibration
154         bool dither(double pixels) override;    //dither
155         //find_star
156         //flip_calibration
157         //get_algo_param_names
158         //get_algo_param
159         void requestAppState();                //get_app_state
160         //get_calibrated
161         //get_calibration_data
162         void checkIfEquipmentConnected();       //get_connected
163         //get_cooler_status
164         void requestCurrentEquipmentUpdate();     //get_current_equipment
165         void checkDEGuideMode();                //get_dec_guide_mode
166         void requestExposureTime();             //get_exposure
167         void requestExposureDurations();        //get_exposure_durations
168         void requestLockPosition();             //get_lock_position
169         //get_lock_shift_enabled
170         //get_lock_shift_params
171         //get_paused
172         void requestPixelScale();               //get_pixel_scale
173         //get_profile
174         //get_profiles
175         //get_search_region
176         //get_sensor_temperature
177         void requestStarImage(int size);        //get_star_image
178         //get_use_subframes
179         bool guide() override;                  //guide
180         //guide_pulse
181         void loop();                            //loop
182         //save_image
183         //set_algo_param
184         void connectEquipment(bool enable);//set_connected
185         void requestSetDEGuideMode(bool deEnabled, bool nEnabled, bool sEnabled);           //set_dec_guide_mode
186         void requestSetExposureTime(int time);  //set_exposure
187         void setLockPosition(double x, double y); //set_lock_position
188         //set_lock_shift_enabled
189         //set_lock_shift_params
190         bool suspend() override;                //set_paused
191         bool resume() override;                 //set_paused
192         //set_profile
193         //shutdown
194         bool abort() override;                  //stop_capture
195 
196         bool calibrate() override; //Note PHD2 does not have a separate calibrate command.  This is unused.
197         void setGuideView(FITSView *guideView);
198 
getCurrentCamera()199         QString getCurrentCamera()
200         {
201             return currentCamera;
202         }
getCurrentMount()203         QString getCurrentMount()
204         {
205             return currentMount;
206         }
getCurrentAuxMount()207         QString getCurrentAuxMount()
208         {
209             return currentAuxMount;
210         }
211 
isCurrentCameraNotInEkos()212         bool isCurrentCameraNotInEkos()
213         {
214             return currentCameraIsNotInEkos;
215         }
setCurrentCameraIsNotInEkos(bool enable)216         void setCurrentCameraIsNotInEkos(bool enable)
217         {
218             currentCameraIsNotInEkos = enable;
219         }
220 
221     private slots:
222 
223         void readPHD2();
224         void displayError(QAbstractSocket::SocketError socketError);
225 
226     private:
227         QPointer<FITSView> guideFrame;
228 
229         QVector<QPointF> errorLog;
230 
231         void sendPHD2Request(const QString &method, const QJsonArray &args = QJsonArray());
232         void sendRpcCall(QJsonObject &call, PHD2ResultType resultType);
233         void sendNextRpcCall();
234 
235         void processPHD2Event(const QJsonObject &jsonEvent, const QByteArray &rawResult);
236         void processPHD2Result(const QJsonObject &jsonObj, const QByteArray &rawResult);
237         void processStarImage(const QJsonObject &jsonStarFrame);
238         void processPHD2State(const QString &phd2State);
239         void handlePHD2AppState(PHD2State state);
240         void processPHD2Error(const QJsonObject &jsonError, const QByteArray &rawResult);
241 
242         PHD2ResultType takeRequestFromList(const QJsonObject &response);
243 
244         QPointer<QTcpSocket> tcpSocket;
245         int nextRpcId { 1 };
246 
247         QHash<QString, PHD2Event> events;                     // maps event name to event type
248         QHash<QString, PHD2ResultType> methodResults;         // maps method name to result type
249 
250         int pendingRpcId;                         // ID of outstanding RPC call
251         PHD2ResultType pendingRpcResultType { NO_RESULT };      // result type of outstanding RPC call
252         bool starImageRequested { false };        // true when there is an outstanding star image request
253 
254         struct RpcCall
255         {
256             QJsonObject call;
257             PHD2ResultType resultType;
258             RpcCall() = default;
RpcCallRpcCall259             RpcCall(const QJsonObject &call_, PHD2ResultType resultType_) : call(call_), resultType(resultType_) { }
260         };
261         QVector<RpcCall> rpcRequestQueue;
262 
263         PHD2State state { STOPPED };
264         bool isDitherActive { false };
265         bool isSettling { false };
266         PHD2Connection connection { DISCONNECTED };
267         PHD2Event event { Alert };
268         uint8_t setConnectedRetries { 0 };
269 
270         void setEquipmentConnected();
271         void updateGuideParameters();
272         void ResetConnectionState();
273 
274         QTimer *abortTimer;
275         QTimer *ditherTimer;
276         QTimer *stateTimer;
277 
278         double pixelScale = 0;
279 
280         QString logValidExposureTimes;
281 
282         QString currentCamera;
283         QString currentMount;
284         QString currentAuxMount;
285         bool currentCameraIsNotInEkos;
286 
287         uint8_t m_PHD2ReconnectCounter {0};
288 
289         // Wait this many milliseconds before trying to reconnect again to PHD2
290         static const uint32_t PHD2_RECONNECT_TIMEOUT {3000};
291         // Try to connect this many times before giving up.
292         static const uint8_t PHD2_RECONNECT_THRESHOLD {10};
293 
294 };
295 
296 }
297