File indexing completed on 2024-07-21 06:28:24

0001 /*
0002     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include <indi/indidevice.h>
0008 
0009 #include "Options.h"
0010 
0011 #include "clientmanagerlite.h"
0012 #include "inditelescopelite.h"
0013 
0014 #include "kstarslite.h"
0015 #include "skymaplite.h"
0016 
0017 TelescopeLite::TelescopeLite(INDI::BaseDevice *device)
0018     : minAlt(-1), maxAlt(-1), IsParked(false), clientManager(KStarsLite::Instance()->clientManagerLite()),
0019       baseDevice(device), slewRateIndex(0)
0020 {
0021     setDeviceName(device->getDeviceName());
0022     //Whenever slew rate is changed (or once it was initialized) we update it
0023     connect(clientManager, &ClientManagerLite::newINDIProperty, this, &TelescopeLite::updateSlewRate);
0024     connect(clientManager, &ClientManagerLite::newINDISwitch, this, &TelescopeLite::updateSlewRate);
0025 }
0026 
0027 void TelescopeLite::updateSlewRate(const QString &deviceName, const QString &propName)
0028 {
0029     if (deviceName == baseDevice->getDeviceName() && propName == "TELESCOPE_SLEW_RATE")
0030     {
0031         auto slewRateSP = baseDevice->getSwitch("TELESCOPE_SLEW_RATE");
0032         int index = 0;
0033         for (int i = 0; i < slewRateSP->count(); ++i)
0034         {
0035             if (slewRateSP->at(i).getState() == ISS_ON)
0036             {
0037                 index = i;
0038                 break;
0039             }
0040         }
0041         m_slewRateLabels.clear();
0042         for (int i = 0; i < slewRateSP->count(); ++i)
0043         {
0044             m_slewRateLabels.push_back(slewRateSP->at(i)->getLabel());
0045         }
0046         emit slewRateUpdate(index, m_slewRateLabels.size());
0047         setSlewRate(index);
0048     }
0049 }
0050 
0051 TelescopeLite::~TelescopeLite()
0052 {
0053 }
0054 
0055 void TelescopeLite::setSlewDecreasable(bool slewDecreasable)
0056 {
0057     if (m_slewDecreasable != slewDecreasable)
0058     {
0059         m_slewDecreasable = slewDecreasable;
0060         emit slewDecreasableChanged(slewDecreasable);
0061     }
0062 }
0063 
0064 void TelescopeLite::setSlewIncreasable(bool slewIncreasable)
0065 {
0066     if (m_slewIncreasable != slewIncreasable)
0067     {
0068         m_slewIncreasable = slewIncreasable;
0069         emit slewIncreasableChanged(slewIncreasable);
0070     }
0071 }
0072 
0073 void TelescopeLite::setSlewRateLabel(const QString &slewRateLabel)
0074 {
0075     if (m_slewRateLabel != slewRateLabel)
0076     {
0077         m_slewRateLabel = slewRateLabel;
0078         emit slewRateLabelChanged(slewRateLabel);
0079     }
0080 }
0081 
0082 void TelescopeLite::setDeviceName(const QString &deviceName)
0083 {
0084     if (m_deviceName != deviceName)
0085     {
0086         m_deviceName = deviceName;
0087         emit deviceNameChanged(deviceName);
0088     }
0089 }
0090 
0091 void TelescopeLite::registerProperty(INDI::Property prop)
0092 {
0093     if (prop->isNameMatch("TELESCOPE_INFO"))
0094     {
0095         auto ti = prop->getNumber();
0096 
0097         if (!ti)
0098             return;
0099 
0100         //        bool aperture_ok=false, focal_ok=false;
0101         //        double temp=0;
0102     }
0103 
0104     if (prop->isNameMatch("TELESCOPE_PARK"))
0105     {
0106         auto svp = prop->getSwitch();
0107 
0108         if (svp)
0109         {
0110             auto sp = svp->findWidgetByName("PARK");
0111             if (sp)
0112             {
0113                 IsParked = ((sp->getState() == ISS_ON) && svp->getState() == IPS_OK);
0114             }
0115         }
0116     }
0117 }
0118 
0119 void TelescopeLite::processNumber(INumberVectorProperty *nvp)
0120 {
0121     if (!strcmp(nvp->name, "EQUATORIAL_EOD_COORD"))
0122     {
0123         INumber *RA  = IUFindNumber(nvp, "RA");
0124         INumber *DEC = IUFindNumber(nvp, "DEC");
0125 
0126         if (RA == nullptr || DEC == nullptr)
0127             return;
0128 
0129         currentCoord.setRA(RA->value);
0130         currentCoord.setDec(DEC->value);
0131 
0132         //KStarsLite::Instance()->map()->update();
0133 
0134         //emit numberUpdated(nvp);
0135 
0136         return;
0137     }
0138 
0139     if (!strcmp(nvp->name, "EQUATORIAL_COORD"))
0140     {
0141         INumber *RA  = IUFindNumber(nvp, "RA");
0142         INumber *DEC = IUFindNumber(nvp, "DEC");
0143 
0144         if (RA == nullptr || DEC == nullptr)
0145             return;
0146 
0147         currentCoord.setRA0(RA->value);
0148         currentCoord.setDec0(DEC->value);
0149         currentCoord.apparentCoord(static_cast<long double>(J2000), KStarsLite::Instance()->data()->ut().djd());
0150 
0151         //KStarsLite::Instance()->map()->update();
0152 
0153         //emit numberUpdated(nvp);
0154 
0155         return;
0156     }
0157 
0158     if (!strcmp(nvp->name, "HORIZONTAL_COORD"))
0159     {
0160         INumber *Az  = IUFindNumber(nvp, "AZ");
0161         INumber *Alt = IUFindNumber(nvp, "ALT");
0162 
0163         if (Az == nullptr || Alt == nullptr)
0164             return;
0165 
0166         currentCoord.setAz(Az->value);
0167         currentCoord.setAlt(Alt->value);
0168         currentCoord.HorizontalToEquatorial(KStarsLite::Instance()->data()->lst(),
0169                                             KStarsLite::Instance()->data()->geo()->lat());
0170 
0171         //KStarsLite::Instance()->map()->update();
0172 
0173         //emit numberUpdated(nvp);
0174 
0175         return;
0176     }
0177 
0178     //DeviceDecorator::processNumber(nvp);
0179 }
0180 
0181 void TelescopeLite::processSwitch(ISwitchVectorProperty *svp)
0182 {
0183     Q_UNUSED(svp);
0184     /*if (!strcmp(svp->name, "TELESCOPE_PARK"))
0185     {
0186         ISwitch *sp = IUFindSwitch(svp, "PARK");
0187         if (sp)
0188         {
0189             IsParked = ( (sp->s == ISS_ON) && svp->s == IPS_OK);
0190         }
0191 
0192         //emit switchUpdated(svp);
0193 
0194         return;
0195 
0196     }*/
0197 }
0198 
0199 bool TelescopeLite::canGuide()
0200 {
0201     auto raPulse  = baseDevice->getNumber("TELESCOPE_TIMED_GUIDE_WE");
0202     auto decPulse = baseDevice->getNumber("TELESCOPE_TIMED_GUIDE_NS");
0203 
0204     return raPulse && decPulse;
0205 }
0206 
0207 bool TelescopeLite::canSync()
0208 {
0209     auto motionSP = baseDevice->getSwitch("ON_COORD_SET");
0210 
0211     if (!motionSP)
0212         return false;
0213 
0214     auto syncSW = motionSP->findWidgetByName("SYNC");
0215 
0216     return (syncSW != nullptr);
0217 }
0218 
0219 bool TelescopeLite::canPark()
0220 {
0221     auto parkSP = baseDevice->getSwitch("TELESCOPE_PARK");
0222 
0223     if (!parkSP)
0224         return false;
0225 
0226     auto parkSW = parkSP->findWidgetByName("PARK");
0227 
0228     return (parkSW != nullptr);
0229 }
0230 
0231 bool TelescopeLite::isSlewing()
0232 {
0233     auto EqProp = baseDevice->getNumber("EQUATORIAL_EOD_COORD");
0234     if (!EqProp)
0235         return false;
0236 
0237     return (EqProp->getState() == IPS_BUSY);
0238 }
0239 
0240 bool TelescopeLite::isInMotion()
0241 {
0242     bool inMotion                     = false;
0243     bool inSlew                       = isSlewing();
0244 
0245     auto movementSP = baseDevice->getSwitch("TELESCOPE_MOTION_NS");
0246     if (movementSP)
0247         inMotion = (movementSP->getState() == IPS_BUSY);
0248 
0249     movementSP = baseDevice->getSwitch("TELESCOPE_MOTION_WE");
0250     if (movementSP)
0251         inMotion = ((movementSP->getState() == IPS_BUSY) || inMotion);
0252 
0253     return (inSlew || inMotion);
0254 }
0255 
0256 bool TelescopeLite::sendCoords(SkyPoint *ScopeTarget)
0257 {
0258     INumber *RAEle                 = nullptr;
0259     INumber *DecEle                = nullptr;
0260     INumber *AzEle                 = nullptr;
0261     INumber *AltEle                = nullptr;
0262     double currentRA = 0, currentDEC = 0, currentAlt = 0, currentAz = 0, targetAlt = 0;
0263     bool useJ2000(false);
0264 
0265     auto EqProp = baseDevice->getNumber("EQUATORIAL_EOD_COORD");
0266     if (!EqProp)
0267     {
0268         // J2000 Property
0269         EqProp = baseDevice->getNumber("EQUATORIAL_COORD");
0270         if (EqProp)
0271             useJ2000 = true;
0272     }
0273 
0274     auto HorProp = baseDevice->getNumber("HORIZONTAL_COORD");
0275 
0276     if (EqProp && EqProp->getPermission() == IP_RO)
0277         EqProp = nullptr;
0278 
0279     if (HorProp && HorProp->getPermission() == IP_RO)
0280         HorProp = nullptr;
0281 
0282     //qDebug() << "Skymap click - RA: " << scope_target->ra().toHMSString() << " DEC: " << scope_target->dec().toDMSString();
0283 
0284     if (EqProp)
0285     {
0286         RAEle = IUFindNumber(EqProp, "RA");
0287         if (!RAEle)
0288             return false;
0289         DecEle = IUFindNumber(EqProp, "DEC");
0290         if (!DecEle)
0291             return false;
0292 
0293         //if (useJ2000)
0294             //ScopeTarget->apparentCoord( KStars::Instance()->data()->ut().djd(), static_cast<long double>(J2000));
0295 
0296         currentRA  = RAEle->value;
0297         currentDEC = DecEle->value;
0298 
0299         ScopeTarget->EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
0300     }
0301 
0302     if (HorProp)
0303     {
0304         AzEle = IUFindNumber(HorProp, "AZ");
0305         if (!AzEle)
0306             return false;
0307         AltEle = IUFindNumber(HorProp, "ALT");
0308         if (!AltEle)
0309             return false;
0310 
0311         currentAz  = AzEle->value;
0312         currentAlt = AltEle->value;
0313     }
0314 
0315     /* Could not find either properties! */
0316     if (EqProp == nullptr && HorProp == nullptr)
0317         return false;
0318 
0319     //targetAz = ScopeTarget->az().Degrees();
0320     targetAlt = ScopeTarget->altRefracted().Degrees();
0321     if (targetAlt < 0)
0322     {
0323        return false;
0324     }
0325 
0326     if (EqProp)
0327     {
0328         dms ra, de;
0329 
0330         if (useJ2000)
0331         {
0332             // If we have invalid DEC, then convert coords to J2000
0333             if (ScopeTarget->dec0().Degrees() == 180.0)
0334             {
0335                ScopeTarget->setRA0(ScopeTarget->ra());
0336                ScopeTarget->setDec0(ScopeTarget->dec());
0337                ScopeTarget->apparentCoord( KStarsLite::Instance()->data()->ut().djd(), static_cast<long double>(J2000));
0338                ra = ScopeTarget->ra();
0339                de = ScopeTarget->dec();
0340             }
0341             else
0342             {
0343                 ra = ScopeTarget->ra0();
0344                 de = ScopeTarget->dec0();
0345             }
0346         }
0347         else
0348         {
0349             ra = ScopeTarget->ra();
0350             de = ScopeTarget->dec();
0351         }
0352 
0353         RAEle->value  = ra.Hours();
0354         DecEle->value = de.Degrees();
0355         clientManager->sendNewNumber(EqProp);
0356 
0357         RAEle->value  = currentRA;
0358         DecEle->value = currentDEC;
0359     }
0360     // Only send Horizontal Coord property if Equatorial is not available.
0361     else if (HorProp)
0362     {
0363         AzEle->value  = ScopeTarget->az().Degrees();
0364         AltEle->value = ScopeTarget->alt().Degrees();
0365         clientManager->sendNewNumber(HorProp);
0366         AzEle->value  = currentAz;
0367         AltEle->value = currentAlt;
0368     }
0369 
0370     return true;
0371 }
0372 
0373 bool TelescopeLite::slew(double ra, double dec)
0374 {
0375     SkyPoint target;
0376 
0377     target.setRA(ra);
0378     target.setDec(dec);
0379 
0380     return slew(&target);
0381 }
0382 
0383 bool TelescopeLite::slew(SkyPoint *ScopeTarget)
0384 {
0385     auto motionSP = baseDevice->getSwitch("ON_COORD_SET");
0386 
0387     if (!motionSP)
0388         return false;
0389 
0390     auto slewSW = motionSP->findWidgetByName("TRACK");
0391 
0392     if (!slewSW)
0393         slewSW = motionSP->findWidgetByName("SLEW");
0394 
0395     if (!slewSW)
0396         return false;
0397 
0398     if (slewSW->setState() != ISS_ON)
0399     {
0400         motionSP->reset();
0401         slewSW->setState(ISS_ON);
0402         clientManager->sendNewSwitch(motionSP);
0403 
0404         if (Options::iNDILogging())
0405             qDebug() << "ISD:Telescope: " << slewSW->getName();
0406     }
0407 
0408     return sendCoords(ScopeTarget);
0409 }
0410 
0411 bool TelescopeLite::sync(double ra, double dec)
0412 {
0413     SkyPoint target;
0414 
0415     target.setRA(ra);
0416     target.setDec(dec);
0417 
0418     return sync(&target);
0419 }
0420 
0421 bool TelescopeLite::sync(SkyPoint *ScopeTarget)
0422 {
0423     auto motionSP = baseDevice->getSwitch("ON_COORD_SET");
0424 
0425     if (!motionSP)
0426         return false;
0427 
0428     auto syncSW = motionSP->findWidgetByName("SYNC");
0429 
0430     if (!syncSW)
0431         return false;
0432 
0433     if (syncSW->getState() != ISS_ON)
0434     {
0435         motionSP->reset();
0436         syncSW->setState(ISS_ON);
0437         clientManager->sendNewSwitch(motionSP);
0438 
0439         if (Options::iNDILogging())
0440             qDebug() << "ISD:Telescope: Syncing...";
0441     }
0442 
0443     return sendCoords(ScopeTarget);
0444 }
0445 
0446 bool TelescopeLite::abort()
0447 {
0448     auto motionSP = baseDevice->getSwitch("TELESCOPE_ABORT_MOTION");
0449 
0450     if (!motionSP)
0451         return false;
0452 
0453     auto abortSW = motionSP->findWidgetByName("ABORT");
0454 
0455     if (!abortSW)
0456         return false;
0457 
0458     if (Options::iNDILogging())
0459         qDebug() << "ISD:Telescope: Aborted." << endl;
0460 
0461     abortSW->setState(ISS_ON);
0462     clientManager->sendNewSwitch(motionSP);
0463 
0464     return true;
0465 }
0466 
0467 bool TelescopeLite::park()
0468 {
0469     auto parkSP = baseDevice->getSwitch("TELESCOPE_PARK");
0470 
0471     if (!parkSP)
0472         return false;
0473 
0474     auto parkSW = parkSP->findWidgetByName("PARK");
0475 
0476     if (!parkSW)
0477         return false;
0478 
0479     if (Options::iNDILogging())
0480         qDebug() << "ISD:Telescope: Parking..." << endl;
0481 
0482     parkSP->reset();
0483     parkSW->setState(ISS_ON);
0484     clientManager->sendNewSwitch(parkSP);
0485 
0486     return true;
0487 }
0488 
0489 bool TelescopeLite::unPark()
0490 {
0491     auto parkSP = baseDevice->getSwitch("TELESCOPE_PARK");
0492 
0493     if (!parkSP)
0494         return false;
0495 
0496     auto parkSW = parkSP->findWidgetByName("UNPARK");
0497 
0498     if (!parkSW)
0499         return false;
0500 
0501     if (Options::iNDILogging())
0502         qDebug() << "ISD:Telescope: UnParking..." << endl;
0503 
0504     parkSP->reset();
0505     parkSW->setState(ISS_ON);
0506     clientManager->sendNewSwitch(parkSP);
0507 
0508     return true;
0509 }
0510 
0511 bool TelescopeLite::getEqCoords(double *ra, double *dec)
0512 {
0513     auto EqProp = baseDevice->getNumber("EQUATORIAL_EOD_COORD");
0514 
0515     if (!EqProp)
0516         return false;
0517 
0518     auto RAEle = EqProp->findWidgetByName("RA");
0519     if (!RAEle)
0520         return false;
0521 
0522     auto DecEle = EqProp->findWidgetByName("DEC");
0523     if (!DecEle)
0524         return false;
0525 
0526     *ra  = RAEle->getValue();
0527     *dec = DecEle->getValue();
0528 
0529     return true;
0530 }
0531 
0532 bool TelescopeLite::moveNS(TelescopeMotionNS dir, TelescopeMotionCommand cmd)
0533 {
0534     auto motionSP = baseDevice->getSwitch("TELESCOPE_MOTION_NS");
0535 
0536     if (!motionSP)
0537         return false;
0538 
0539     auto motionNorth = motionSP->findWidgetByName("MOTION_NORTH");
0540     auto motionSouth = motionSP->findWidgetByName("MOTION_SOUTH");
0541 
0542     if (!motionNorth || !motionSouth)
0543         return false;
0544 
0545     // If same direction, return
0546     if (dir == MOTION_NORTH && motionNorth->getState() == ((cmd == MOTION_START) ? ISS_ON : ISS_OFF))
0547         return true;
0548 
0549     if (dir == MOTION_SOUTH && motionSouth->getState() == ((cmd == MOTION_START) ? ISS_ON : ISS_OFF))
0550         return true;
0551 
0552     motionSP->reset();
0553 
0554     if (cmd == MOTION_START)
0555     {
0556         if (dir == MOTION_NORTH)
0557             motionNorth->setState(ISS_ON);
0558         else
0559             motionSouth->setState(ISS_ON);
0560     }
0561 
0562     if (cmd == MOTION_STOP)
0563     {
0564         if (dir == MOTION_NORTH)
0565             motionNorth->setState(ISS_OFF);
0566         else
0567             motionSouth->setState(ISS_OFF);
0568     }
0569 
0570     clientManager->sendNewSwitch(motionSP);
0571 
0572     return true;
0573 }
0574 
0575 bool TelescopeLite::moveWE(TelescopeMotionWE dir, TelescopeMotionCommand cmd)
0576 {
0577     auto motionSP = baseDevice->getSwitch("TELESCOPE_MOTION_WE");
0578 
0579     if (motionSP == nullptr)
0580         return false;
0581 
0582     auto motionWest = motionSP->findWidgetByName("MOTION_WEST");
0583     auto motionEast = motionSP->findWidgetByName("MOTION_EAST");
0584 
0585     if (motionWest == nullptr || motionEast == nullptr)
0586         return false;
0587 
0588     // If same direction, return
0589     if (dir == MOTION_WEST && motionWest->getState() == ((cmd == MOTION_START) ? ISS_ON : ISS_OFF))
0590         return true;
0591 
0592     if (dir == MOTION_EAST && motionEast->getState() == ((cmd == MOTION_START) ? ISS_ON : ISS_OFF))
0593         return true;
0594 
0595     IUResetSwitch(motionSP);
0596 
0597     if (cmd == MOTION_START)
0598     {
0599         if (dir == MOTION_WEST)
0600             motionWest->setState(ISS_ON);
0601         else
0602             motionEast->setState(ISS_ON);
0603     }
0604 
0605     if (cmd == MOTION_STOP)
0606     {
0607         if (dir == MOTION_WEST)
0608             motionWest->setState(ISS_OFF);
0609         else
0610             motionEast->setState(ISS_OFF);
0611     }
0612 
0613     clientManager->sendNewSwitch(motionSP);
0614 
0615     return true;
0616 }
0617 
0618 bool TelescopeLite::setSlewRate(int index)
0619 {
0620     auto slewRateSP = baseDevice->getSwitch("TELESCOPE_SLEW_RATE");
0621 
0622     if (slewRateSP == nullptr)
0623         return false;
0624 
0625     int maxSlewRate = slewRateSP->count();
0626 
0627     if (index < 0)
0628     {
0629         index = 0;
0630     }
0631     else if (index >= maxSlewRate)
0632     {
0633         index = maxSlewRate - 1;
0634     }
0635 
0636     if (slewRateSP->at(index)->getState() != ISS_ON || index != slewRateIndex)
0637     {
0638         slewRateSP->reset();
0639 
0640         slewRateSP->at(index)->setState(ISS_ON);
0641 
0642         slewRateIndex = index;
0643         setSlewRateLabel(slewRateSP->at(index)->getLabel());
0644         setSlewDecreasable(index != 0);
0645         setSlewIncreasable(index != maxSlewRate - 1);
0646 
0647         clientManager->sendNewSwitch(slewRateSP);
0648     }
0649 
0650     return true;
0651 }
0652 
0653 bool TelescopeLite::decreaseSlewRate()
0654 {
0655     return setSlewRate(slewRateIndex - 1);
0656 }
0657 
0658 bool TelescopeLite::increaseSlewRate()
0659 {
0660     return setSlewRate(slewRateIndex + 1);
0661 }
0662 
0663 void TelescopeLite::setAltLimits(double minAltitude, double maxAltitude)
0664 {
0665     minAlt = minAltitude;
0666     maxAlt = maxAltitude;
0667 }
0668 
0669 bool TelescopeLite::isParked()
0670 {
0671     return IsParked;
0672 }