Kstars

linguider.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "linguider.h"
8
9#include "Options.h"
10
11#include <KLocalizedString>
12#include <KMessageBox>
13
14#include <QNetworkReply>
15
16namespace Ekos
17{
18LinGuider::LinGuider()
19{
20 tcpSocket = new QTcpSocket(this);
21
22 rawBuffer.clear();
23
24 connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readLinGuider()));
25 connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
26 SLOT(displayError(QAbstractSocket::SocketError)));
27
28 connect(tcpSocket, SIGNAL(connected()), this, SLOT(onConnected()));
29
30 deviationTimer.setInterval(1000);
31 connect(&deviationTimer, &QTimer::timeout, this, [&]()
32 {
33 sendCommand(GET_RA_DEC_DRIFT);
34 });
35}
36
37bool LinGuider::Connect()
38{
39 if (connection == DISCONNECTED)
40 {
41 rawBuffer.clear();
42 connection = CONNECTING;
43 tcpSocket->connectToHost(Options::linGuiderHost(), Options::linGuiderPort());
44 }
45 // Already connected, let's connect equipment
46 else
47 emit newStatus(GUIDE_CONNECTED);
48
49 return true;
50}
51
52bool LinGuider::Disconnect()
53{
54 rawBuffer.clear();
55 connection = DISCONNECTED;
56 tcpSocket->disconnectFromHost();
57
58 emit newStatus(GUIDE_DISCONNECTED);
59
60 return true;
61}
62
63void LinGuider::displayError(QAbstractSocket::SocketError socketError)
64{
65 switch (socketError)
66 {
68 break;
70 emit newLog(i18n("The host was not found. Please check the host name and port settings in Guide options."));
71 emit newStatus(GUIDE_DISCONNECTED);
72 break;
74 emit newLog(i18n("The connection was refused by the peer. Make sure the LinGuider is running, and check "
75 "that the host name and port settings are correct."));
76 emit newStatus(GUIDE_DISCONNECTED);
77 break;
78 default:
79 emit newLog(i18n("The following error occurred: %1.", tcpSocket->errorString()));
80 }
81
82 connection = DISCONNECTED;
83}
84
85void LinGuider::readLinGuider()
86{
87 while (tcpSocket->atEnd() == false)
88 {
89 rawBuffer += tcpSocket->readAll();
90
91 while (1)
92 {
93 if (rawBuffer.size() < 8)
94 break;
95
96 if (Options::guideLogging())
97 qDebug() << Q_FUNC_INFO << "Guide:" << rawBuffer;
98
99 qint16 magicNumber = *(reinterpret_cast<qint16 *>(rawBuffer.data()));
100 if (magicNumber != 0x02)
101 {
102 emit newLog(i18n("Invalid response."));
103 rawBuffer = rawBuffer.mid(1);
104 continue;
105 }
106
107 qint16 command = *(reinterpret_cast<qint16 *>(rawBuffer.data() + 2));
108 if (command < GET_VER || command > GET_RA_DEC_DRIFT)
109 {
110 emit newLog(i18n("Invalid response."));
111 rawBuffer = rawBuffer.mid(1);
112 continue;
113 }
114
115 qint16 datalen = *(reinterpret_cast<qint16 *>(rawBuffer.data() + 4));
116 if (rawBuffer.size() < datalen + 8)
117 break;
118
119 QString reply = rawBuffer.mid(8, datalen);
120 processResponse(static_cast<LinGuiderCommand>(command), reply);
121 rawBuffer = rawBuffer.mid(8 + datalen);
122 }
123 }
124}
125
126void LinGuider::processResponse(LinGuiderCommand command, const QString &reply)
127{
128 if (reply == "Error: Guiding not started.")
129 {
130 state = IDLE;
131 emit newStatus(GUIDE_ABORTED);
132 deviationTimer.stop();
133 return;
134 }
135
136 switch (command)
137 {
138 case GET_VER:
139 emit newLog(i18n("Connected to LinGuider %1", reply));
140 if (reply < "v.4.1.0")
141 {
142 emit newLog(
143 i18n("Only LinGuider v4.1.0 or higher is supported. Please upgrade LinGuider and try again."));
144 Disconnect();
145 }
146
147 sendCommand(GET_GUIDER_STATE);
148 break;
149
150 case GET_GUIDER_STATE:
151 if (reply == "GUIDING")
152 {
153 state = GUIDING;
154 emit newStatus(GUIDE_GUIDING);
155 deviationTimer.start();
156 }
157 else
158 {
159 state = IDLE;
160 deviationTimer.stop();
161 }
162 break;
163
164 case FIND_STAR:
165 {
166 emit newLog(i18n("Auto star selected %1", reply));
167 QStringList pos = reply.split(' ');
168 if (pos.count() == 2)
169 {
170 starCenter = reply;
171 sendCommand(SET_GUIDER_RETICLE_POS, reply);
172 }
173 else
174 {
175 emit newLog(i18n("Failed to process star position."));
176 emit newStatus(GUIDE_CALIBRATION_ERROR);
177 }
178 }
179 break;
180
181 case SET_GUIDER_RETICLE_POS:
182 if (reply == "OK")
183 {
184 sendCommand(SET_GUIDER_SQUARE_POS, starCenter);
185 }
186 else
187 {
188 emit newLog(i18n("Failed to set guider reticle position."));
189 emit newStatus(GUIDE_CALIBRATION_ERROR);
190 }
191 break;
192
193 case SET_GUIDER_SQUARE_POS:
194 if (reply == "OK")
195 {
196 emit newStatus(GUIDE_CALIBRATION_SUCCESS);
197 }
198 else
199 {
200 emit newLog(i18n("Failed to set guider square position."));
201 emit newStatus(GUIDE_CALIBRATION_ERROR);
202 }
203 break;
204
205 case GUIDER:
206 if (reply == "OK")
207 {
208 if (state == IDLE)
209 {
210 emit newStatus(GUIDE_GUIDING);
211 state = GUIDING;
212
213 deviationTimer.start();
214 }
215 else
216 {
217 emit newStatus(GUIDE_IDLE);
218 state = IDLE;
219
220 deviationTimer.stop();
221 }
222 }
223 else
224 {
225 if (state == IDLE)
226 emit newLog(i18n("Failed to start guider."));
227 else
228 emit newLog(i18n("Failed to stop guider."));
229 }
230 break;
231
232 case GET_RA_DEC_DRIFT:
233 {
234 if (state != GUIDING)
235 {
236 state = GUIDING;
237 emit newStatus(GUIDE_GUIDING);
238 }
239
240 QStringList pos = reply.split(' ');
241 if (pos.count() == 2)
242 {
243 bool raOK = false, deOK = false;
244
245 double raDev = pos[0].toDouble(&raOK);
246 double deDev = pos[1].toDouble(&deOK);
247
248 if (raOK && deOK)
249 emit newAxisDelta(raDev, deDev);
250 }
251 else
252 {
253 emit newLog(i18n("Failed to get RA/DEC Drift."));
254 }
255 }
256 break;
257
258 case SET_DITHERING_RANGE:
259 if (reply == "OK")
260 {
261 sendCommand(DITHER);
262
263 deviationTimer.stop();
264 }
265 else
266 {
267 emit newLog(i18n("Failed to set dither range."));
268 }
269 break;
270
271 case DITHER:
272 if (reply == "Long time cmd finished")
273 emit newStatus(GUIDE_DITHERING_SUCCESS);
274 else
275 emit newStatus(GUIDE_DITHERING_ERROR);
276
277 state = GUIDING;
278 deviationTimer.start();
279 break;
280
281 default:
282 break;
283 }
284}
285
286void LinGuider::onConnected()
287{
288 connection = CONNECTED;
289
290 emit newStatus(GUIDE_CONNECTED);
291 // Get version
292
293 sendCommand(GET_VER);
294}
295
296void LinGuider::sendCommand(LinGuiderCommand command, const QString &args)
297{
298 // Command format: Magic Number (0x00 0x02), cmd (2 bytes), len_of_param (4 bytes), param (ascii)
299
300 int size = 8 + args.size();
301
302 QByteArray cmd(size, 0);
303
304 // Magic number
305 cmd[0] = 0x02;
306 cmd[1] = 0x00;
307
308 // Command
309 cmd[2] = command;
310 cmd[3] = 0x00;
311
312 // Len
313 qint32 len = args.size();
314 memcpy(cmd.data() + 4, &len, 4);
315
316 // Params
317 if (args.isEmpty() == false)
318 memcpy(cmd.data() + 8, args.toLatin1().data(), args.size());
319
320 tcpSocket->write(cmd);
321}
322
323bool LinGuider::calibrate()
324{
325 // Let's start calibration. It is already calibrated but in this step we auto-select and star and set the square
326 emit newStatus(Ekos::GUIDE_CALIBRATING);
327
328 sendCommand(FIND_STAR);
329
330 return true;
331}
332
333bool LinGuider::guide()
334{
335 sendCommand(GUIDER, "start");
336 return true;
337}
338
339bool LinGuider::abort()
340{
341 sendCommand(GUIDER, "stop");
342 return true;
343}
344
345bool LinGuider::suspend()
346{
347 return abort();
348}
349
350bool LinGuider::resume()
351{
352 return guide();
353}
354
355bool LinGuider::dither(double pixels)
356{
357 QString pixelsString = QString::number(pixels, 'f', 2);
358 QString args = QString("%1 %2").arg(pixelsString, pixelsString);
359
360 sendCommand(SET_DITHERING_RANGE, args);
361
362 return true;
363}
364}
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:83
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
virtual void disconnectFromHost()
void clear()
char * data()
qsizetype size() const const
virtual bool atEnd() const const
QString errorString() const const
QByteArray readAll()
qint64 write(const QByteArray &data)
qsizetype count() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
qsizetype size() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
void setInterval(int msec)
void start()
void stop()
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:43 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.