Kstars

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

KDE's Doxygen guidelines are available online.