File indexing completed on 2025-04-27 03:32:49
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 }