summaryrefslogtreecommitdiffstats
path: root/indi-lxd650/lxd650.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indi-lxd650/lxd650.cpp')
-rw-r--r--indi-lxd650/lxd650.cpp429
1 files changed, 429 insertions, 0 deletions
diff --git a/indi-lxd650/lxd650.cpp b/indi-lxd650/lxd650.cpp
new file mode 100644
index 0000000..1e0c4a4
--- /dev/null
+++ b/indi-lxd650/lxd650.cpp
@@ -0,0 +1,429 @@
+#if 0
+LX200 Basic Driver
+Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+This library is free software;
+you can redistribute it and / or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation;
+either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY;
+without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library;
+if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
+
+#endif
+
+#include "lxd650.h"
+
+#include "indicom.h"
+#include "lx200driver.h"
+
+#include <libnova/sidereal_time.h>
+#include <alignment/DriverCommon.h>
+
+#include <cmath>
+#include <memory>
+#include <cstring>
+#include <unistd.h>
+
+
+using namespace INDI::AlignmentSubsystem;
+
+/* Simulation Parameters */
+#define SLEWRATE 1 /* slew rate, degrees/s */
+#define SIDRATE 0.004178 /* sidereal rate, degrees/s */
+
+/* Our telescope auto pointer */
+static std::unique_ptr<LXD650> telescope(new LXD650());
+
+/**************************************************************************************
+** LX200 Basic constructor
+***************************************************************************************/
+LXD650::LXD650()
+{
+ setVersion(2, 1);
+
+ DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE");
+
+ SetTelescopeCapability(TELESCOPE_CAN_SYNC | TELESCOPE_CAN_GOTO | TELESCOPE_CAN_ABORT, 4);
+
+ LOG_DEBUG("Initializing from LX200 Basic device...");
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LXD650::debugTriggered(bool enable)
+{
+ INDI_UNUSED(enable);
+ setLX200Debug(getDeviceName(), DBG_SCOPE);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+const char *LXD650::getDefaultName()
+{
+ return "LX200 Basic";
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::initProperties()
+{
+ /* Make sure to init parent properties first */
+ INDI::Telescope::initProperties();
+
+ // Slew threshold
+ IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+ IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+ IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), getDeviceName(), "Slew Accuracy", "",
+ OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
+
+ addAuxControls();
+
+ currentRA = get_local_sidereal_time(LocationN[LOCATION_LONGITUDE].value);
+ currentDEC = LocationN[LOCATION_LATITUDE].value > 0 ? 90 : -90;
+
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::updateProperties()
+{
+ INDI::Telescope::updateProperties();
+
+ if (isConnected())
+ {
+ defineProperty(&SlewAccuracyNP);
+
+ // We don't support NSWE controls
+ deleteProperty(MovementNSSP.name);
+ deleteProperty(MovementWESP.name);
+
+ getBasicData();
+ }
+ else
+ {
+ deleteProperty(SlewAccuracyNP.name);
+ }
+
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::Handshake()
+{
+ if (getLX200RA(PortFD, &currentRA) != 0)
+ {
+ LOG_ERROR("Error communication with telescope.");
+ return false;
+ }
+
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::isSlewComplete()
+{
+ const double dx = targetRA - currentRA;
+ const double dy = targetDEC - currentDEC;
+ return fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::ReadScopeStatus()
+{
+ if (!isConnected())
+ return false;
+
+ if (isSimulation())
+ {
+ mountSim();
+ return true;
+ }
+
+ if (getLX200RA(PortFD, &currentRA) < 0 || getLX200DEC(PortFD, &currentDEC) < 0)
+ {
+ EqNP.s = IPS_ALERT;
+ IDSetNumber(&EqNP, "Error reading RA/DEC.");
+ return false;
+ }
+
+ if (TrackState == SCOPE_SLEWING)
+ {
+ // Check if LX200 is done slewing
+ if (isSlewComplete())
+ {
+ TrackState = SCOPE_TRACKING;
+ LOG_INFO("Slew is complete. Tracking...");
+ }
+ }
+
+ NewRaDec(currentRA, currentDEC);
+
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::Goto(double r, double d)
+{
+ targetRA = r;
+ targetDEC = d;
+ char RAStr[64] = {0}, DecStr[64] = {0};
+
+ fs_sexa(RAStr, targetRA, 2, 3600);
+ fs_sexa(DecStr, targetDEC, 2, 3600);
+
+ // If moving, let's stop it first.
+ if (EqNP.s == IPS_BUSY)
+ {
+ if (!isSimulation() && abortSlew(PortFD) < 0)
+ {
+ AbortSP.s = IPS_ALERT;
+ IDSetSwitch(&AbortSP, "Abort slew failed.");
+ return false;
+ }
+
+ AbortSP.s = IPS_OK;
+ EqNP.s = IPS_IDLE;
+ IDSetSwitch(&AbortSP, "Slew aborted.");
+ IDSetNumber(&EqNP, nullptr);
+
+ // sleep for 100 mseconds
+ usleep(100000);
+ }
+
+ if (!isSimulation())
+ {
+ if (setObjectRA(PortFD, targetRA) < 0 || (setObjectDEC(PortFD, targetDEC)) < 0)
+ {
+ EqNP.s = IPS_ALERT;
+ IDSetNumber(&EqNP, "Error setting RA/DEC.");
+ return false;
+ }
+
+ int err = 0;
+
+ /* Slew reads the '0', that is not the end of the slew */
+ if ((err = Slew(PortFD)))
+ {
+ EqNP.s = IPS_ALERT;
+ IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+ slewError(err);
+ return false;
+ }
+ }
+
+ TrackState = SCOPE_SLEWING;
+ //EqNP.s = IPS_BUSY;
+
+ LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::Sync(double ra, double dec)
+{
+ char syncString[256] = {0};
+
+ if (!isSimulation() && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0))
+ {
+ EqNP.s = IPS_ALERT;
+ IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync.");
+ return false;
+ }
+
+ if (!isSimulation() && ::Sync(PortFD, syncString) < 0)
+ {
+ EqNP.s = IPS_ALERT;
+ IDSetNumber(&EqNP, "Synchronization failed.");
+ return false;
+ }
+
+ currentRA = ra;
+ currentDEC = dec;
+
+ LOG_INFO("Synchronization successful.");
+
+ EqNP.s = IPS_OK;
+
+ NewRaDec(currentRA, currentDEC);
+
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
+{
+ if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
+ {
+ if (!strcmp(name, SlewAccuracyNP.name))
+ {
+ if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
+ return false;
+
+ SlewAccuracyNP.s = IPS_OK;
+
+ if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
+ IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
+
+ IDSetNumber(&SlewAccuracyNP, nullptr);
+ return true;
+ }
+ }
+
+ return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::Abort()
+{
+ if (!isSimulation() && abortSlew(PortFD) < 0)
+ {
+ LOG_ERROR("Failed to abort slew.");
+ return false;
+ }
+
+ EqNP.s = IPS_IDLE;
+ TrackState = SCOPE_IDLE;
+ IDSetNumber(&EqNP, nullptr);
+
+ LOG_INFO("Slew aborted.");
+ return true;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LXD650::getBasicData()
+{
+ // Make sure short
+ checkLX200EquatorialFormat(PortFD);
+
+ // Get current RA/DEC
+ getLX200RA(PortFD, &currentRA);
+ getLX200DEC(PortFD, &currentDEC);
+
+ IDSetNumber(&EqNP, nullptr);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LXD650::mountSim()
+{
+ static struct timeval ltv;
+ struct timeval tv;
+ double dt, da, dx;
+ int nlocked;
+
+ /* update elapsed time since last poll, don't presume exactly POLLMS */
+ gettimeofday(&tv, nullptr);
+
+ if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
+ ltv = tv;
+
+ dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
+ ltv = tv;
+ da = SLEWRATE * dt;
+
+ /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
+ switch (TrackState)
+ {
+ case SCOPE_TRACKING:
+ /* RA moves at sidereal, Dec stands still */
+ currentRA += (SIDRATE * dt / 15.);
+ break;
+
+ case SCOPE_SLEWING:
+ /* slewing - nail it when both within one pulse @ SLEWRATE */
+ nlocked = 0;
+
+ dx = targetRA - currentRA;
+
+ if (fabs(dx) <= da)
+ {
+ currentRA = targetRA;
+ nlocked++;
+ }
+ else if (dx > 0)
+ currentRA += da / 15.;
+ else
+ currentRA -= da / 15.;
+
+ dx = targetDEC - currentDEC;
+ if (fabs(dx) <= da)
+ {
+ currentDEC = targetDEC;
+ nlocked++;
+ }
+ else if (dx > 0)
+ currentDEC += da;
+ else
+ currentDEC -= da;
+
+ if (nlocked == 2)
+ {
+ TrackState = SCOPE_TRACKING;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ NewRaDec(currentRA, currentDEC);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LXD650::slewError(int slewCode)
+{
+ EqNP.s = IPS_ALERT;
+
+ if (slewCode == 1)
+ IDSetNumber(&EqNP, "Object below horizon.");
+ else if (slewCode == 2)
+ IDSetNumber(&EqNP, "Object below the minimum elevation limit.");
+ else
+ IDSetNumber(&EqNP, "Slew failed.");
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LXD650::saveConfigItems(FILE *fp)
+{
+ INDI::Telescope::saveConfigItems(fp);
+ IUSaveConfigNumber(fp, &SlewAccuracyNP);
+ return true;
+}