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

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