13#include "ekos/manager.h"
14#include "fitsviewer/fitsdata.h"
15#include "ekos/guide/guide.h"
16#include "fitsviewer/fitsview.h"
23#include <QJsonDocument>
24#include <QNetworkReply>
26#include <ekos_guide_debug.h>
28#define MAX_SET_CONNECTED_RETRIES 3
38 events[
"Version"] = Version;
39 events[
"LockPositionSet"] = LockPositionSet;
40 events[
"Calibrating"] = Calibrating;
41 events[
"CalibrationComplete"] = CalibrationComplete;
42 events[
"StarSelected"] = StarSelected;
43 events[
"StartGuiding"] = StartGuiding;
44 events[
"Paused"] = Paused;
45 events[
"StartCalibration"] = StartCalibration;
46 events[
"AppState"] = AppState;
47 events[
"CalibrationFailed"] = CalibrationFailed;
48 events[
"CalibrationDataFlipped"] = CalibrationDataFlipped;
49 events[
"LoopingExposures"] = LoopingExposures;
50 events[
"LoopingExposuresStopped"] = LoopingExposuresStopped;
51 events[
"SettleBegin"] = SettleBegin;
52 events[
"Settling"] = Settling;
53 events[
"SettleDone"] = SettleDone;
54 events[
"StarLost"] = StarLost;
55 events[
"GuidingStopped"] = GuidingStopped;
56 events[
"Resumed"] = Resumed;
57 events[
"GuideStep"] = GuideStep;
58 events[
"GuidingDithered"] = GuidingDithered;
59 events[
"LockPositionLost"] = LockPositionLost;
60 events[
"Alert"] = Alert;
61 events[
"GuideParamChange"] = GuideParamChange;
62 events[
"ConfigurationChange"] = ConfigurationChange;
66 methodResults[
"capture_single_frame"] = CAPTURE_SINGLE_FRAME;
67 methodResults[
"clear_calibration"] = CLEAR_CALIBRATION_COMMAND_RECEIVED;
68 methodResults[
"dither"] = DITHER_COMMAND_RECEIVED;
73 methodResults[
"get_app_state"] = APP_STATE_RECEIVED;
76 methodResults[
"get_connected"] = IS_EQUIPMENT_CONNECTED;
78 methodResults[
"get_current_equipment"] = GET_CURRENT_EQUIPMENT;
79 methodResults[
"get_dec_guide_mode"] = DEC_GUIDE_MODE;
80 methodResults[
"get_exposure"] = EXPOSURE_TIME;
81 methodResults[
"get_exposure_durations"] = EXPOSURE_DURATIONS;
82 methodResults[
"get_lock_position"] = LOCK_POSITION;
86 methodResults[
"get_pixel_scale"] = PIXEL_SCALE;
91 methodResults[
"get_star_image"] = STAR_IMAGE;
93 methodResults[
"guide"] = GUIDE_COMMAND_RECEIVED;
95 methodResults[
"loop"] = LOOP;
98 methodResults[
"set_connected"] = CONNECTION_RESULT;
99 methodResults[
"set_dec_guide_mode"] = SET_DEC_GUIDE_MODE_COMMAND_RECEIVED;
100 methodResults[
"set_exposure"] = SET_EXPOSURE_COMMAND_RECEIVED;
101 methodResults[
"set_lock_position"] = SET_LOCK_POSITION;
104 methodResults[
"set_paused"] = SET_PAUSED_COMMAND_RECEIVED;
107 methodResults[
"stop_capture"] = STOP_CAPTURE_COMMAND_RECEIVED;
109 abortTimer =
new QTimer(
this);
112 if (state == CALIBRATING)
113 qCDebug(KSTARS_EKOS_GUIDE) <<
"Abort timeout expired while calibrating, retrying to guide.";
114 else if (state == LOSTLOCK)
115 qCDebug(KSTARS_EKOS_GUIDE) <<
"Abort timeout expired while reacquiring star, retrying to guide.";
117 qCDebug(KSTARS_EKOS_GUIDE) <<
"Abort timeout expired, stopping.";
121 ditherTimer =
new QTimer(
this);
124 qCDebug(KSTARS_EKOS_GUIDE) <<
"ditherTimer expired, state" << state <<
"dithering" << isDitherActive <<
"settling" << isSettling;
126 isDitherActive =
false;
128 if (Options::ditherFailAbortsAutoGuide())
131 emit newStatus(GUIDE_DITHERING_ERROR);
135 emit newLog(
i18n(
"PHD2: There was no dithering response from PHD2, but continue guiding."));
136 emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS);
140 stateTimer =
new QTimer(
this);
147 m_PHD2ReconnectCounter++;
148 if (m_PHD2ReconnectCounter > PHD2_RECONNECT_THRESHOLD)
151 emit newLog(
i18n(
"Giving up reconnecting."));
155 emit newLog(
i18n(
"Reconnecting to PHD2 Host: %1, on port %2. . .", Options::pHD2Host(), Options::pHD2Port()));
158#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
164 tcpSocket->connectToHost(Options::pHD2Host(), Options::pHD2Port());
168 m_PHD2ReconnectCounter = 0;
169 checkIfEquipmentConnected();
173 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: TCP connection state:" << socketstate;
191 connection = CONNECTING;
192 emit newLog(
i18n(
"Connecting to PHD2 Host: %1, on port %2. . .", Options::pHD2Host(), Options::pHD2Port()));
195#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
202 tcpSocket->connectToHost(Options::pHD2Host(), Options::pHD2Port());
204 m_PHD2ReconnectCounter = 0;
205 stateTimer->start(PHD2_RECONNECT_TIMEOUT);
208 case EQUIPMENT_DISCONNECTED:
210 connectEquipment(
true);
222void PHD2::ResetConnectionState()
224 connection = DISCONNECTED;
227 pendingRpcResultType = NO_RESULT;
228 rpcRequestQueue.clear();
230 starImageRequested =
false;
232 isDitherActive =
false;
237 tcpSocket->disconnect(
this);
239 emit newStatus(GUIDE_DISCONNECTED);
242bool PHD2::Disconnect()
246 case EQUIPMENT_CONNECTED:
247 emit newLog(
i18n(
"Aborting any capture before disconnecting equipment..."));
249 connection = DISCONNECTING;
254 case EQUIPMENT_DISCONNECTED:
256 tcpSocket->disconnectFromHost();
257 ResetConnectionState();
259 tcpSocket->waitForDisconnected(5000);
260 emit newLog(
i18n(
"Disconnected from PHD2 Host: %1, on port %2.", Options::pHD2Host(), Options::pHD2Port()));
276 emit newLog(
i18n(
"The host disconnected."));
279 emit newLog(
i18n(
"The host was not found. Please check the host name and port settings in Guide options."));
282 emit newLog(
i18n(
"The connection was refused by the peer. Make sure the PHD2 is running, and check that "
283 "the host name and port settings are correct."));
286 emit newLog(
i18n(
"The following error occurred: %1.", tcpSocket->errorString()));
289 ResetConnectionState();
291 emit newStatus(GUIDE_DISCONNECTED);
296 while (!tcpSocket->atEnd() && tcpSocket->canReadLine())
308 emit newLog(
i18n(
"PHD2: invalid response received: %1",
QString(line)));
316 processPHD2Event(jsonObj, line);
318 processPHD2Error(jsonObj, line);
319 else if (jsonObj.
contains(
"result"))
320 processPHD2Result(jsonObj, line);
326 if (Options::verboseLogging())
327 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: event:" << line;
329 QString eventName = jsonEvent[
"Event"].toString();
333 emit newLog(
i18n(
"Unknown PHD2 event: %1", eventName));
337 event = events.
value(eventName);
342 emit newLog(
i18n(
"PHD2: Version %1", jsonEvent[
"PHDVersion"].
toString()));
345 case CalibrationComplete:
346 emit newLog(
i18n(
"PHD2: Calibration Complete."));
347 emit newStatus(Ekos::GUIDE_CALIBRATION_SUCCESS);
351 updateGuideParameters();
352 requestCurrentEquipmentUpdate();
356 emit newLog(
i18n(
"PHD2: Waiting for guiding to settle."));
360 handlePHD2AppState(PAUSED);
363 case StartCalibration:
364 handlePHD2AppState(CALIBRATING);
369 processPHD2State(jsonEvent[
"State"].
toString());
371 if (connection == CONNECTING)
373 emit newLog(
"PHD2: Connecting equipment and external guider...");
374 connectEquipment(
true);
378 case CalibrationFailed:
379 emit newLog(
i18n(
"PHD2: Calibration Failed (%1).", jsonEvent[
"Reason"].
toString()));
380 handlePHD2AppState(STOPPED);
383 case CalibrationDataFlipped:
384 emit newLog(
i18n(
"Calibration Data Flipped."));
387 case LoopingExposures:
388 handlePHD2AppState(LOOPING);
391 case LoopingExposuresStopped:
392 handlePHD2AppState(STOPPED);
403 emit newLog(
i18n(
"PHD2: SettleDone."));
406 if (state == PHD2::STOPPED)
411 if (jsonEvent[
"Status"].toInt() != 0)
414 emit newLog(
i18n(
"PHD2: Settling failed (%1).", jsonEvent[
"Error"].
toString()));
417 bool wasDithering = isDitherActive;
419 isDitherActive =
false;
425 if (error && Options::ditherFailAbortsAutoGuide())
428 emit newStatus(GUIDE_DITHERING_ERROR);
433 emit newLog(
i18n(
"PHD2: There was a dithering error, but continue guiding."));
435 emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS);
442 emit newLog(
i18n(
"PHD2: Settling failed, aborted."));
443 emit newStatus(GUIDE_ABORTED);
448 emit newLog(
i18n(
"PHD2: Settling complete, Guiding Started."));
449 emit newStatus(GUIDE_GUIDING);
456 handlePHD2AppState(SELECTED);
461 handlePHD2AppState(LOSTLOCK);
465 handlePHD2AppState(STOPPED);
469 handlePHD2AppState(GUIDING);
476 if (state == LOSTLOCK)
477 emit newLog(
i18n(
"PHD2: Star found, guiding is resuming..."));
482 double diff_ra_pixels, diff_de_pixels, diff_ra_arcsecs, diff_de_arcsecs, pulse_ra, pulse_dec, snr;
483 QString RADirection, DECDirection;
484 diff_ra_pixels = jsonEvent[
"RADistanceRaw"].toDouble();
485 diff_de_pixels = jsonEvent[
"DECDistanceRaw"].toDouble();
486 pulse_ra = jsonEvent[
"RADuration"].toDouble();
487 pulse_dec = jsonEvent[
"DECDuration"].toDouble();
488 RADirection = jsonEvent[
"RADirection"].toString();
489 DECDirection = jsonEvent[
"DECDirection"].toString();
490 snr = jsonEvent[
"SNR"].toDouble();
492 if (RADirection ==
"East")
493 pulse_ra = -pulse_ra;
494 if (DECDirection ==
"South")
495 pulse_dec = -pulse_dec;
500 diff_ra_arcsecs = diff_ra_pixels * pixelScale;
501 diff_de_arcsecs = diff_de_pixels * pixelScale;
505 diff_ra_arcsecs = 206.26480624709 * diff_ra_pixels * ccdPixelSizeX / mountFocalLength;
506 diff_de_arcsecs = 206.26480624709 * diff_de_pixels * ccdPixelSizeY / mountFocalLength;
509 if (std::isfinite(snr))
512 if (std::isfinite(diff_ra_arcsecs) && std::isfinite(diff_de_arcsecs))
514 errorLog.append(
QPointF(diff_ra_arcsecs, diff_de_arcsecs));
515 if(errorLog.size() > 50)
518 emit newAxisDelta(diff_ra_arcsecs, diff_de_arcsecs);
519 emit newAxisPulse(pulse_ra, pulse_dec);
522 emit guideStats(diff_ra_arcsecs, diff_de_arcsecs, pulse_ra, pulse_dec,
523 std::isfinite(snr) ? snr : 0, 0, 0);
525 double total_sqr_RA_error = 0.0;
526 double total_sqr_DE_error = 0.0;
528 for (
auto &point : errorLog)
530 total_sqr_RA_error += point.x() * point.x();
531 total_sqr_DE_error += point.y() * point.y();
534 emit newAxisSigma(sqrt(total_sqr_RA_error / errorLog.size()), sqrt(total_sqr_DE_error / errorLog.size()));
540 if ( Options::guideSubframe() || currentCameraIsNotInEkos )
541 requestStarImage(32);
543 requestLockPosition();
547 case GuidingDithered:
550 case LockPositionSet:
551 handlePHD2AppState(SELECTED);
554 case LockPositionLost:
555 handlePHD2AppState(LOSTLOCK);
562 case GuideParamChange:
563 case ConfigurationChange:
578void PHD2::processPHD2State(
const QString &phd2State)
580 if (phd2State ==
"Stopped")
581 handlePHD2AppState(STOPPED);
582 else if (phd2State ==
"Selected")
583 handlePHD2AppState(SELECTED);
584 else if (phd2State ==
"Calibrating")
585 handlePHD2AppState(CALIBRATING);
586 else if (phd2State ==
"Guiding")
587 handlePHD2AppState(GUIDING);
588 else if (phd2State ==
"LostLock")
589 handlePHD2AppState(LOSTLOCK);
590 else if (phd2State ==
"Paused")
591 handlePHD2AppState(PAUSED);
592 else if (phd2State ==
"Looping")
593 handlePHD2AppState(LOOPING);
594 else emit newLog(
QString(
"PHD2: Unsupported app state ") + phd2State +
".");
597void PHD2::handlePHD2AppState(PHD2State newstate)
600 if (state == newstate)
610 emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR);
613 emit newLog(
i18n(
"PHD2: Looping Exposures Stopped."));
614 emit newStatus(Ekos::GUIDE_IDLE);
618 emit newLog(
i18n(
"PHD2: Guiding Stopped."));
619 emit newStatus(Ekos::GUIDE_ABORTED);
622 if (connection == DISCONNECTING)
624 emit newLog(
"PHD2: Disconnecting equipment and external guider...");
625 connectEquipment(
false);
637 emit newLog(
i18n(
"PHD2: Lock Position Set."));
640 newstate = CALIBRATING;
641 emit newStatus(Ekos::GUIDE_CALIBRATING);
648 emit newLog(
i18n(
"PHD2: Star Selected."));
649 emit newStatus(GUIDE_STAR_SELECT);
657 emit newLog(
i18n(
"PHD2: Guiding...waiting for settle..."));
661 emit newLog(
i18n(
"PHD2: Dithering successful."));
664 emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS);
667 emit newLog(
i18n(
"PHD2: Guiding started."));
669 emit newStatus(Ekos::GUIDE_GUIDING);
678 emit newLog(
i18n(
"PHD2: Lock Position Lost, continuing calibration."));
684 emit newLog(
i18n(
"PHD2: Star Lost. Trying to reacquire for %1s.", Options::guideLostStarTimeout()));
685 abortTimer->
start(
static_cast<int>(Options::guideLostStarTimeout()) * 1000);
686 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout started (" << Options::guideLostStarTimeout() <<
" sec)";
687 emit newStatus(Ekos::GUIDE_REACQUIRE);
690 emit newLog(
i18n(
"PHD2: Lock Position Lost."));
696 emit newLog(
i18n(
"PHD2: Guiding paused."));
697 emit newStatus(GUIDE_SUSPENDED);
701 emit newLog(
i18n(
"PHD2: Calibrating, timing out in %1s.", Options::guideCalibrationTimeout()));
702 abortTimer->
start(
static_cast<int>(Options::guideCalibrationTimeout()) * 1000);
703 emit newStatus(GUIDE_CALIBRATING);
710 emit newLog(
i18n(
"PHD2: Calibration turned to looping, failed."));
711 emit newStatus(GUIDE_CALIBRATION_ERROR);
714 emit newLog(
i18n(
"PHD2: Looping Exposures."));
715 emit newStatus(GUIDE_LOOPING);
720 emit newLog(
i18n(
"PHD2: Dithering started."));
721 emit newStatus(GUIDE_DITHERING);
730 PHD2ResultType resultType = takeRequestFromList(jsonObj);
732 if (resultType == STAR_IMAGE)
733 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: received star image response, id" <<
734 jsonObj[
"id"].toInt();
736 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: response:" << line;
744 case CAPTURE_SINGLE_FRAME:
747 case CLEAR_CALIBRATION_COMMAND_RECEIVED:
748 emit newLog(
i18n(
"PHD2: Calibration is cleared"));
751 case DITHER_COMMAND_RECEIVED:
752 handlePHD2AppState(DITHERING);
760 case APP_STATE_RECEIVED:
762 QString state = jsonObj[
"State"].toString();
764 state = jsonObj[
"result"].toString();
766 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: received unsupported app state";
768 processPHD2State(state);
775 case IS_EQUIPMENT_CONNECTED:
777 bool isConnected = jsonObj[
"result"].toBool();
784 connection = CONNECTED;
785 setEquipmentConnected();
787 else connectEquipment(
true);
793 setEquipmentConnected();
800 connection = EQUIPMENT_DISCONNECTED;
803 else connectEquipment(
false);
806 case EQUIPMENT_CONNECTED:
811 connection = EQUIPMENT_DISCONNECTED;
812 emit newStatus(Ekos::GUIDE_DISCONNECTED);
817 case EQUIPMENT_DISCONNECTED:
820 setEquipmentConnected();
827 case GET_CURRENT_EQUIPMENT:
829 QJsonObject equipObject = jsonObj[
"result"].toObject();
830 currentCamera = equipObject[
"camera"].toObject()[
"name"].toString();
831 currentMount = equipObject[
"mount"].toObject()[
"name"].toString();
832 currentAuxMount = equipObject[
"aux_mount"].toObject()[
"name"].toString();
834 emit guideEquipmentUpdated();
842 QString mode = jsonObj[
"result"].toString();
843 Ekos::Manager::Instance()->guideModule()->updateDirectionsFromPHD2(mode);
844 emit newLog(
i18n(
"PHD2: DEC Guide Mode is Set to: %1", mode));
851 int exposurems = jsonObj[
"result"].toInt();
852 double exposureTime = exposurems / 1000.0;
853 Ekos::Manager::Instance()->guideModule()->
setExposure(exposureTime);
859 case EXPOSURE_DURATIONS:
861 QVariantList exposureListArray = jsonObj[
"result"].toArray().toVariantList();
862 logValidExposureTimes =
i18n(
"PHD2: Valid Exposure Times: Auto, ");
864 for(
int i = 1; i < exposureListArray.size();
866 values << exposureListArray.
at(i).toDouble() / 1000.0;
867 logValidExposureTimes += Ekos::Manager::Instance()->guideModule()->setRecommendedExposureValues(values);
868 emit newLog(logValidExposureTimes);
873 if(jsonObj[
"result"].toArray().count() == 2)
875 double x = jsonObj[
"result"].toArray().at(0).toDouble();
876 double y = jsonObj[
"result"].toArray().at(1).toDouble();
878 emit newStarPosition(newStarCenter,
true);
882 emit newStarPixmap(m_GuideFrame->getTrackingBoxPixmap());
891 pixelScale = jsonObj[
"result"].toDouble();
893 emit newLog(
i18n(
"PHD2: Please set CCD and telescope parameters in PHD2, Pixel Scale is invalid."));
895 emit newLog(
i18n(
"PHD2: Pixel Scale is %1 arcsec per pixel",
QString::number(pixelScale,
'f', 2)));
905 starImageRequested =
false;
906 QJsonObject jsonResult = jsonObj[
"result"].toObject();
907 processStarImage(jsonResult);
913 case GUIDE_COMMAND_RECEIVED:
914 if (0 != jsonObj[
"result"].toInt(0))
916 emit newLog(
"PHD2: Guide command was rejected.");
917 handlePHD2AppState(STOPPED);
924 handlePHD2AppState(jsonObj[
"result"].toBool() ? LOOPING : STOPPED);
930 case CONNECTION_RESULT:
931 checkIfEquipmentConnected();
934 case SET_DEC_GUIDE_MODE_COMMAND_RECEIVED:
938 case SET_EXPOSURE_COMMAND_RECEIVED:
939 requestExposureTime();
942 case SET_LOCK_POSITION:
943 handlePHD2AppState(SELECTED);
949 case SET_PAUSED_COMMAND_RECEIVED:
950 handlePHD2AppState(PAUSED);
955 case STOP_CAPTURE_COMMAND_RECEIVED:
956 handlePHD2AppState(STOPPED);
967 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: error:" << line;
969 QJsonObject jsonErrorObject = jsonError[
"error"].toObject();
971 PHD2ResultType resultType = takeRequestFromList(jsonError);
976 case SET_EXPOSURE_COMMAND_RECEIVED:
977 emit newLog(logValidExposureTimes);
981 case CONNECTION_RESULT:
982 connection = EQUIPMENT_DISCONNECTED;
983 emit newStatus(Ekos::GUIDE_DISCONNECTED);
986 case DITHER_COMMAND_RECEIVED:
989 isDitherActive =
false;
990 emit newStatus(GUIDE_DITHERING_ERROR);
992 if (Options::ditherFailAbortsAutoGuide())
995 emit newLog(
"PHD2: failing after dithering aborts.");
996 emit newStatus(GUIDE_ABORTED);
1005 case GUIDE_COMMAND_RECEIVED:
1010 emit newLog(
i18n(
"PHD2 Error: unhandled '%1'", jsonErrorObject[
"message"].
toString()));
1022 m_GuideFrame = guideView;
1025void PHD2::processStarImage(
const QJsonObject &jsonStarFrame)
1028 int width = jsonStarFrame[
"width"].toInt();
1029 int height = jsonStarFrame[
"height"].toInt();
1032 fitsfile *fptr =
nullptr;
1034 long fpixel = 1, naxis = 2, nelements, exposure;
1035 long naxes[2] = { width, height };
1036 char error_status[512] = {0};
1038 void* fits_buffer =
nullptr;
1039 size_t fits_buffer_size = 0;
1040 if (fits_create_memfile(&fptr, &fits_buffer, &fits_buffer_size, 4096, realloc, &status))
1042 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_create_file failed:" << error_status;
1046 if (fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status))
1048 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_create_img failed:" << error_status;
1050 fits_close_file(fptr, &status);
1057 fits_update_key(fptr, TLONG,
"EXPOSURE", &exposure,
"Total Exposure Time", &status);
1065 nelements = naxes[0] * naxes[1];
1066 if (fits_write_img(fptr, TUSHORT, fpixel, nelements, converted.
data(), &status))
1068 fits_get_errstatus(status, error_status);
1069 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_write_img failed:" << error_status;
1071 fits_close_file(fptr, &status);
1076 if (fits_flush_file(fptr, &status))
1078 fits_get_errstatus(status, error_status);
1079 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_flush_file failed:" << error_status;
1081 fits_close_file(fptr, &status);
1086 if (fits_close_file(fptr, &status))
1088 fits_get_errstatus(status, error_status);
1089 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_close_file failed:" << error_status;
1099 fdata->setExtension(
QString(
"fits"));
1100 fdata->loadFromBuffer(buffer);
1102 m_GuideFrame->loadData(fdata);
1104 m_GuideFrame->updateFrame();
1105 m_GuideFrame->setTrackingBox(
QRect(0, 0, width, height));
1106 emit newStarPixmap(m_GuideFrame->getTrackingBoxPixmap());
1109void PHD2::setEquipmentConnected()
1111 if (connection != EQUIPMENT_CONNECTED)
1113 setConnectedRetries = 0;
1114 connection = EQUIPMENT_CONNECTED;
1115 emit newStatus(Ekos::GUIDE_CONNECTED);
1116 updateGuideParameters();
1117 requestExposureDurations();
1118 requestCurrentEquipmentUpdate();
1122void PHD2::updateGuideParameters()
1124 if (pixelScale == 0)
1125 requestPixelScale();
1126 requestExposureTime();
1133void PHD2::captureSingleFrame()
1135 sendPHD2Request(
"capture_single_frame");
1139bool PHD2::clearCalibration()
1141 if (connection != EQUIPMENT_CONNECTED)
1143 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1144 emit newStatus(Ekos::GUIDE_ABORTED);
1151 sendPHD2Request(
"clear_calibration", args);
1157bool PHD2::dither(
double pixels)
1159 if (connection != EQUIPMENT_CONNECTED)
1161 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1162 emit newStatus(Ekos::GUIDE_ABORTED);
1168 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring dither requested while already settling";
1170 if (!isDitherActive)
1174 handlePHD2AppState(DITHERING);
1175 isDitherActive =
true;
1183 int ditherTimeout =
static_cast<int>(Options::ditherTimeout());
1185 settle.
insert(
"pixels",
static_cast<double>(Options::ditherThreshold()));
1186 settle.
insert(
"time",
static_cast<int>(Options::ditherSettle()));
1187 settle.
insert(
"timeout", ditherTimeout);
1197 isDitherActive =
true;
1205 enum { TIMEOUT_EXTRA_SECONDS = 60 };
1206 int millis = (ditherTimeout + TIMEOUT_EXTRA_SECONDS) * 1000;
1207 ditherTimer->start(millis);
1209 sendPHD2Request(
"dither", args);
1211 handlePHD2AppState(DITHERING);
1222void PHD2::requestAppState()
1224 sendPHD2Request(
"get_app_state");
1231void PHD2::checkIfEquipmentConnected()
1233 sendPHD2Request(
"get_connected");
1238void PHD2::requestCurrentEquipmentUpdate()
1240 sendPHD2Request(
"get_current_equipment");
1244void PHD2::checkDEGuideMode()
1246 sendPHD2Request(
"get_dec_guide_mode");
1250void PHD2::requestExposureTime()
1252 sendPHD2Request(
"get_exposure");
1256void PHD2::requestExposureDurations()
1258 sendPHD2Request(
"get_exposure_durations");
1262void PHD2::requestLockPosition()
1264 sendPHD2Request(
"get_lock_position");
1271void PHD2::requestPixelScale()
1273 sendPHD2Request(
"get_pixel_scale");
1282void PHD2::requestStarImage(
int size)
1284 if (starImageRequested)
1286 if (Options::verboseLogging())
1287 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: skip extra star image request";
1293 sendPHD2Request(
"get_star_image", args2);
1295 starImageRequested =
true;
1303 if (state == GUIDING)
1305 emit newLog(
i18n(
"PHD2: Guiding is already running."));
1306 emit newStatus(Ekos::GUIDE_GUIDING);
1310 if (connection != EQUIPMENT_CONNECTED)
1312 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1313 emit newStatus(Ekos::GUIDE_ABORTED);
1320 settle.
insert(
"pixels",
static_cast<double>(Options::ditherThreshold()));
1321 settle.
insert(
"time",
static_cast<int>(Options::ditherSettle()));
1322 settle.
insert(
"timeout",
static_cast<int>(Options::ditherTimeout()));
1332 sendPHD2Request(
"guide", args);
1341 sendPHD2Request(
"loop");
1347void PHD2::connectEquipment(
bool enable)
1349 if (connection == EQUIPMENT_CONNECTED && enable ==
true)
1352 if (connection == EQUIPMENT_DISCONNECTED && enable ==
false)
1355 if (setConnectedRetries++ > MAX_SET_CONNECTED_RETRIES)
1357 setConnectedRetries = 0;
1358 connection = EQUIPMENT_DISCONNECTED;
1359 emit newStatus(Ekos::GUIDE_DISCONNECTED);
1371 emit newLog(
i18n(
"PHD2: Connecting Equipment. . ."));
1373 emit newLog(
i18n(
"PHD2: Disconnecting Equipment. . ."));
1375 sendPHD2Request(
"set_connected", args);
1379void PHD2::requestSetDEGuideMode(
bool deEnabled,
bool nEnabled,
1386 if(nEnabled && sEnabled)
1400 sendPHD2Request(
"set_dec_guide_mode", args);
1404void PHD2::requestSetExposureTime(
int time)
1408 sendPHD2Request(
"set_exposure", args);
1412void PHD2::setLockPosition(
double x,
double y)
1416 args << x << y <<
false;
1417 sendPHD2Request(
"set_lock_position", args);
1425 if (connection != EQUIPMENT_CONNECTED)
1427 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1428 emit newStatus(Ekos::GUIDE_ABORTED);
1439 sendPHD2Request(
"set_paused", args);
1444 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout cancelled.";
1454 if (connection != EQUIPMENT_CONNECTED)
1456 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1457 emit newStatus(Ekos::GUIDE_ABORTED);
1466 sendPHD2Request(
"set_paused", args);
1468 if (state == LOSTLOCK)
1470 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout restarted.";
1471 abortTimer->
start(
static_cast<int>(Options::guideLostStarTimeout()) * 1000);
1483 if (connection != EQUIPMENT_CONNECTED)
1485 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1486 emit newStatus(Ekos::GUIDE_ABORTED);
1492 sendPHD2Request(
"stop_capture");
1497bool PHD2::calibrate()
1506void PHD2::sendRpcCall(
QJsonObject &call, PHD2ResultType resultType)
1508 assert(resultType != NO_RESULT);
1509 assert(pendingRpcResultType == NO_RESULT);
1513 int rpcId = nextRpcId++;
1514 call.
insert(
"id", rpcId);
1518 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: request:" << request;
1522 qint64
const n = tcpSocket->write(request);
1524 if ((
int) n == request.
size())
1527 pendingRpcId = rpcId;
1528 pendingRpcResultType = resultType;
1532 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: unexpected short write:" << n <<
"bytes of" << request.
size();
1537void PHD2::sendNextRpcCall()
1539 if (pendingRpcResultType != NO_RESULT)
1542 if (rpcRequestQueue.empty())
1545 RpcCall &call = rpcRequestQueue.front();
1546 sendRpcCall(call.call, call.resultType);
1547 rpcRequestQueue.pop_front();
1552 assert(methodResults.
contains(method));
1554 PHD2ResultType resultType = methodResults[method];
1558 jsonRPC.
insert(
"jsonrpc",
"2.0");
1559 jsonRPC.
insert(
"method", method);
1562 jsonRPC.
insert(
"params", args);
1564 if (pendingRpcResultType == NO_RESULT)
1567 sendRpcCall(jsonRPC, resultType);
1574 if (Options::verboseLogging())
1575 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: defer call" << method;
1577 rpcRequestQueue.push_back(RpcCall(jsonRPC, resultType));
1581PHD2::PHD2ResultType PHD2::takeRequestFromList(
const QJsonObject &response)
1583 if (Q_UNLIKELY(!response.
contains(
"id")))
1585 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring unexpected response with no id";
1589 int id = response[
"id"].toInt();
1591 if (Q_UNLIKELY(
id != pendingRpcId))
1595 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring unexpected response with id" << id;
1599 PHD2ResultType val = pendingRpcResultType;
1600 pendingRpcResultType = NO_RESULT;
Q_SCRIPTABLE Q_NOREPLY void setExposure(double value)
DBUS interface function.
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
void errorOccurred(QAbstractSocket::SocketError socketError)
QByteArray & append(QByteArrayView data)
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
QByteArray fromRawData(const char *data, qsizetype size)
bool isEmpty() const const
qsizetype size() const const
bool contains(const Key &key) const const
T value(const Key &key) const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QByteArray toJson(JsonFormat format) const const
bool contains(QLatin1StringView key) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
QString errorString() const const
const_reference at(qsizetype i) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
QString number(double n, char format, int precision)
bool isActive() const const