File indexing completed on 2024-04-21 03:44:07
0001 /* 0002 SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <basedevice.h> 0008 #include <KActionCollection> 0009 #include <KNotification> 0010 #include <QAction> 0011 #include <qdbusmetatype.h> 0012 0013 #include "indidome.h" 0014 #include "kstars.h" 0015 #include "domeadaptor.h" 0016 0017 namespace ISD 0018 { 0019 0020 const QList<const char *> Dome::domeStates = { I18N_NOOP("Idle"), I18N_NOOP("Moving clockwise"), I18N_NOOP("Moving counter clockwise"), 0021 I18N_NOOP("Tracking"), I18N_NOOP("Parking"), I18N_NOOP("UnParking"), I18N_NOOP("Parked"), 0022 I18N_NOOP("Error") 0023 }; 0024 0025 Dome::Dome(GenericDevice *parent) : ConcreteDevice(parent) 0026 { 0027 qRegisterMetaType<ISD::Dome::Status>("ISD::Dome::Status"); 0028 qDBusRegisterMetaType<ISD::Dome::Status>(); 0029 0030 qRegisterMetaType<ISD::Dome::ShutterStatus>("ISD::Dome::ShutterStatus"); 0031 qDBusRegisterMetaType<ISD::Dome::ShutterStatus>(); 0032 0033 new DomeAdaptor(this); 0034 m_DBusObjectPath = QString("/KStars/INDI/Dome/%1").arg(getID()); 0035 QDBusConnection::sessionBus().registerObject(m_DBusObjectPath, this); 0036 } 0037 0038 void Dome::registerProperty(INDI::Property prop) 0039 { 0040 if (!prop.getRegistered()) 0041 return; 0042 0043 if (prop.isNameMatch("ABS_DOME_POSITION")) 0044 { 0045 m_CanAbsMove = true; 0046 } 0047 else if (prop.isNameMatch("REL_DOME_POSITION")) 0048 { 0049 m_CanRelMove = true; 0050 } 0051 else if (prop.isNameMatch("DOME_ABORT_MOTION")) 0052 { 0053 m_CanAbort = true; 0054 } 0055 else if (prop.isNameMatch("DOME_SHUTTER")) 0056 { 0057 m_HasShutter = true; 0058 } 0059 0060 ConcreteDevice::registerProperty(prop); 0061 } 0062 0063 void Dome::processNumber(INDI::Property prop) 0064 { 0065 auto nvp = prop.getNumber(); 0066 if (nvp->isNameMatch("ABS_DOME_POSITION")) 0067 { 0068 emit positionChanged(nvp->at(0)->getValue()); 0069 } 0070 } 0071 0072 void Dome::processSwitch(INDI::Property prop) 0073 { 0074 auto svp = prop.getSwitch(); 0075 if (svp->isNameMatch("CONNECTION")) 0076 { 0077 auto conSP = svp->findWidgetByName("CONNECT"); 0078 if (conSP) 0079 { 0080 if (conSP->getState() == ISS_ON) 0081 KStars::Instance()->slotSetDomeEnabled(true); 0082 else 0083 { 0084 KStars::Instance()->slotSetDomeEnabled(false); 0085 0086 m_CanAbsMove = false; 0087 m_CanPark = false; 0088 } 0089 } 0090 } 0091 else if (svp->isNameMatch("DOME_PARK")) 0092 { 0093 m_CanPark = true; 0094 0095 auto sp = svp->findWidgetByName("PARK"); 0096 if (sp) 0097 { 0098 if (svp->getState() == IPS_ALERT) 0099 { 0100 m_ParkStatus = PARK_ERROR; 0101 emit newParkStatus(PARK_ERROR); 0102 0103 // If alert, set park status to whatever it was opposite to. That is, if it was parking and failed 0104 // then we set status to unparked since it did not successfully complete parking. 0105 // if (m_ParkStatus == PARK_PARKING) 0106 // m_ParkStatus = PARK_UNPARKED; 0107 // else if (m_ParkStatus == PARK_UNPARKING) 0108 // m_ParkStatus = PARK_PARKED; 0109 0110 // emit newParkStatus(m_ParkStatus); 0111 0112 } 0113 else if (svp->getState() == IPS_BUSY && sp->getState() == ISS_ON && m_ParkStatus != PARK_PARKING) 0114 { 0115 m_ParkStatus = PARK_PARKING; 0116 KNotification::event(QLatin1String("DomeParking"), i18n("Dome parking is in progress")); 0117 emit newParkStatus(m_ParkStatus); 0118 0119 if (m_Status != DOME_PARKING) 0120 { 0121 m_Status = DOME_PARKING; 0122 emit newStatus(m_Status); 0123 } 0124 } 0125 else if (svp->getState() == IPS_BUSY && sp->getState() == ISS_OFF && m_ParkStatus != PARK_UNPARKING) 0126 { 0127 m_ParkStatus = PARK_UNPARKING; 0128 KNotification::event(QLatin1String("DomeUnparking"), i18n("Dome unparking is in progress")); 0129 emit newParkStatus(m_ParkStatus); 0130 0131 if (m_Status != DOME_UNPARKING) 0132 { 0133 m_Status = DOME_UNPARKING; 0134 emit newStatus(m_Status); 0135 } 0136 } 0137 else if (svp->getState() == IPS_OK && sp->getState() == ISS_ON && m_ParkStatus != PARK_PARKED) 0138 { 0139 m_ParkStatus = PARK_PARKED; 0140 KNotification::event(QLatin1String("DomeParked"), i18n("Dome parked")); 0141 emit newParkStatus(m_ParkStatus); 0142 0143 QAction *parkAction = KStars::Instance()->actionCollection()->action("dome_park"); 0144 if (parkAction) 0145 parkAction->setEnabled(false); 0146 QAction *unParkAction = KStars::Instance()->actionCollection()->action("dome_unpark"); 0147 if (unParkAction) 0148 unParkAction->setEnabled(true); 0149 0150 if (m_Status != DOME_PARKED) 0151 { 0152 m_Status = DOME_PARKED; 0153 emit newStatus(m_Status); 0154 } 0155 0156 } 0157 else if ( (svp->getState() == IPS_OK || svp->getState() == IPS_IDLE) && sp->s == ISS_OFF && m_ParkStatus != PARK_UNPARKED) 0158 { 0159 m_ParkStatus = PARK_UNPARKED; 0160 KNotification::event(QLatin1String("DomeUnparked"), i18n("Dome unparked")); 0161 0162 QAction *parkAction = KStars::Instance()->actionCollection()->action("dome_park"); 0163 if (parkAction) 0164 parkAction->setEnabled(true); 0165 QAction *unParkAction = KStars::Instance()->actionCollection()->action("dome_unpark"); 0166 if (unParkAction) 0167 unParkAction->setEnabled(false); 0168 0169 emit newParkStatus(m_ParkStatus); 0170 0171 if (m_Status != DOME_IDLE) 0172 { 0173 m_Status = DOME_IDLE; 0174 emit newStatus(m_Status); 0175 } 0176 } 0177 } 0178 } 0179 else if (svp->isNameMatch("DOME_MOTION")) 0180 { 0181 Status lastStatus = m_Status; 0182 0183 if (svp->getState() == IPS_BUSY && lastStatus != DOME_MOVING_CW && lastStatus != DOME_MOVING_CCW 0184 && lastStatus != DOME_PARKING 0185 && lastStatus != DOME_UNPARKING) 0186 { 0187 m_Status = svp->at(0)->getState() == ISS_ON ? DOME_MOVING_CW : DOME_MOVING_CCW; 0188 emit newStatus(m_Status); 0189 0190 // rolloff roofs: cw = opening = unparking, ccw = closing = parking 0191 if (!canAbsoluteMove() && !canRelativeMove()) 0192 { 0193 m_ParkStatus = (m_Status == DOME_MOVING_CW) ? PARK_UNPARKING : PARK_PARKING; 0194 emit newParkStatus(m_ParkStatus); 0195 } 0196 } 0197 else if (svp->getState() == IPS_OK && (lastStatus == DOME_MOVING_CW || lastStatus == DOME_MOVING_CCW)) 0198 { 0199 m_Status = DOME_TRACKING; 0200 emit newStatus(m_Status); 0201 } 0202 else if (svp->getState() == IPS_IDLE && lastStatus != DOME_IDLE) 0203 { 0204 m_Status = DOME_IDLE; 0205 emit newStatus(m_Status); 0206 } 0207 else if (svp->getState() == IPS_ALERT) 0208 { 0209 m_Status = DOME_ERROR; 0210 emit newStatus(m_Status); 0211 } 0212 } 0213 else if (svp->isNameMatch("DOME_SHUTTER")) 0214 { 0215 if (svp->getState() == IPS_ALERT) 0216 { 0217 emit newShutterStatus(SHUTTER_ERROR); 0218 0219 // If alert, set shutter status to whatever it was opposite to. That is, if it was opening and failed 0220 // then we set status to closed since it did not successfully complete opening. 0221 if (m_ShutterStatus == SHUTTER_CLOSING) 0222 m_ShutterStatus = SHUTTER_OPEN; 0223 else 0224 m_ShutterStatus = SHUTTER_CLOSED; 0225 0226 emit newShutterStatus(m_ShutterStatus); 0227 } 0228 0229 ShutterStatus status = parseShutterStatus(prop); 0230 0231 switch (status) 0232 { 0233 case SHUTTER_CLOSING: 0234 if (m_ShutterStatus != SHUTTER_CLOSING) 0235 { 0236 m_ShutterStatus = SHUTTER_CLOSING; 0237 KNotification::event(QLatin1String("ShutterClosing"), i18n("Shutter closing is in progress")); 0238 emit newShutterStatus(m_ShutterStatus); 0239 } 0240 break; 0241 case SHUTTER_OPENING: 0242 if (m_ShutterStatus != SHUTTER_OPENING) 0243 { 0244 m_ShutterStatus = SHUTTER_OPENING; 0245 KNotification::event(QLatin1String("ShutterOpening"), i18n("Shutter opening is in progress")); 0246 emit newShutterStatus(m_ShutterStatus); 0247 } 0248 break; 0249 case SHUTTER_CLOSED: 0250 if (m_ShutterStatus != SHUTTER_CLOSED) 0251 { 0252 m_ShutterStatus = SHUTTER_CLOSED; 0253 KNotification::event(QLatin1String("ShutterClosed"), i18n("Shutter closed")); 0254 emit newShutterStatus(m_ShutterStatus); 0255 } 0256 break; 0257 case SHUTTER_OPEN: 0258 if (m_ShutterStatus != SHUTTER_OPEN) 0259 { 0260 m_ShutterStatus = SHUTTER_OPEN; 0261 KNotification::event(QLatin1String("ShutterOpened"), i18n("Shutter opened")); 0262 emit newShutterStatus(m_ShutterStatus); 0263 } 0264 break; 0265 default: 0266 break; 0267 } 0268 0269 return; 0270 0271 } 0272 else if (svp->isNameMatch("DOME_AUTOSYNC")) 0273 { 0274 auto sp = svp->findWidgetByName("DOME_AUTOSYNC_ENABLE"); 0275 if (sp != nullptr) 0276 emit newAutoSyncStatus(sp->s == ISS_ON); 0277 } 0278 } 0279 0280 bool Dome::abort() 0281 { 0282 if (m_CanAbort == false) 0283 return false; 0284 0285 auto motionSP = getSwitch("DOME_ABORT_MOTION"); 0286 0287 if (!motionSP) 0288 return false; 0289 0290 auto abortSW = motionSP->findWidgetByName("ABORT"); 0291 0292 if (!abortSW) 0293 return false; 0294 0295 abortSW->setState(ISS_ON); 0296 sendNewProperty(motionSP); 0297 0298 return true; 0299 } 0300 0301 bool Dome::park() 0302 { 0303 auto parkSP = getSwitch("DOME_PARK"); 0304 0305 if (!parkSP) 0306 return false; 0307 0308 auto parkSW = parkSP->findWidgetByName("PARK"); 0309 0310 if (!parkSW) 0311 return false; 0312 0313 parkSP->reset(); 0314 parkSW->setState(ISS_ON); 0315 sendNewProperty(parkSP); 0316 0317 return true; 0318 } 0319 0320 bool Dome::unpark() 0321 { 0322 auto parkSP = getSwitch("DOME_PARK"); 0323 0324 if (!parkSP) 0325 return false; 0326 0327 auto parkSW = parkSP->findWidgetByName("UNPARK"); 0328 0329 if (!parkSW) 0330 return false; 0331 0332 parkSP->reset(); 0333 parkSW->setState(ISS_ON); 0334 sendNewProperty(parkSP); 0335 0336 return true; 0337 } 0338 0339 bool Dome::isMoving() const 0340 { 0341 auto motionSP = getSwitch("DOME_MOTION"); 0342 0343 if (motionSP && motionSP->getState() == IPS_BUSY) 0344 return true; 0345 0346 return false; 0347 } 0348 0349 double Dome::position() const 0350 { 0351 auto az = getNumber("ABS_DOME_POSITION"); 0352 0353 if (!az) 0354 return -1; 0355 else 0356 return az->at(0)->getValue(); 0357 } 0358 0359 bool Dome::setPosition(double position) 0360 { 0361 auto az = getNumber("ABS_DOME_POSITION"); 0362 0363 if (!az) 0364 return false; 0365 0366 az->at(0)->setValue(position); 0367 sendNewProperty(az); 0368 return true; 0369 } 0370 0371 bool Dome::setRelativePosition(double position) 0372 { 0373 auto azDiff = getNumber("REL_DOME_POSITION"); 0374 if (!azDiff) 0375 return false; 0376 0377 azDiff->at(0)->setValue(position); 0378 sendNewProperty(azDiff); 0379 return true; 0380 } 0381 0382 bool Dome::isAutoSync() 0383 { 0384 auto autosync = getSwitch("DOME_AUTOSYNC"); 0385 if (!autosync) 0386 return false; 0387 0388 auto autosyncSW = autosync->findWidgetByName("DOME_AUTOSYNC_ENABLE"); 0389 if (!autosyncSW) 0390 return false; 0391 else 0392 return (autosyncSW->s == ISS_ON); 0393 } 0394 0395 bool Dome::setAutoSync(bool activate) 0396 { 0397 auto autosync = getSwitch("DOME_AUTOSYNC"); 0398 if (!autosync) 0399 return false; 0400 0401 auto autosyncSW = autosync->findWidgetByName(activate ? "DOME_AUTOSYNC_ENABLE" : "DOME_AUTOSYNC_DISABLE"); 0402 if (!autosyncSW) 0403 return false; 0404 0405 autosync->reset(); 0406 autosyncSW->setState(ISS_ON); 0407 sendNewProperty(autosync); 0408 0409 return true; 0410 } 0411 0412 bool Dome::moveDome(DomeDirection dir, DomeMotionCommand operation) 0413 { 0414 auto domeMotion = getSwitch("DOME_MOTION"); 0415 if (!domeMotion) 0416 return false; 0417 0418 auto opSwitch = domeMotion->findWidgetByName(dir == DomeDirection::DOME_CW ? "DOME_CW" : "DOME_CCW"); 0419 if (!opSwitch) 0420 return false; 0421 0422 domeMotion->reset(); 0423 opSwitch->setState(operation == DomeMotionCommand::MOTION_START ? ISS_ON : ISS_OFF); 0424 sendNewProperty(domeMotion); 0425 return true; 0426 } 0427 0428 bool Dome::controlShutter(bool open) 0429 { 0430 auto shutterSP = getSwitch("DOME_SHUTTER"); 0431 if (!shutterSP) 0432 return false; 0433 0434 auto shutterSW = shutterSP->findWidgetByName(open ? "SHUTTER_OPEN" : "SHUTTER_CLOSE"); 0435 if (!shutterSW) 0436 return false; 0437 0438 shutterSP->reset(); 0439 shutterSW->setState(ISS_ON); 0440 sendNewProperty(shutterSP); 0441 0442 return true; 0443 } 0444 0445 Dome::ShutterStatus Dome::shutterStatus() 0446 { 0447 auto shutterSP = getSwitch("DOME_SHUTTER"); 0448 0449 return parseShutterStatus(shutterSP); 0450 } 0451 0452 Dome::ShutterStatus Dome::parseShutterStatus(INDI::Property prop) 0453 { 0454 if (prop.isValid() == false) 0455 return SHUTTER_UNKNOWN; 0456 0457 auto svp = prop.getSwitch(); 0458 0459 auto sp = svp->findWidgetByName("SHUTTER_OPEN"); 0460 if (sp == nullptr) 0461 return SHUTTER_UNKNOWN; 0462 0463 if (svp->getState() == IPS_ALERT) 0464 return SHUTTER_ERROR; 0465 else if (svp->getState() == IPS_BUSY) 0466 return (sp->s == ISS_ON) ? SHUTTER_OPENING : SHUTTER_CLOSING; 0467 else if (svp->getState() == IPS_OK) 0468 return (sp->s == ISS_ON) ? SHUTTER_OPEN : SHUTTER_CLOSED; 0469 0470 // this should not happen 0471 return SHUTTER_UNKNOWN; 0472 } 0473 0474 const QString Dome::getStatusString(Dome::Status status, bool translated) 0475 { 0476 return translated ? i18n(domeStates[status]) : domeStates[status]; 0477 } 0478 0479 } 0480 0481 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Dome::Status &source) 0482 { 0483 argument.beginStructure(); 0484 argument << static_cast<int>(source); 0485 argument.endStructure(); 0486 return argument; 0487 } 0488 0489 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Dome::Status &dest) 0490 { 0491 int a; 0492 argument.beginStructure(); 0493 argument >> a; 0494 argument.endStructure(); 0495 dest = static_cast<ISD::Dome::Status>(a); 0496 return argument; 0497 } 0498 0499 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Dome::ShutterStatus &source) 0500 { 0501 argument.beginStructure(); 0502 argument << static_cast<int>(source); 0503 argument.endStructure(); 0504 return argument; 0505 } 0506 0507 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Dome::ShutterStatus &dest) 0508 { 0509 int a; 0510 argument.beginStructure(); 0511 argument >> a; 0512 argument.endStructure(); 0513 dest = static_cast<ISD::Dome::ShutterStatus>(a); 0514 return argument; 0515 } 0516