1 /*
2 * guidinglog.cpp
3 * PHD Guiding
4 *
5 * Created by Bret McKee
6 * Copyright (c) 2012-2013 Bret McKee
7 * All rights reserved.
8 *
9 * This source code is distributed under the following "BSD" license
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * Neither the name of Bret McKee, Dad Dog Development,
18 * Craig Stark, Stark Labs nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36 #include "phd.h"
37
38 #include <wx/wfstream.h>
39 #include <wx/txtstrm.h>
40
41 #define GUIDELOG_VERSION _T("2.5")
42
43 const int RetentionPeriod = 60;
44
GuidingLog()45 GuidingLog::GuidingLog()
46 :
47 m_enabled(false),
48 m_keepFile(false),
49 m_isGuiding(false)
50 {
51 }
52
~GuidingLog()53 GuidingLog::~GuidingLog()
54 {
55 }
56
PierSideStr(PierSide p)57 static wxString PierSideStr(PierSide p)
58 {
59 switch (p)
60 {
61 case PIER_SIDE_EAST: return "East";
62 case PIER_SIDE_WEST: return "West";
63 default: return "Unknown";
64 }
65 }
66
ParityStr(int p)67 static wxString ParityStr(int p)
68 {
69 switch (p)
70 {
71 case GUIDE_PARITY_EVEN: return "Even";
72 case GUIDE_PARITY_ODD: return "Odd";
73 default: return "N/A";
74 }
75 }
76
HourAngle(double ra,double lst)77 static double HourAngle(double ra, double lst)
78 {
79 return norm(lst - ra, -12.0, 12.0);
80 }
81
RotatorPosStr()82 static wxString RotatorPosStr()
83 {
84 if (!pRotator)
85 return "N/A";
86 double pos = Rotator::RotatorPosition();
87 if (pos == Rotator::POSITION_UNKNOWN)
88 return "Unknown";
89 else
90 return wxString::Format("%.1f", norm(pos, 0.0, 360.0));
91 }
92
93 // Angles in degrees, HA in hours, results in degrees
GetAltAz(double Latitude,double HA,double Dec,double & Altitude,double & Azimuth)94 static void GetAltAz(double Latitude, double HA, double Dec, double& Altitude, double& Azimuth)
95 {
96 const double HrsToRad = 0.2617993881;
97 // Get altitude first
98 // sin(Alt) = cos(HA)cos(Dec)cos(Lat) + sin(Dec)sin(Lat)
99 double decRadians = radians(Dec);
100 double latRadians = radians(Latitude);
101 double haRadians = HA * HrsToRad;
102 double altRadians;
103 double sinAlt = cos(haRadians) * cos(decRadians) * cos(latRadians) + sin(decRadians) * sin(latRadians);
104 altRadians = asin(sinAlt);
105 Altitude = degrees(asin(sinAlt));
106 // Special handling if we're very close to zenith (very small zenith angle)
107 double zenDist = acos(sinAlt);
108 double zSin = sin(zenDist);
109 if (fabs(zSin) < 1e-5)
110 {
111 Altitude = 90.0;
112 // Azimuth values are arbitrary in this situation
113 if (sin(haRadians) >= 0)
114 Azimuth = 270;
115 else
116 Azimuth = 90;
117 return;
118 }
119
120 // Now get azimuth - alternative formula using zSin avoids div-by-zero conditions
121 double As = cos(decRadians) * sin(haRadians) / zSin;
122 double Ac = (sin(latRadians) * cos(decRadians) * cos(haRadians) - cos(latRadians) *
123 sin(decRadians)) / zSin;
124 // atan2 doesn't want both params = 0
125 if (Ac == 0.0 && As == 0.0)
126 {
127 if (Dec > 0)
128 Azimuth = 180.0;
129 else
130 Azimuth = 0.0;
131 return;
132 }
133 // arctan2 handles quadrants automatically but returns result in the range of -180 to +180 - we want 0 to 360
134 double altPrime = atan2(As, Ac);
135 Azimuth = degrees(altPrime) + 180.0;
136 }
137
PointingInfo()138 static wxString PointingInfo()
139 {
140 double cur_ra, cur_dec, cur_st;
141 double latitude, longitude;
142 double alt;
143 double az;
144 double ha;
145 wxString rslt;
146 bool pointingError = false;
147 if (pPointingSource && !pPointingSource->GetCoordinates(&cur_ra, &cur_dec, &cur_st))
148 {
149 ha = HourAngle(cur_ra, cur_st);
150 rslt = wxString::Format("RA = %0.2f hr, Dec = %0.1f deg, Hour angle = %0.2f hr, Pier side = %s, Rotator pos = %s, ",
151 cur_ra, cur_dec, ha, PierSideStr(pPointingSource->SideOfPier()), RotatorPosStr());
152 }
153 else
154 {
155 rslt = wxString::Format("RA/Dec = Unknown, Hour angle = Unknown, Pier side = Unknown, Rotator pos = %s, ", RotatorPosStr());
156 pointingError = true;
157 }
158 if (pPointingSource && !pointingError && !pPointingSource->GetSiteLatLong(&latitude, &longitude))
159 {
160 GetAltAz(latitude, ha, cur_dec, alt, az);
161 }
162 if (!pointingError)
163 rslt += wxString::Format("Alt = %0.1f deg, Az = %0.1f deg", alt, az);
164 else
165 rslt += "Alt = Unknown, Az = Unknown";
166
167 return rslt;
168 }
169
GuidingHeader(wxFFile & file)170 static void GuidingHeader(wxFFile& file)
171 // output guiding header to log file
172 {
173 file.Write("Equipment Profile = " + pConfig->GetCurrentProfile() + "\n");
174
175 file.Write(pFrame->GetSettingsSummary());
176 file.Write(pFrame->pGuider->GetSettingsSummary());
177
178 if (pCamera)
179 {
180 file.Write(pCamera->GetSettingsSummary());
181 file.Write("Exposure = " + pFrame->ExposureDurationSummary() + "\n");
182 }
183
184 if (pMount)
185 file.Write(pMount->GetSettingsSummary());
186
187 if (pSecondaryMount)
188 file.Write(pSecondaryMount->GetSettingsSummary());
189
190 file.Write(PointingInfo());
191 file.Write("\n");
192
193 const Star& star = pFrame->pGuider->PrimaryStar();
194
195 file.Write(wxString::Format("Lock position = %.3f, %.3f, Star position = %.3f, %.3f, HFD = %.2f px\n",
196 pFrame->pGuider->LockPosition().X,
197 pFrame->pGuider->LockPosition().Y,
198 pFrame->pGuider->CurrentPosition().X,
199 pFrame->pGuider->CurrentPosition().Y,
200 star.HFD));
201
202 file.Write("Frame,Time,mount,dx,dy,RARawDistance,DECRawDistance,RAGuideDistance,DECGuideDistance,"
203 "RADuration,RADirection,DECDuration,DECDirection,XStep,YStep,StarMass,SNR,ErrorCode\n");
204 }
205
WriteSummaryInfo(wxFFile & file,const GuideLogSummaryInfo & summary)206 static void WriteSummaryInfo(wxFFile& file, const GuideLogSummaryInfo& summary)
207 {
208 if (!summary.valid)
209 return;
210
211 file.Write(wxString::Format("Log Summary: calcnt:%u gcnt:%u gdur:%.f gacnt:%u\n",
212 summary.cal_cnt, summary.guide_cnt, summary.guide_dur,
213 summary.ga_cnt));
214 }
215
LoadSummaryInfo(wxFFile & file)216 void GuideLogSummaryInfo::LoadSummaryInfo(wxFFile& file)
217 {
218 Clear();
219
220 wxFFileInputStream is(file);
221 if (is.IsOk())
222 {
223 struct RestorePos {
224 wxFFile& f;
225 wxFileOffset o;
226 RestorePos(wxFFile& f_) : f(f_) { o = f.Tell(); }
227 ~RestorePos() { try { f.Seek(o); } catch (...) {} }
228 } restore(file);
229 wxFileOffset ofs = wxMax(file.Length() - 128, 0LL);
230 is.SeekI(ofs);
231 wxTextInputStream tis(is, wxS(" "), wxMBConvUTF8());
232 while (!is.Eof())
233 {
234 wxString s = tis.ReadLine();
235 if (s.StartsWith(wxS("Log Summary: ")))
236 {
237 size_t pos;
238 wxStringCharType *e;
239 if ((pos = s.find(wxS("calcnt:"))) != wxString::npos)
240 cal_cnt = wxStrtoul(s.substr(pos + 7), &e, 10);
241 if ((pos = s.find(wxS("gcnt:"))) != wxString::npos)
242 guide_cnt = wxStrtoul(s.substr(pos + 5), &e, 10);
243 if ((pos = s.find(wxS("gdur:"))) != wxString::npos)
244 guide_dur = wxStrtod(s.substr(pos + 5), &e);
245 if ((pos = s.find(wxS("gacnt:"))) != wxString::npos)
246 ga_cnt = wxStrtoul(s.substr(pos + 6), &e, 10);
247 valid = true;
248 return;
249 }
250 }
251 }
252 }
253
EnableLogging()254 void GuidingLog::EnableLogging()
255 {
256 if (m_enabled)
257 return;
258
259 try
260 {
261 const wxDateTime& logFileTime = wxGetApp().GetLogFileTime();
262 if (!m_file.IsOpened())
263 {
264 m_fileName = GetLogDir() + PATHSEPSTR + logFileTime.Format(_T("PHD2_GuideLog_%Y-%m-%d_%H%M%S.txt"));
265
266 if (!m_file.Open(m_fileName, "a+"))
267 {
268 throw ERROR_INFO("unable to open file");
269 }
270 if (m_file.Length() > 0)
271 {
272 m_keepFile = true;
273 m_summary.LoadSummaryInfo(m_file);
274 }
275 else
276 {
277 // starting a new log, don't keep it until something meaningful is logged
278 m_keepFile = false;
279 m_summary.valid = true;
280 }
281 }
282
283 assert(m_file.IsOpened());
284
285 m_file.Write(_T("PHD2 version ") FULLVER _T(" [") PHD_OSNAME _T("]") _T(", Log version ") GUIDELOG_VERSION _T(". Log enabled at ") +
286 logFileTime.Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
287
288 m_enabled = true;
289
290 // persist state
291 pConfig->Global.SetBoolean("/LoggingMode", m_enabled);
292
293 // dump guiding header if logging enabled during guide
294 if (pFrame && pFrame->pGuider->IsGuiding())
295 GuidingHeader(m_file);
296
297 Flush();
298 }
299 catch (const wxString& Msg)
300 {
301 POSSIBLY_UNUSED(Msg);
302 }
303 }
304
EnableLogging(bool enable)305 void GuidingLog::EnableLogging(bool enable)
306 {
307 if (enable)
308 EnableLogging();
309 else
310 DisableLogging();
311 }
312
DisableLogging()313 void GuidingLog::DisableLogging()
314 {
315 if (!m_enabled)
316 return;
317
318 if (m_file.IsOpened())
319 {
320 wxDateTime now = wxDateTime::Now();
321
322 m_file.Write("\n");
323 m_file.Write("Log disabled at " + now.Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
324 Flush();
325 }
326
327 m_enabled = false;
328
329 // persist state
330 pConfig->Global.SetBoolean("/LoggingMode", m_enabled);
331 }
332
ChangeDirLog(const wxString & newdir)333 bool GuidingLog::ChangeDirLog(const wxString& newdir)
334 {
335 bool enabled = IsEnabled();
336 bool ok = true;
337
338 CloseGuideLog();
339
340 if (!SetLogDir(newdir))
341 {
342 wxMessageBox(wxString::Format("invalid folder name %s, log folder unchanged", newdir));
343 ok = false;
344 }
345
346 if (enabled) // if SetLogDir failed, no harm no foul, stay with original. Otherwise
347 {
348 EnableLogging(); // start fresh...
349 }
350
351 return ok;
352 }
353
RemoveOldFiles()354 void GuidingLog::RemoveOldFiles()
355 {
356 Logger::RemoveMatchingFiles("PHD2_GuideLog*.txt", RetentionPeriod);
357 }
358
Flush()359 bool GuidingLog::Flush()
360 {
361 if (!m_enabled)
362 return false;
363
364 bool error = false;
365
366 try
367 {
368 assert(m_file.IsOpened());
369
370 if (!m_file.Flush())
371 {
372 throw ERROR_INFO("unable to flush file");
373 }
374 }
375 catch (const wxString& Msg)
376 {
377 POSSIBLY_UNUSED(Msg);
378 error = true;
379 }
380
381 return error;
382 }
383
CloseGuideLog()384 void GuidingLog::CloseGuideLog()
385 {
386 if (m_file.IsOpened())
387 {
388 if (m_keepFile)
389 {
390 wxDateTime now = wxDateTime::Now();
391
392 m_file.Write("\n");
393 WriteSummaryInfo(m_file, m_summary);
394 m_file.Write("Log closed at " + now.Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
395 Flush();
396 }
397
398 m_file.Close();
399 }
400
401 m_enabled = false;
402
403 if (!m_keepFile) // Delete the file if nothing useful was logged
404 {
405 wxRemove(m_fileName);
406 }
407 }
408
StartCalibration(const Mount * pCalibrationMount)409 void GuidingLog::StartCalibration(const Mount *pCalibrationMount)
410 {
411 m_isGuiding = true;
412
413 if (!m_enabled)
414 return;
415
416 assert(m_file.IsOpened());
417 wxDateTime now = wxDateTime::Now();
418
419 m_file.Write("\n");
420 m_file.Write("Calibration Begins at " + now.Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
421 m_file.Write("Equipment Profile = " + pConfig->GetCurrentProfile() + "\n");
422
423 m_file.Write(pFrame->GetSettingsSummary());
424 m_file.Write(pFrame->pGuider->GetSettingsSummary());
425
426 if (pCamera)
427 {
428 m_file.Write(pCamera->GetSettingsSummary());
429 m_file.Write("Exposure = " + pFrame->ExposureDurationSummary() + "\n");
430 }
431
432 assert(pCalibrationMount && pCalibrationMount->IsConnected());
433
434 m_file.Write("Mount = " + pCalibrationMount->Name());
435 wxString calSettings = pCalibrationMount->CalibrationSettingsSummary();
436 if (!calSettings.IsEmpty())
437 m_file.Write(", " + calSettings);
438 m_file.Write("\n");
439
440 m_file.Write(PointingInfo());
441 m_file.Write("\n");
442
443 const Star& star = pFrame->pGuider->PrimaryStar();
444
445 m_file.Write(wxString::Format("Lock position = %.3f, %.3f, Star position = %.3f, %.3f, HFD = %.2f px\n",
446 pFrame->pGuider->LockPosition().X,
447 pFrame->pGuider->LockPosition().Y,
448 pFrame->pGuider->CurrentPosition().X,
449 pFrame->pGuider->CurrentPosition().Y,
450 star.HFD));
451
452 m_file.Write("Direction,Step,dx,dy,x,y,Dist\n");
453
454 Flush();
455
456 m_keepFile = true;
457 }
458
CalibrationFailed(const Mount * pCalibrationMount,const wxString & msg)459 void GuidingLog::CalibrationFailed(const Mount *pCalibrationMount, const wxString& msg)
460 {
461 m_isGuiding = false;
462
463 if (!m_enabled)
464 return;
465
466 assert(m_file.IsOpened());
467
468 m_file.Write(msg); m_file.Write("\n");
469 Flush();
470 }
471
CalibrationStep(const CalibrationStepInfo & info)472 void GuidingLog::CalibrationStep(const CalibrationStepInfo& info)
473 {
474 if (!m_enabled)
475 return;
476
477 assert(m_file.IsOpened());
478
479 // Direction,Step,dx,dy,x,y,Dist
480 m_file.Write(wxString::Format("%s,%d,%.3f,%.3f,%.3f,%.3f,%.3f\n",
481 info.direction,
482 info.stepNumber,
483 info.dx, info.dy,
484 info.pos.X, info.pos.Y,
485 info.dist));
486
487 Flush();
488 }
489
CalibrationDirectComplete(const Mount * pCalibrationMount,const wxString & direction,double angle,double rate,int parity)490 void GuidingLog::CalibrationDirectComplete(const Mount *pCalibrationMount, const wxString& direction, double angle, double rate, int parity)
491 {
492 if (!m_enabled)
493 return;
494
495 assert(m_file.IsOpened());
496
497 m_file.Write(wxString::Format("%s calibration complete. Angle = %.1f deg, Rate = %.3f px/sec, Parity = %s\n",
498 direction, degrees(angle), rate * 1000.0, ParityStr(parity)));
499
500 Flush();
501 }
502
CalibrationComplete(const Mount * pCalibrationMount)503 void GuidingLog::CalibrationComplete(const Mount *pCalibrationMount)
504 {
505 m_isGuiding = false;
506
507 if (!m_enabled)
508 return;
509
510 ++m_summary.cal_cnt;
511
512 assert(m_file.IsOpened());
513
514 m_file.Write(wxString::Format("Calibration complete, mount = %s.\n", pCalibrationMount->Name()));
515
516 Flush();
517 }
518
GuidingStarted()519 void GuidingLog::GuidingStarted()
520 {
521 m_isGuiding = true;
522
523 if (!m_enabled)
524 return;
525
526 assert(m_file.IsOpened());
527
528 m_file.Write("\n");
529 m_file.Write("Guiding Begins at " + pFrame->m_guidingStarted.Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
530
531 // add common guiding header
532 GuidingHeader(m_file);
533
534 Flush();
535
536 m_keepFile = true;
537 }
538
GuidingStopped()539 void GuidingLog::GuidingStopped()
540 {
541 m_isGuiding = false;
542
543 if (!m_enabled)
544 return;
545
546 assert(m_file.IsOpened());
547
548 ++m_summary.guide_cnt;
549 m_summary.guide_dur += pFrame->TimeSinceGuidingStarted();
550
551 m_file.Write("Guiding Ends at " + wxDateTime::Now().Format(_T("%Y-%m-%d %H:%M:%S")) + "\n");
552 Flush();
553 }
554
GuideStep(const GuideStepInfo & step)555 void GuidingLog::GuideStep(const GuideStepInfo& step)
556 {
557 if (!m_enabled)
558 return;
559
560 assert(m_file.IsOpened());
561
562 m_file.Write(wxString::Format("%d,%.3f,\"%s\",%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,",
563 step.frameNumber, step.time,
564 step.mount->IsStepGuider() ? "AO" : "Mount",
565 step.cameraOffset.X, step.cameraOffset.Y,
566 step.mountOffset.X, step.mountOffset.Y,
567 step.guideDistanceRA, step.guideDistanceDec));
568
569 if (step.mount->IsStepGuider())
570 {
571 int xSteps = step.directionRA == LEFT ? -step.durationRA : step.durationRA;
572 int ySteps = step.directionDec == DOWN ? -step.durationDec : step.durationDec;
573 m_file.Write(wxString::Format(",,,,%d,%d,", xSteps, ySteps));
574 }
575 else
576 {
577 m_file.Write(wxString::Format("%d,%s,%d,%s,,,",
578 step.durationRA, step.durationRA > 0 ? step.mount->DirectionChar((GUIDE_DIRECTION)step.directionRA) : "",
579 step.durationDec, step.durationDec > 0 ? step.mount->DirectionChar((GUIDE_DIRECTION)step.directionDec): ""));
580 }
581
582 m_file.Write(wxString::Format("%.f,%.2f,%d\n",
583 step.starMass, step.starSNR, step.starError));
584
585 Flush();
586 }
587
FrameDropped(const FrameDroppedInfo & info)588 void GuidingLog::FrameDropped(const FrameDroppedInfo& info)
589 {
590 if (!m_enabled)
591 return;
592
593 assert(m_file.IsOpened());
594
595 m_file.Write(wxString::Format("%d,%.3f,\"DROP\",,,,,,,,,,,,,%.f,%.2f,%d,\"%s\"\n",
596 info.frameNumber, info.time, info.starMass, info.starSNR, info.starError, info.status));
597
598 Flush();
599 }
600
601
CalibrationFrameDropped(const FrameDroppedInfo & info)602 void GuidingLog::CalibrationFrameDropped(const FrameDroppedInfo& info)
603 {
604 if (!m_enabled)
605 return;
606
607 assert(m_file.IsOpened());
608
609 m_file.Write(wxString::Format("INFO: STAR LOST during calibration, Mass= %.f, SNR= %.2f, Error= %d, Status=%s\n",
610 info.starMass, info.starSNR, info.starError, info.status));
611
612 Flush();
613 }
614
NotifyGuidingDithered(Guider * guider,double dx,double dy)615 void GuidingLog::NotifyGuidingDithered(Guider *guider, double dx, double dy)
616 {
617 if (!m_enabled || !m_isGuiding)
618 return;
619
620 m_file.Write(wxString::Format("INFO: DITHER by %.3f, %.3f, new lock pos = %.3f, %.3f\n",
621 dx, dy, guider->LockPosition().X, guider->LockPosition().Y));
622
623 Flush();
624 }
625
NotifySettlingStateChange(const wxString & msg)626 void GuidingLog::NotifySettlingStateChange(const wxString& msg)
627 {
628 if (!m_enabled)
629 return;
630 m_file.Write(wxString::Format("INFO: SETTLING STATE CHANGE, %s\n", msg));
631 Flush();
632 }
633
NotifyGACompleted()634 void GuidingLog::NotifyGACompleted()
635 {
636 if (!m_enabled)
637 return;
638
639 ++m_summary.ga_cnt;
640 }
641
NotifyGAResult(const wxString & msg)642 void GuidingLog::NotifyGAResult(const wxString& msg)
643 {
644 if (!m_enabled)
645 return;
646
647 // Client needs to handle end-of-line formatting
648 m_file.Write(wxString::Format("INFO: GA Result - %s", msg));
649 Flush();
650 }
651
NotifySetLockPosition(Guider * guider)652 void GuidingLog::NotifySetLockPosition(Guider *guider)
653 {
654 if (!m_enabled || !m_isGuiding)
655 return;
656
657 m_file.Write(wxString::Format("INFO: SET LOCK POSITION, new lock pos = %.3f, %.3f\n",
658 guider->LockPosition().X, guider->LockPosition().Y));
659
660 Flush();
661
662 m_keepFile = true;
663 }
664
NotifyLockShiftParams(const LockPosShiftParams & shiftParams,const PHD_Point & cameraRate)665 void GuidingLog::NotifyLockShiftParams(const LockPosShiftParams& shiftParams, const PHD_Point& cameraRate)
666 {
667 if (!m_enabled || !m_isGuiding)
668 return;
669
670 wxString details;
671 if (shiftParams.shiftEnabled)
672 {
673 details = wxString::Format("%s rate (%.2f,%.2f) %s/hr (%.2f,%.2f) px/hr",
674 shiftParams.shiftIsMountCoords ? "RA,Dec" : "X,Y",
675 shiftParams.shiftRate.IsValid() ? shiftParams.shiftRate.X : 0.0,
676 shiftParams.shiftRate.IsValid() ? shiftParams.shiftRate.Y : 0.0,
677 shiftParams.shiftUnits == UNIT_ARCSEC ? "arc-sec" : "pixels",
678 cameraRate.IsValid() ? cameraRate.X * 3600.0 : 0.0,
679 cameraRate.IsValid() ? cameraRate.Y * 3600.0 : 0.0);
680 }
681
682 m_file.Write(wxString::Format("INFO: LOCK SHIFT, enabled = %d %s\n", shiftParams.shiftEnabled, details));
683 Flush();
684
685 m_keepFile = true;
686 }
687
ServerCommand(Guider * guider,const wxString & cmd)688 void GuidingLog::ServerCommand(Guider *guider, const wxString& cmd)
689 {
690 if (!m_enabled || !m_isGuiding)
691 return;
692
693 m_file.Write(wxString::Format("INFO: Server received %s\n", cmd));
694 Flush();
695
696 m_keepFile = true;
697 }
698
NotifyManualGuide(const Mount * mount,int direction,int duration)699 void GuidingLog::NotifyManualGuide(const Mount *mount, int direction, int duration)
700 {
701 if (!m_enabled || !m_isGuiding)
702 return;
703
704 m_file.Write(wxString::Format("INFO: Manual guide (%s) %s %d %s\n",
705 mount->IsStepGuider() ? "AO" : "Mount",
706 mount->DirectionStr(static_cast<GUIDE_DIRECTION>(direction)), duration,
707 mount->IsStepGuider() ? (duration != 1 ? "steps" : "step") : "ms"));
708 Flush();
709
710 m_keepFile = true;
711 }
712
SetGuidingParam(const wxString & name,double val)713 void GuidingLog::SetGuidingParam(const wxString& name, double val)
714 {
715 SetGuidingParam(name, wxString::Format("%.2f", val));
716 }
717
SetGuidingParam(const wxString & name,int val)718 void GuidingLog::SetGuidingParam(const wxString& name, int val)
719 {
720 SetGuidingParam(name, wxString::Format("%d", val));
721 }
722
SetGuidingParam(const wxString & name,bool val)723 void GuidingLog::SetGuidingParam(const wxString& name, bool val)
724 {
725 SetGuidingParam(name, wxString(val ? "true" : "false"));
726 }
727
SetGuidingParam(const wxString & name,const wxString & val)728 void GuidingLog::SetGuidingParam(const wxString& name, const wxString& val)
729 {
730 if (!m_enabled || !m_isGuiding)
731 return;
732
733 m_file.Write(wxString::Format("INFO: Guiding parameter change, %s = %s\n", name, val));
734 Flush();
735
736 m_keepFile = true;
737 }
738
SetGuidingParam(const wxString & name,const wxString & val,bool AlwaysLog)739 void GuidingLog::SetGuidingParam(const wxString& name, const wxString& val, bool AlwaysLog)
740 {
741 m_file.Write(wxString::Format("INFO: Guiding parameter change, %s = %s\n", name, val));
742 Flush();
743
744 m_keepFile = true;
745 }
746