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);
404 if (state == PHD2::STOPPED)
409 if (jsonEvent[
"Status"].toInt() != 0)
412 emit newLog(
i18n(
"PHD2: Settling failed (%1).", jsonEvent[
"Error"].
toString()));
415 bool wasDithering = isDitherActive;
417 isDitherActive =
false;
423 if (error && Options::ditherFailAbortsAutoGuide())
426 emit newStatus(GUIDE_DITHERING_ERROR);
431 emit newLog(
i18n(
"PHD2: There was a dithering error, but continue guiding."));
433 emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS);
440 emit newLog(
i18n(
"PHD2: Settling failed, aborted."));
441 emit newStatus(GUIDE_ABORTED);
446 emit newLog(
i18n(
"PHD2: Settling complete, Guiding Started."));
447 emit newStatus(GUIDE_GUIDING);
454 handlePHD2AppState(SELECTED);
459 handlePHD2AppState(LOSTLOCK);
463 handlePHD2AppState(STOPPED);
467 handlePHD2AppState(GUIDING);
474 if (state == LOSTLOCK)
475 emit newLog(
i18n(
"PHD2: Star found, guiding is resuming..."));
480 double diff_ra_pixels, diff_de_pixels, diff_ra_arcsecs, diff_de_arcsecs, pulse_ra, pulse_dec, snr;
481 QString RADirection, DECDirection;
482 diff_ra_pixels = jsonEvent[
"RADistanceRaw"].toDouble();
483 diff_de_pixels = jsonEvent[
"DECDistanceRaw"].toDouble();
484 pulse_ra = jsonEvent[
"RADuration"].toDouble();
485 pulse_dec = jsonEvent[
"DECDuration"].toDouble();
486 RADirection = jsonEvent[
"RADirection"].toString();
487 DECDirection = jsonEvent[
"DECDirection"].toString();
488 snr = jsonEvent[
"SNR"].toDouble();
490 if (RADirection ==
"East")
491 pulse_ra = -pulse_ra;
492 if (DECDirection ==
"South")
493 pulse_dec = -pulse_dec;
498 diff_ra_arcsecs = diff_ra_pixels * pixelScale;
499 diff_de_arcsecs = diff_de_pixels * pixelScale;
503 diff_ra_arcsecs = 206.26480624709 * diff_ra_pixels * ccdPixelSizeX / mountFocalLength;
504 diff_de_arcsecs = 206.26480624709 * diff_de_pixels * ccdPixelSizeY / mountFocalLength;
507 if (std::isfinite(snr))
510 if (std::isfinite(diff_ra_arcsecs) && std::isfinite(diff_de_arcsecs))
512 errorLog.append(
QPointF(diff_ra_arcsecs, diff_de_arcsecs));
513 if(errorLog.size() > 50)
516 emit newAxisDelta(diff_ra_arcsecs, diff_de_arcsecs);
517 emit newAxisPulse(pulse_ra, pulse_dec);
520 emit guideStats(diff_ra_arcsecs, diff_de_arcsecs, pulse_ra, pulse_dec,
521 std::isfinite(snr) ? snr : 0, 0, 0);
523 double total_sqr_RA_error = 0.0;
524 double total_sqr_DE_error = 0.0;
526 for (
auto &point : errorLog)
528 total_sqr_RA_error += point.x() * point.x();
529 total_sqr_DE_error += point.y() * point.y();
532 emit newAxisSigma(sqrt(total_sqr_RA_error / errorLog.size()), sqrt(total_sqr_DE_error / errorLog.size()));
538 if ( Options::guideSubframe() || currentCameraIsNotInEkos )
539 requestStarImage(32);
541 requestLockPosition();
545 case GuidingDithered:
548 case LockPositionSet:
549 handlePHD2AppState(SELECTED);
552 case LockPositionLost:
553 handlePHD2AppState(LOSTLOCK);
560 case GuideParamChange:
561 case ConfigurationChange:
576void PHD2::processPHD2State(
const QString &phd2State)
578 if (phd2State ==
"Stopped")
579 handlePHD2AppState(STOPPED);
580 else if (phd2State ==
"Selected")
581 handlePHD2AppState(SELECTED);
582 else if (phd2State ==
"Calibrating")
583 handlePHD2AppState(CALIBRATING);
584 else if (phd2State ==
"Guiding")
585 handlePHD2AppState(GUIDING);
586 else if (phd2State ==
"LostLock")
587 handlePHD2AppState(LOSTLOCK);
588 else if (phd2State ==
"Paused")
589 handlePHD2AppState(PAUSED);
590 else if (phd2State ==
"Looping")
591 handlePHD2AppState(LOOPING);
592 else emit newLog(
QString(
"PHD2: Unsupported app state ") + phd2State +
".");
595void PHD2::handlePHD2AppState(PHD2State newstate)
598 if (state == newstate)
608 emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR);
611 emit newLog(
i18n(
"PHD2: Looping Exposures Stopped."));
612 emit newStatus(Ekos::GUIDE_IDLE);
616 emit newLog(
i18n(
"PHD2: Guiding Stopped."));
617 emit newStatus(Ekos::GUIDE_ABORTED);
620 if (connection == DISCONNECTING)
622 emit newLog(
"PHD2: Disconnecting equipment and external guider...");
623 connectEquipment(
false);
635 emit newLog(
i18n(
"PHD2: Lock Position Set."));
638 newstate = CALIBRATING;
639 emit newStatus(Ekos::GUIDE_CALIBRATING);
646 emit newLog(
i18n(
"PHD2: Star Selected."));
647 emit newStatus(GUIDE_STAR_SELECT);
656 emit newLog(
i18n(
"PHD2: Dithering successful."));
659 emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS);
662 emit newLog(
i18n(
"PHD2: Guiding started."));
664 emit newStatus(Ekos::GUIDE_GUIDING);
673 emit newLog(
i18n(
"PHD2: Lock Position Lost, continuing calibration."));
679 emit newLog(
i18n(
"PHD2: Star Lost. Trying to reacquire for %1s.", Options::guideLostStarTimeout()));
680 abortTimer->
start(
static_cast<int>(Options::guideLostStarTimeout()) * 1000);
681 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout started (" << Options::guideLostStarTimeout() <<
" sec)";
682 emit newStatus(Ekos::GUIDE_REACQUIRE);
685 emit newLog(
i18n(
"PHD2: Lock Position Lost."));
691 emit newLog(
i18n(
"PHD2: Guiding paused."));
692 emit newStatus(GUIDE_SUSPENDED);
696 emit newLog(
i18n(
"PHD2: Calibrating, timing out in %1s.", Options::guideCalibrationTimeout()));
697 abortTimer->
start(
static_cast<int>(Options::guideCalibrationTimeout()) * 1000);
698 emit newStatus(GUIDE_CALIBRATING);
705 emit newLog(
i18n(
"PHD2: Calibration turned to looping, failed."));
706 emit newStatus(GUIDE_CALIBRATION_ERROR);
709 emit newLog(
i18n(
"PHD2: Looping Exposures."));
710 emit newStatus(GUIDE_LOOPING);
715 emit newLog(
i18n(
"PHD2: Dithering started."));
716 emit newStatus(GUIDE_DITHERING);
725 PHD2ResultType resultType = takeRequestFromList(jsonObj);
727 if (resultType == STAR_IMAGE)
728 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: received star image response, id" <<
729 jsonObj[
"id"].toInt();
731 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: response:" << line;
739 case CAPTURE_SINGLE_FRAME:
742 case CLEAR_CALIBRATION_COMMAND_RECEIVED:
743 emit newLog(
i18n(
"PHD2: Calibration is cleared"));
746 case DITHER_COMMAND_RECEIVED:
747 handlePHD2AppState(DITHERING);
755 case APP_STATE_RECEIVED:
757 QString state = jsonObj[
"State"].toString();
759 state = jsonObj[
"result"].toString();
761 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: received unsupported app state";
763 processPHD2State(state);
770 case IS_EQUIPMENT_CONNECTED:
772 bool isConnected = jsonObj[
"result"].toBool();
779 connection = CONNECTED;
780 setEquipmentConnected();
782 else connectEquipment(
true);
788 setEquipmentConnected();
795 connection = EQUIPMENT_DISCONNECTED;
798 else connectEquipment(
false);
801 case EQUIPMENT_CONNECTED:
806 connection = EQUIPMENT_DISCONNECTED;
807 emit newStatus(Ekos::GUIDE_DISCONNECTED);
812 case EQUIPMENT_DISCONNECTED:
815 setEquipmentConnected();
822 case GET_CURRENT_EQUIPMENT:
824 QJsonObject equipObject = jsonObj[
"result"].toObject();
825 currentCamera = equipObject[
"camera"].toObject()[
"name"].toString();
826 currentMount = equipObject[
"mount"].toObject()[
"name"].toString();
827 currentAuxMount = equipObject[
"aux_mount"].toObject()[
"name"].toString();
829 emit guideEquipmentUpdated();
837 QString mode = jsonObj[
"result"].toString();
838 Ekos::Manager::Instance()->guideModule()->updateDirectionsFromPHD2(mode);
839 emit newLog(
i18n(
"PHD2: DEC Guide Mode is Set to: %1", mode));
846 int exposurems = jsonObj[
"result"].toInt();
847 double exposureTime = exposurems / 1000.0;
848 Ekos::Manager::Instance()->guideModule()->
setExposure(exposureTime);
854 case EXPOSURE_DURATIONS:
856 QVariantList exposureListArray = jsonObj[
"result"].toArray().toVariantList();
857 logValidExposureTimes =
i18n(
"PHD2: Valid Exposure Times: Auto, ");
859 for(
int i = 1; i < exposureListArray.size();
861 values << exposureListArray.
at(i).toDouble() / 1000.0;
862 logValidExposureTimes += Ekos::Manager::Instance()->guideModule()->setRecommendedExposureValues(values);
863 emit newLog(logValidExposureTimes);
868 if(jsonObj[
"result"].toArray().count() == 2)
870 double x = jsonObj[
"result"].toArray().at(0).toDouble();
871 double y = jsonObj[
"result"].toArray().at(1).toDouble();
873 emit newStarPosition(newStarCenter,
true);
877 emit newStarPixmap(m_GuideFrame->getTrackingBoxPixmap());
886 pixelScale = jsonObj[
"result"].toDouble();
888 emit newLog(
i18n(
"PHD2: Please set CCD and telescope parameters in PHD2, Pixel Scale is invalid."));
890 emit newLog(
i18n(
"PHD2: Pixel Scale is %1 arcsec per pixel",
QString::number(pixelScale,
'f', 2)));
900 starImageRequested =
false;
901 QJsonObject jsonResult = jsonObj[
"result"].toObject();
902 processStarImage(jsonResult);
908 case GUIDE_COMMAND_RECEIVED:
909 if (0 != jsonObj[
"result"].toInt(0))
911 emit newLog(
"PHD2: Guide command was rejected.");
912 handlePHD2AppState(STOPPED);
919 handlePHD2AppState(jsonObj[
"result"].toBool() ? LOOPING : STOPPED);
925 case CONNECTION_RESULT:
926 checkIfEquipmentConnected();
929 case SET_DEC_GUIDE_MODE_COMMAND_RECEIVED:
933 case SET_EXPOSURE_COMMAND_RECEIVED:
934 requestExposureTime();
937 case SET_LOCK_POSITION:
938 handlePHD2AppState(SELECTED);
944 case SET_PAUSED_COMMAND_RECEIVED:
945 handlePHD2AppState(PAUSED);
950 case STOP_CAPTURE_COMMAND_RECEIVED:
951 handlePHD2AppState(STOPPED);
962 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: error:" << line;
964 QJsonObject jsonErrorObject = jsonError[
"error"].toObject();
966 PHD2ResultType resultType = takeRequestFromList(jsonError);
971 case SET_EXPOSURE_COMMAND_RECEIVED:
972 emit newLog(logValidExposureTimes);
976 case CONNECTION_RESULT:
977 connection = EQUIPMENT_DISCONNECTED;
978 emit newStatus(Ekos::GUIDE_DISCONNECTED);
981 case DITHER_COMMAND_RECEIVED:
984 isDitherActive =
false;
985 emit newStatus(GUIDE_DITHERING_ERROR);
987 if (Options::ditherFailAbortsAutoGuide())
990 emit newLog(
"PHD2: failing after dithering aborts.");
991 emit newStatus(GUIDE_ABORTED);
1000 case GUIDE_COMMAND_RECEIVED:
1005 emit newLog(
i18n(
"PHD2 Error: unhandled '%1'", jsonErrorObject[
"message"].
toString()));
1017 m_GuideFrame = guideView;
1020void PHD2::processStarImage(
const QJsonObject &jsonStarFrame)
1023 int width = jsonStarFrame[
"width"].toInt();
1024 int height = jsonStarFrame[
"height"].toInt();
1027 fitsfile *fptr =
nullptr;
1029 long fpixel = 1, naxis = 2, nelements, exposure;
1030 long naxes[2] = { width, height };
1031 char error_status[512] = {0};
1033 void* fits_buffer =
nullptr;
1034 size_t fits_buffer_size = 0;
1035 if (fits_create_memfile(&fptr, &fits_buffer, &fits_buffer_size, 4096, realloc, &status))
1037 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_create_file failed:" << error_status;
1041 if (fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status))
1043 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_create_img failed:" << error_status;
1045 fits_close_file(fptr, &status);
1052 fits_update_key(fptr, TLONG,
"EXPOSURE", &exposure,
"Total Exposure Time", &status);
1060 nelements = naxes[0] * naxes[1];
1061 if (fits_write_img(fptr, TUSHORT, fpixel, nelements, converted.
data(), &status))
1063 fits_get_errstatus(status, error_status);
1064 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_write_img failed:" << error_status;
1066 fits_close_file(fptr, &status);
1071 if (fits_flush_file(fptr, &status))
1073 fits_get_errstatus(status, error_status);
1074 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_flush_file failed:" << error_status;
1076 fits_close_file(fptr, &status);
1081 if (fits_close_file(fptr, &status))
1083 fits_get_errstatus(status, error_status);
1084 qCWarning(KSTARS_EKOS_GUIDE) <<
"fits_close_file failed:" << error_status;
1094 fdata->setExtension(
QString(
"fits"));
1095 fdata->loadFromBuffer(buffer);
1097 m_GuideFrame->loadData(fdata);
1099 m_GuideFrame->updateFrame();
1100 m_GuideFrame->setTrackingBox(
QRect(0, 0, width, height));
1101 emit newStarPixmap(m_GuideFrame->getTrackingBoxPixmap());
1104void PHD2::setEquipmentConnected()
1106 if (connection != EQUIPMENT_CONNECTED)
1108 setConnectedRetries = 0;
1109 connection = EQUIPMENT_CONNECTED;
1110 emit newStatus(Ekos::GUIDE_CONNECTED);
1111 updateGuideParameters();
1112 requestExposureDurations();
1113 requestCurrentEquipmentUpdate();
1117void PHD2::updateGuideParameters()
1119 if (pixelScale == 0)
1120 requestPixelScale();
1121 requestExposureTime();
1128void PHD2::captureSingleFrame()
1130 sendPHD2Request(
"capture_single_frame");
1134bool PHD2::clearCalibration()
1136 if (connection != EQUIPMENT_CONNECTED)
1138 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1139 emit newStatus(Ekos::GUIDE_ABORTED);
1146 sendPHD2Request(
"clear_calibration", args);
1152bool PHD2::dither(
double pixels)
1154 if (connection != EQUIPMENT_CONNECTED)
1156 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1157 emit newStatus(Ekos::GUIDE_ABORTED);
1163 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring dither requested while already settling";
1165 if (!isDitherActive)
1169 handlePHD2AppState(DITHERING);
1170 isDitherActive =
true;
1178 int ditherTimeout =
static_cast<int>(Options::ditherTimeout());
1180 settle.
insert(
"pixels",
static_cast<double>(Options::ditherThreshold()));
1181 settle.
insert(
"time",
static_cast<int>(Options::ditherSettle()));
1182 settle.
insert(
"timeout", ditherTimeout);
1192 isDitherActive =
true;
1200 enum { TIMEOUT_EXTRA_SECONDS = 60 };
1201 int millis = (ditherTimeout + TIMEOUT_EXTRA_SECONDS) * 1000;
1202 ditherTimer->start(millis);
1204 sendPHD2Request(
"dither", args);
1206 handlePHD2AppState(DITHERING);
1217void PHD2::requestAppState()
1219 sendPHD2Request(
"get_app_state");
1226void PHD2::checkIfEquipmentConnected()
1228 sendPHD2Request(
"get_connected");
1233void PHD2::requestCurrentEquipmentUpdate()
1235 sendPHD2Request(
"get_current_equipment");
1239void PHD2::checkDEGuideMode()
1241 sendPHD2Request(
"get_dec_guide_mode");
1245void PHD2::requestExposureTime()
1247 sendPHD2Request(
"get_exposure");
1251void PHD2::requestExposureDurations()
1253 sendPHD2Request(
"get_exposure_durations");
1257void PHD2::requestLockPosition()
1259 sendPHD2Request(
"get_lock_position");
1266void PHD2::requestPixelScale()
1268 sendPHD2Request(
"get_pixel_scale");
1277void PHD2::requestStarImage(
int size)
1279 if (starImageRequested)
1281 if (Options::verboseLogging())
1282 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: skip extra star image request";
1288 sendPHD2Request(
"get_star_image", args2);
1290 starImageRequested =
true;
1298 if (state == GUIDING)
1300 emit newLog(
i18n(
"PHD2: Guiding is already running."));
1301 emit newStatus(Ekos::GUIDE_GUIDING);
1305 if (connection != EQUIPMENT_CONNECTED)
1307 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1308 emit newStatus(Ekos::GUIDE_ABORTED);
1315 settle.
insert(
"pixels",
static_cast<double>(Options::ditherThreshold()));
1316 settle.
insert(
"time",
static_cast<int>(Options::ditherSettle()));
1317 settle.
insert(
"timeout",
static_cast<int>(Options::ditherTimeout()));
1327 sendPHD2Request(
"guide", args);
1336 sendPHD2Request(
"loop");
1342void PHD2::connectEquipment(
bool enable)
1344 if (connection == EQUIPMENT_CONNECTED && enable ==
true)
1347 if (connection == EQUIPMENT_DISCONNECTED && enable ==
false)
1350 if (setConnectedRetries++ > MAX_SET_CONNECTED_RETRIES)
1352 setConnectedRetries = 0;
1353 connection = EQUIPMENT_DISCONNECTED;
1354 emit newStatus(Ekos::GUIDE_DISCONNECTED);
1366 emit newLog(
i18n(
"PHD2: Connecting Equipment. . ."));
1368 emit newLog(
i18n(
"PHD2: Disconnecting Equipment. . ."));
1370 sendPHD2Request(
"set_connected", args);
1374void PHD2::requestSetDEGuideMode(
bool deEnabled,
bool nEnabled,
1381 if(nEnabled && sEnabled)
1395 sendPHD2Request(
"set_dec_guide_mode", args);
1399void PHD2::requestSetExposureTime(
int time)
1403 sendPHD2Request(
"set_exposure", args);
1407void PHD2::setLockPosition(
double x,
double y)
1411 args << x << y <<
false;
1412 sendPHD2Request(
"set_lock_position", args);
1420 if (connection != EQUIPMENT_CONNECTED)
1422 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1423 emit newStatus(Ekos::GUIDE_ABORTED);
1434 sendPHD2Request(
"set_paused", args);
1439 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout cancelled.";
1449 if (connection != EQUIPMENT_CONNECTED)
1451 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1452 emit newStatus(Ekos::GUIDE_ABORTED);
1461 sendPHD2Request(
"set_paused", args);
1463 if (state == LOSTLOCK)
1465 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: Lost star timeout restarted.";
1466 abortTimer->
start(
static_cast<int>(Options::guideLostStarTimeout()) * 1000);
1478 if (connection != EQUIPMENT_CONNECTED)
1480 emit newLog(
i18n(
"PHD2 Error: Equipment not connected."));
1481 emit newStatus(Ekos::GUIDE_ABORTED);
1487 sendPHD2Request(
"stop_capture");
1492bool PHD2::calibrate()
1501void PHD2::sendRpcCall(
QJsonObject &call, PHD2ResultType resultType)
1503 assert(resultType != NO_RESULT);
1504 assert(pendingRpcResultType == NO_RESULT);
1508 int rpcId = nextRpcId++;
1509 call.
insert(
"id", rpcId);
1513 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: request:" << request;
1517 qint64
const n = tcpSocket->write(request);
1519 if ((
int) n == request.
size())
1522 pendingRpcId = rpcId;
1523 pendingRpcResultType = resultType;
1527 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: unexpected short write:" << n <<
"bytes of" << request.
size();
1532void PHD2::sendNextRpcCall()
1534 if (pendingRpcResultType != NO_RESULT)
1537 if (rpcRequestQueue.empty())
1540 RpcCall &call = rpcRequestQueue.front();
1541 sendRpcCall(call.call, call.resultType);
1542 rpcRequestQueue.pop_front();
1547 assert(methodResults.
contains(method));
1549 PHD2ResultType resultType = methodResults[method];
1553 jsonRPC.
insert(
"jsonrpc",
"2.0");
1554 jsonRPC.
insert(
"method", method);
1557 jsonRPC.
insert(
"params", args);
1559 if (pendingRpcResultType == NO_RESULT)
1562 sendRpcCall(jsonRPC, resultType);
1569 if (Options::verboseLogging())
1570 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: defer call" << method;
1572 rpcRequestQueue.push_back(RpcCall(jsonRPC, resultType));
1576PHD2::PHD2ResultType PHD2::takeRequestFromList(
const QJsonObject &response)
1578 if (Q_UNLIKELY(!response.
contains(
"id")))
1580 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring unexpected response with no id";
1584 int id = response[
"id"].toInt();
1586 if (Q_UNLIKELY(
id != pendingRpcId))
1590 qCDebug(KSTARS_EKOS_GUIDE) <<
"PHD2: ignoring unexpected response with id" << id;
1594 PHD2ResultType val = pendingRpcResultType;
1595 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