Kstars

guidelog.cpp
1/*
2 SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "guidelog.h"
8
9#include <math.h>
10#include <cstdint>
11
12#include <QDateTime>
13#include <QStandardPaths>
14#include <QTextStream>
15
16#include "auxiliary/kspaths.h"
17#include <version.h>
18
19// This class writes a guide log that is compatible with the phdlogview program.
20// See https://openphdguiding.org/phd2-log-viewer/ for details on that program.
21
22namespace
23{
24
25// These conversion aren't correct. I believe the KStars way of doing it, with RA_INC etc
26// is better, however, it is consistent and will work with phdlogview.
27QString directionString(GuideDirection direction)
28{
29 switch(direction)
30 {
31 case DEC_INC_DIR:
32 return "N";
33 case DEC_DEC_DIR:
34 return "S";
35 case RA_DEC_DIR:
36 return "E";
37 case RA_INC_DIR:
38 return "W";
39 case NO_DIR:
40 return "";
41 }
42 return "";
43}
44
45QString directionStringLong(GuideDirection direction)
46{
47 switch(direction)
48 {
49 case DEC_INC_DIR:
50 return "North";
51 case DEC_DEC_DIR:
52 return "South";
53 case RA_DEC_DIR:
54 return "East";
55 case RA_INC_DIR:
56 return "West";
57 case NO_DIR:
58 return "";
59 }
60 return "";
61}
62
63QString pierSideString(ISD::Mount::PierSide side)
64{
65 switch(side)
66 {
67 case ISD::Mount::PierSide::PIER_WEST:
68 return QString("West");
69 case ISD::Mount::PierSide::PIER_EAST:
70 return QString("East");
71 case ISD::Mount::PierSide::PIER_UNKNOWN:
72 return QString("Unknown");
73 }
74 return QString("");
75}
76
77double degreesToHours(double degrees)
78{
79 return 24.0 * degrees / 360.0;
80}
81
82} // namespace
83
84GuideLog::GuideLog()
85{
86}
87
88GuideLog::~GuideLog()
89{
90 endLog();
91}
92
93void GuideLog::appendToLog(const QString &lines)
94{
95 if (!enabled)
96 return;
97 QTextStream out(&logFile);
98 out << lines;
99 out.flush();
100}
101
102// Creates the filename and opens the file.
103// Prints a line like the one below.
104// KStars version 3.4.0. PHD2 log version 2.5. Log enabled at 2019-11-21 00:00:48
105void GuideLog::startLog()
106{
107 QDir dir = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("guidelogs");
108 dir.mkpath(".");
109
110 logFileName = dir.filePath("guide_log-" + QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss") + ".txt");
111 logFile.setFileName(logFileName);
113
114 appendToLog(QString("KStars version %1. PHD2 log version 2.5. Log enabled at %2\n\n")
115 .arg(KSTARS_VERSION)
116 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")));
117
118 initialized = true;
119}
120
121// Prints a line like the one below and closes the file.
122// Log closed at 2019-11-21 08:46:38
123void GuideLog::endLog()
124{
125 if (!enabled || !initialized)
126 return;
127
128 if (isGuiding && initialized)
129 endGuiding();
130
131 appendToLog(QString("Log closed at %1\n")
132 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")));
133 logFile.close();
134}
135
136// Output at the start of Guiding.
137// Note that in the PHD2 generated versions of this log, there is a lot of guiding information here.
138// We just output two lines which phdlogview needs, for pixel scale and RA/DEC.
139void GuideLog::startGuiding(const GuideInfo &info)
140{
141 if (!enabled)
142 return;
143 if (!initialized)
144 startLog();
145
146 // Currently phdlogview just reads the Pixel scale value on the 2nd line, and
147 // just reads the Dec value on the 3rd line.
148 // Note the log wants hrs for RA, the input to this method is in degrees.
149 appendToLog(QString("Guiding Begins at %1\n"
150 "Pixel scale = %2 arc-sec/px, Binning = %3, Focal length = %4 mm\n"
151 "RA = %5 hr, Dec = %6 deg, Hour angle = N/A hr, Pier side = %7, "
152 "Rotator pos = N/A, Alt = %8 deg, Az = %9 deg\n"
153 "Mount = mount, xAngle = %10, xRate = %11, yAngle = %12, yRate = %13\n"
154 "Frame,Time,mount,dx,dy,RARawDistance,DECRawDistance,RAGuideDistance,DECGuideDistance,"
155 "RADuration,RADirection,DECDuration,DECDirection,XStep,YStep,StarMass,SNR,ErrorCode\n")
156 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
157 .arg(QString::number(info.pixelScale, 'f', 2))
158 .arg(info.binning)
159 .arg(info.focalLength)
160 .arg(QString::number(degreesToHours(info.ra), 'f', 2))
161 .arg(QString::number(info.dec, 'f', 1))
162 .arg(pierSideString(info.pierSide))
163 .arg(QString::number(info.altitude, 'f', 1))
164 .arg(QString::number(info.azimuth, 'f', 1))
165 .arg(QString::number(info.xangle, 'f', 1))
166 .arg(QString::number(info.xrate, 'f', 3))
167 .arg(QString::number(info.yangle, 'f', 1))
168 .arg(QString::number(info.yrate, 'f', 3)));
169
170
171 guideIndex = 1;
172 isGuiding = true;
173 timer.start();
174}
175
176// Prints a line that looks something like this:
177// 55,467.914,"Mount",-1.347,-2.160,2.319,-1.451,1.404,-0.987,303,W,218,N,,,2173,26.91,0
178// See the log analysis section in https://openphdguiding.org/PHD2_User_Guide.pdf for definitions of the fields.
179void GuideLog::addGuideData(const GuideData &data)
180{
181 QString mountString = data.type == GuideData::MOUNT ? "\"Mount\"" : "\"DROP\"";
182 QString xStepString = "";
183 QString yStepString = "";
184 appendToLog(QString("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16,%17,%18\n")
185 .arg(guideIndex)
186 .arg(QString::number(timer.elapsed() / 1000.0, 'f', 3))
187 .arg(mountString)
188 .arg(QString::number(data.dx, 'f', 3))
189 .arg(QString::number(data.dy, 'f', 3))
190 .arg(QString::number(data.raDistance, 'f', 3))
191 .arg(QString::number(data.decDistance, 'f', 3))
192 .arg(QString::number(data.raGuideDistance, 'f', 3))
193 .arg(QString::number(data.decGuideDistance, 'f', 3))
194 .arg(data.raDuration)
195 .arg(directionString(data.raDirection))
196 .arg(data.decDuration)
197 .arg(directionString(data.decDirection))
198 .arg(xStepString)
199 .arg(yStepString)
200 .arg(QString::number(data.mass, 'f', 0))
201 .arg(QString::number(data.snr, 'f', 2))
202 .arg(static_cast<int>(data.code)));
203 ++guideIndex;
204}
205
206// Prints a line that looks like:
207// Guiding Ends at 2019-11-21 01:57:45
208void GuideLog::endGuiding()
209{
210 appendToLog(QString("Guiding Ends at %1\n\n")
211 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")));
212 isGuiding = false;
213}
214
215// Note that in the PHD2 generated versions of this log, there is a lot of calibration information here.
216// We just output two lines which phdlogview needs, for pixel scale and RA/DEC.
217void GuideLog::startCalibration(const GuideInfo &info)
218{
219 if (!enabled)
220 return;
221 if (!initialized)
222 startLog();
223 // Currently phdlogview just reads the Pixel scale value on the 2nd line, and
224 // just reads the Dec value on the 3rd line.
225 appendToLog(QString("Calibration Begins at %1\n"
226 "Pixel scale = %2 arc-sec/px, Binning = %3, Focal length = %4 mm\n"
227 "RA = %5 hr, Dec = %6 deg, Hour angle = N/A hr, Pier side = %7, "
228 "Rotator pos = N/A, Alt = %8 deg, Az = %9 deg\n"
229 "Direction,Step,dx,dy,x,y,Dist\n")
230 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
231 .arg(QString::number(info.pixelScale, 'f', 2))
232 .arg(info.binning)
233 .arg(info.focalLength)
234 .arg(QString::number(degreesToHours(info.ra), 'f', 2))
235 .arg(QString::number(info.dec, 'f', 1))
236 .arg(pierSideString(info.pierSide))
237 .arg(QString::number(info.altitude, 'f', 1))
238 .arg(QString::number(info.azimuth, 'f', 1)));
239
240 calibrationIndex = 1;
241 timer.start();
242 lastCalibrationDirection = NO_DIR;
243}
244
245// Prints a line that looks like:
246// West,2,-15.207,-1.037,54.800,58.947,15.242
247void GuideLog::addCalibrationData(GuideDirection direction, double x, double y, double xOrigin, double yOrigin)
248{
249 if (direction != lastCalibrationDirection)
250 calibrationIndex = 1;
251 lastCalibrationDirection = direction;
252
253 appendToLog(QString("%1,%2,%3,%4,%5,%6,%7\n")
254 .arg(directionStringLong(direction))
255 .arg(calibrationIndex)
256 .arg(QString::number(x - xOrigin, 'f', 3))
257 .arg(QString::number(y - yOrigin, 'f', 3))
258 .arg(QString::number(x, 'f', 3))
259 .arg(QString::number(y, 'f', 3))
260 .arg(QString::number(hypot(x - xOrigin, y - yOrigin), 'f', 3)));
261
262 // This is a little different than PHD2--they seem to count down in the reverse directions.
263 calibrationIndex++;
264}
265
266// Prints a line that looks like:
267// West calibration complete. Angle = 106.8 deg
268// Currently phdlogview ignores this line.
269void GuideLog::endCalibrationSection(GuideDirection direction, double degrees)
270{
271 appendToLog(QString("%1 calibration complete. Angle = %2 deg\n")
272 .arg(directionStringLong(direction))
273 .arg(QString::number(degrees, 'f', 1)));
274}
275
276// Prints two lines that look like:
277// Calibration guide speeds: RA = 191.5 a-s/s, Dec = 408.0 a-s/s
278// Calibration complete
279// The failed version is not in the PHD2 log, will be ignored by the viewer.
280void GuideLog::endCalibration(double raSpeed, double decSpeed)
281{
282 if (raSpeed == 0 && decSpeed == 0)
283 appendToLog(QString("Calibration complete (Failed)\n\n"));
284 else
285 appendToLog(QString("Calibration guide speeds: RA = %1 a-s/s, Dec = %2 a-s/s\n"
286 "Calibration complete\n\n")
287 .arg(QString::number(raSpeed, 'f', 1))
288 .arg(QString::number(decSpeed, 'f', 1)));
289}
290
291void GuideLog::ditherInfo(double dx, double dy, double x, double y)
292{
293 appendToLog(QString("INFO: DITHER by %1, %2, new lock pos = %3, %4\n")
294 .arg(QString::number(dx, 'f', 3))
295 .arg(QString::number(dy, 'f', 3))
296 .arg(QString::number(x, 'f', 3))
297 .arg(QString::number(y, 'f', 3)));
298 // Below moved to ditherInfo from settleStartedInfo() to match phdlogview.
299 appendToLog("INFO: SETTLING STATE CHANGE, Settling started\n");
300}
301
302void GuideLog::pauseInfo()
303{
304 appendToLog("INFO: Server received PAUSE\n");
305}
306
307void GuideLog::resumeInfo()
308{
309 appendToLog("INFO: Server received RESUME\n");
310}
311
312void GuideLog::settleStartedInfo()
313{
314 // This was moved to ditherInfo() to match phdlogview
315 // appendToLog("INFO: SETTLING STATE CHANGE, Settling started\n");
316}
317
318void GuideLog::settleCompletedInfo()
319{
320 appendToLog("INFO: SETTLING STATE CHANGE, Settling complete\n");
321}
char * toString(const EngineQuery &query)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QDateTime currentDateTime()
QString filePath(const QString &fileName) const const
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:40 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.