diff options
Diffstat (limited to 'indi-lxd650/lxd650.cpp')
-rw-r--r-- | indi-lxd650/lxd650.cpp | 429 |
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, ¤tRA) != 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, ¤tRA) < 0 || getLX200DEC(PortFD, ¤tDEC) < 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, ¤tRA); + getLX200DEC(PortFD, ¤tDEC); + + 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; +} |