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