File indexing completed on 2024-05-12 15:23:42
0001 /* 0002 SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "guidelog.h" 0008 0009 #include <math.h> 0010 #include <cstdint> 0011 0012 #include <QDateTime> 0013 #include <QStandardPaths> 0014 #include <QTextStream> 0015 0016 #include "auxiliary/kspaths.h" 0017 #include <version.h> 0018 0019 // This class writes a guide log that is compatible with the phdlogview program. 0020 // See https://openphdguiding.org/phd2-log-viewer/ for details on that program. 0021 0022 namespace 0023 { 0024 0025 // These conversion aren't correct. I believe the KStars way of doing it, with RA_INC etc 0026 // is better, however, it is consistent and will work with phdlogview. 0027 QString directionString(GuideDirection direction) 0028 { 0029 switch(direction) 0030 { 0031 case DEC_INC_DIR: 0032 return "N"; 0033 case DEC_DEC_DIR: 0034 return "S"; 0035 case RA_DEC_DIR: 0036 return "E"; 0037 case RA_INC_DIR: 0038 return "W"; 0039 case NO_DIR: 0040 return ""; 0041 } 0042 return ""; 0043 } 0044 0045 QString directionStringLong(GuideDirection direction) 0046 { 0047 switch(direction) 0048 { 0049 case DEC_INC_DIR: 0050 return "North"; 0051 case DEC_DEC_DIR: 0052 return "South"; 0053 case RA_DEC_DIR: 0054 return "East"; 0055 case RA_INC_DIR: 0056 return "West"; 0057 case NO_DIR: 0058 return ""; 0059 } 0060 return ""; 0061 } 0062 0063 QString pierSideString(ISD::Mount::PierSide side) 0064 { 0065 switch(side) 0066 { 0067 case ISD::Mount::PierSide::PIER_WEST: 0068 return QString("West"); 0069 case ISD::Mount::PierSide::PIER_EAST: 0070 return QString("East"); 0071 case ISD::Mount::PierSide::PIER_UNKNOWN: 0072 return QString("Unknown"); 0073 } 0074 return QString(""); 0075 } 0076 0077 double degreesToHours(double degrees) 0078 { 0079 return 24.0 * degrees / 360.0; 0080 } 0081 0082 } // namespace 0083 0084 GuideLog::GuideLog() 0085 { 0086 } 0087 0088 GuideLog::~GuideLog() 0089 { 0090 endLog(); 0091 } 0092 0093 void GuideLog::appendToLog(const QString &lines) 0094 { 0095 if (!enabled) 0096 return; 0097 QTextStream out(&logFile); 0098 out << lines; 0099 out.flush(); 0100 } 0101 0102 // Creates the filename and opens the file. 0103 // Prints a line like the one below. 0104 // KStars version 3.4.0. PHD2 log version 2.5. Log enabled at 2019-11-21 00:00:48 0105 void GuideLog::startLog() 0106 { 0107 QDir dir = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("guidelogs"); 0108 dir.mkpath("."); 0109 0110 logFileName = dir.filePath("guide_log-" + QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss") + ".txt"); 0111 logFile.setFileName(logFileName); 0112 logFile.open(QIODevice::WriteOnly | QIODevice::Text); 0113 0114 appendToLog(QString("KStars version %1. PHD2 log version 2.5. Log enabled at %2\n\n") 0115 .arg(KSTARS_VERSION) 0116 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))); 0117 0118 initialized = true; 0119 } 0120 0121 // Prints a line like the one below and closes the file. 0122 // Log closed at 2019-11-21 08:46:38 0123 void GuideLog::endLog() 0124 { 0125 if (!enabled || !initialized) 0126 return; 0127 0128 if (isGuiding && initialized) 0129 endGuiding(); 0130 0131 appendToLog(QString("Log closed at %1\n") 0132 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))); 0133 logFile.close(); 0134 } 0135 0136 // Output at the start of Guiding. 0137 // Note that in the PHD2 generated versions of this log, there is a lot of guiding information here. 0138 // We just output two lines which phdlogview needs, for pixel scale and RA/DEC. 0139 void GuideLog::startGuiding(const GuideInfo &info) 0140 { 0141 if (!enabled) 0142 return; 0143 if (!initialized) 0144 startLog(); 0145 0146 // Currently phdlogview just reads the Pixel scale value on the 2nd line, and 0147 // just reads the Dec value on the 3rd line. 0148 // Note the log wants hrs for RA, the input to this method is in degrees. 0149 appendToLog(QString("Guiding Begins at %1\n" 0150 "Pixel scale = %2 arc-sec/px, Binning = %3, Focal length = %4 mm\n" 0151 "RA = %5 hr, Dec = %6 deg, Hour angle = N/A hr, Pier side = %7, " 0152 "Rotator pos = N/A, Alt = %8 deg, Az = %9 deg\n" 0153 "Mount = mount, xAngle = %10, xRate = %11, yAngle = %12, yRate = %13\n" 0154 "Frame,Time,mount,dx,dy,RARawDistance,DECRawDistance,RAGuideDistance,DECGuideDistance," 0155 "RADuration,RADirection,DECDuration,DECDirection,XStep,YStep,StarMass,SNR,ErrorCode\n") 0156 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) 0157 .arg(QString::number(info.pixelScale, 'f', 2)) 0158 .arg(info.binning) 0159 .arg(info.focalLength) 0160 .arg(QString::number(degreesToHours(info.ra), 'f', 2)) 0161 .arg(QString::number(info.dec, 'f', 1)) 0162 .arg(pierSideString(info.pierSide)) 0163 .arg(QString::number(info.altitude, 'f', 1)) 0164 .arg(QString::number(info.azimuth, 'f', 1)) 0165 .arg(QString::number(info.xangle, 'f', 1)) 0166 .arg(QString::number(info.xrate, 'f', 3)) 0167 .arg(QString::number(info.yangle, 'f', 1)) 0168 .arg(QString::number(info.yrate, 'f', 3))); 0169 0170 0171 guideIndex = 1; 0172 isGuiding = true; 0173 timer.start(); 0174 } 0175 0176 // Prints a line that looks something like this: 0177 // 55,467.914,"Mount",-1.347,-2.160,2.319,-1.451,1.404,-0.987,303,W,218,N,,,2173,26.91,0 0178 // See the log analysis section in https://openphdguiding.org/PHD2_User_Guide.pdf for definitions of the fields. 0179 void GuideLog::addGuideData(const GuideData &data) 0180 { 0181 QString mountString = data.type == GuideData::MOUNT ? "\"Mount\"" : "\"DROP\""; 0182 QString xStepString = ""; 0183 QString yStepString = ""; 0184 appendToLog(QString("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16,%17,%18\n") 0185 .arg(guideIndex) 0186 .arg(QString::number(timer.elapsed() / 1000.0, 'f', 3)) 0187 .arg(mountString) 0188 .arg(QString::number(data.dx, 'f', 3)) 0189 .arg(QString::number(data.dy, 'f', 3)) 0190 .arg(QString::number(data.raDistance, 'f', 3)) 0191 .arg(QString::number(data.decDistance, 'f', 3)) 0192 .arg(QString::number(data.raGuideDistance, 'f', 3)) 0193 .arg(QString::number(data.decGuideDistance, 'f', 3)) 0194 .arg(data.raDuration) 0195 .arg(directionString(data.raDirection)) 0196 .arg(data.decDuration) 0197 .arg(directionString(data.decDirection)) 0198 .arg(xStepString) 0199 .arg(yStepString) 0200 .arg(QString::number(data.mass, 'f', 0)) 0201 .arg(QString::number(data.snr, 'f', 2)) 0202 .arg(static_cast<int>(data.code))); 0203 ++guideIndex; 0204 } 0205 0206 // Prints a line that looks like: 0207 // Guiding Ends at 2019-11-21 01:57:45 0208 void GuideLog::endGuiding() 0209 { 0210 appendToLog(QString("Guiding Ends at %1\n\n") 0211 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))); 0212 isGuiding = false; 0213 } 0214 0215 // Note that in the PHD2 generated versions of this log, there is a lot of calibration information here. 0216 // We just output two lines which phdlogview needs, for pixel scale and RA/DEC. 0217 void GuideLog::startCalibration(const GuideInfo &info) 0218 { 0219 if (!enabled) 0220 return; 0221 if (!initialized) 0222 startLog(); 0223 // Currently phdlogview just reads the Pixel scale value on the 2nd line, and 0224 // just reads the Dec value on the 3rd line. 0225 appendToLog(QString("Calibration Begins at %1\n" 0226 "Pixel scale = %2 arc-sec/px, Binning = %3, Focal length = %4 mm\n" 0227 "RA = %5 hr, Dec = %6 deg, Hour angle = N/A hr, Pier side = %7, " 0228 "Rotator pos = N/A, Alt = %8 deg, Az = %9 deg\n" 0229 "Direction,Step,dx,dy,x,y,Dist\n") 0230 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) 0231 .arg(QString::number(info.pixelScale, 'f', 2)) 0232 .arg(info.binning) 0233 .arg(info.focalLength) 0234 .arg(QString::number(degreesToHours(info.ra), 'f', 2)) 0235 .arg(QString::number(info.dec, 'f', 1)) 0236 .arg(pierSideString(info.pierSide)) 0237 .arg(QString::number(info.altitude, 'f', 1)) 0238 .arg(QString::number(info.azimuth, 'f', 1))); 0239 0240 calibrationIndex = 1; 0241 timer.start(); 0242 lastCalibrationDirection = NO_DIR; 0243 } 0244 0245 // Prints a line that looks like: 0246 // West,2,-15.207,-1.037,54.800,58.947,15.242 0247 void GuideLog::addCalibrationData(GuideDirection direction, double x, double y, double xOrigin, double yOrigin) 0248 { 0249 if (direction != lastCalibrationDirection) 0250 calibrationIndex = 1; 0251 lastCalibrationDirection = direction; 0252 0253 appendToLog(QString("%1,%2,%3,%4,%5,%6,%7\n") 0254 .arg(directionStringLong(direction)) 0255 .arg(calibrationIndex) 0256 .arg(QString::number(x - xOrigin, 'f', 3)) 0257 .arg(QString::number(y - yOrigin, 'f', 3)) 0258 .arg(QString::number(x, 'f', 3)) 0259 .arg(QString::number(y, 'f', 3)) 0260 .arg(QString::number(hypot(x - xOrigin, y - yOrigin), 'f', 3))); 0261 0262 // This is a little different than PHD2--they seem to count down in the reverse directions. 0263 calibrationIndex++; 0264 } 0265 0266 // Prints a line that looks like: 0267 // West calibration complete. Angle = 106.8 deg 0268 // Currently phdlogview ignores this line. 0269 void GuideLog::endCalibrationSection(GuideDirection direction, double degrees) 0270 { 0271 appendToLog(QString("%1 calibration complete. Angle = %2 deg\n") 0272 .arg(directionStringLong(direction)) 0273 .arg(QString::number(degrees, 'f', 1))); 0274 } 0275 0276 // Prints two lines that look like: 0277 // Calibration guide speeds: RA = 191.5 a-s/s, Dec = 408.0 a-s/s 0278 // Calibration complete 0279 // The failed version is not in the PHD2 log, will be ignored by the viewer. 0280 void GuideLog::endCalibration(double raSpeed, double decSpeed) 0281 { 0282 if (raSpeed == 0 && decSpeed == 0) 0283 appendToLog(QString("Calibration complete (Failed)\n\n")); 0284 else 0285 appendToLog(QString("Calibration guide speeds: RA = %1 a-s/s, Dec = %2 a-s/s\n" 0286 "Calibration complete\n\n") 0287 .arg(QString::number(raSpeed, 'f', 1)) 0288 .arg(QString::number(decSpeed, 'f', 1))); 0289 } 0290 0291 void GuideLog::ditherInfo(double dx, double dy, double x, double y) 0292 { 0293 appendToLog(QString("INFO: DITHER by %1, %2, new lock pos = %3, %4\n") 0294 .arg(QString::number(dx, 'f', 3)) 0295 .arg(QString::number(dy, 'f', 3)) 0296 .arg(QString::number(x, 'f', 3)) 0297 .arg(QString::number(y, 'f', 3))); 0298 // Below moved to ditherInfo from settleStartedInfo() to match phdlogview. 0299 appendToLog("INFO: SETTLING STATE CHANGE, Settling started\n"); 0300 } 0301 0302 void GuideLog::pauseInfo() 0303 { 0304 appendToLog("INFO: Server received PAUSE\n"); 0305 } 0306 0307 void GuideLog::resumeInfo() 0308 { 0309 appendToLog("INFO: Server received RESUME\n"); 0310 } 0311 0312 void GuideLog::settleStartedInfo() 0313 { 0314 // This was moved to ditherInfo() to match phdlogview 0315 // appendToLog("INFO: SETTLING STATE CHANGE, Settling started\n"); 0316 } 0317 0318 void GuideLog::settleCompletedInfo() 0319 { 0320 appendToLog("INFO: SETTLING STATE CHANGE, Settling complete\n"); 0321 }