File indexing completed on 2024-04-14 14:10:52

0001 /*
0002     SPDX-FileCopyrightText: 2014 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "indidbus.h"
0008 
0009 #include "indiadaptor.h"
0010 #include "nan.h"
0011 #include "indi/drivermanager.h"
0012 #include "indi/driverinfo.h"
0013 #include "indi/clientmanager.h"
0014 #include "indi/indilistener.h"
0015 #include "indi/indiconcretedevice.h"
0016 #include "indi/deviceinfo.h"
0017 
0018 #include "kstars_debug.h"
0019 
0020 #include <basedevice.h>
0021 
0022 INDIDBus::INDIDBus(QObject *parent) : QObject(parent)
0023 {
0024     new INDIAdaptor(this);
0025     QDBusConnection::sessionBus().registerObject("/KStars/INDI", this);
0026 }
0027 
0028 bool INDIDBus::start(int port, const QStringList &drivers)
0029 {
0030     QList<QSharedPointer<DriverInfo>> newDrivers;
0031 
0032     for (auto &driver : drivers)
0033     {
0034         auto drv = DriverManager::Instance()->findDriverByExec(driver);
0035 
0036         if (drv == nullptr)
0037             continue;
0038 
0039         QSharedPointer<DriverInfo> di(new DriverInfo(QString("%1").arg(driver)));
0040         di->setHostParameters("localhost", port);
0041         di->setDriverSource(EM_XML);
0042         di->setExecutable(driver);
0043         di->setUniqueLabel(drv->getUniqueLabel().isEmpty() ? drv->getLabel() : drv->getUniqueLabel());
0044 
0045         DriverManager::Instance()->addDriver(di);
0046         newDrivers.append(di);
0047     }
0048 
0049     DriverManager::Instance()->startDevices(newDrivers);
0050     return true;
0051 }
0052 
0053 bool INDIDBus::stop(const QString &port)
0054 {
0055     QList<QSharedPointer<DriverInfo>> stopDrivers;
0056 
0057     foreach (QSharedPointer<DriverInfo>di, DriverManager::Instance()->getDrivers())
0058     {
0059         if (di->getClientState() && di->getPort() == port)
0060             stopDrivers.append(di);
0061     }
0062 
0063     if (stopDrivers.isEmpty())
0064     {
0065         qCWarning(KSTARS) << "Could not find devices on port " << port;
0066         return false;
0067     }
0068 
0069     DriverManager::Instance()->stopDevices(stopDrivers);
0070 
0071     for (auto &di : stopDrivers)
0072         DriverManager::Instance()->removeDriver(di);
0073 
0074     return true;
0075 }
0076 
0077 bool INDIDBus::connect(const QString &host, int port)
0078 {
0079     QSharedPointer<DriverInfo> remote_indi(new DriverInfo(QString("INDI Remote Host")));
0080 
0081     remote_indi->setHostParameters(host, port);
0082 
0083     remote_indi->setDriverSource(GENERATED_SOURCE);
0084 
0085     // TODO migrate to event-based system.
0086     DriverManager::Instance()->connectRemoteHost(remote_indi);
0087     //    {
0088     //        delete (remote_indi);
0089     //        remote_indi = nullptr;
0090     //        return false;
0091     //    }
0092 
0093     DriverManager::Instance()->addDriver(remote_indi);
0094 
0095     return true;
0096 }
0097 
0098 bool INDIDBus::disconnect(const QString &host, int port)
0099 {
0100     for (auto &dv : DriverManager::Instance()->getDrivers())
0101     {
0102         if (dv->getHost() == host && dv->getPort() == port && dv->getDriverSource() == GENERATED_SOURCE)
0103         {
0104             if (DriverManager::Instance()->disconnectRemoteHost(dv))
0105             {
0106                 DriverManager::Instance()->removeDriver(dv);
0107                 return true;
0108             }
0109             else
0110                 return false;
0111         }
0112     }
0113 
0114     return false;
0115 }
0116 
0117 QStringList INDIDBus::getDevices()
0118 {
0119     QStringList devices;
0120 
0121     for (auto &oneDevice : INDIListener::devices())
0122     {
0123         devices << oneDevice->getDeviceName();
0124     }
0125 
0126     return devices;
0127 }
0128 
0129 QStringList INDIDBus::getDevicesPaths(uint32_t interface)
0130 {
0131     QStringList paths;
0132     for (auto &oneDevice : INDIListener::devicesByInterface(interface))
0133     {
0134         QSharedPointer<ISD::ConcreteDevice> concreteDevice;
0135         if (oneDevice->findConcreteDevice(interface, concreteDevice))
0136             paths << concreteDevice->getDUBSObjectPath();
0137     }
0138     return paths;
0139 }
0140 
0141 QStringList INDIDBus::getProperties(const QString &device)
0142 {
0143     QStringList properties;
0144 
0145     for (auto &oneDevice : INDIListener::devices())
0146     {
0147         if (oneDevice->getDeviceName() == device)
0148         {
0149             // Let's print a list of all device properties
0150             for (const auto &prop : oneDevice->getProperties())
0151             {
0152                 switch (prop.getType())
0153                 {
0154                     case INDI_SWITCH:
0155                         for (const auto &it : *prop.getSwitch())
0156                             properties << device + '.' + QString(prop.getName()) + '.' + it.getName();
0157                         break;
0158 
0159                     case INDI_TEXT:
0160                         for (const auto &it : *prop.getText())
0161                             properties << device + '.' + QString(prop.getName()) + '.' + it.getName();
0162                         break;
0163 
0164                     case INDI_NUMBER:
0165                         for (const auto &it : *prop.getNumber())
0166                             properties << device + '.' + QString(prop.getName()) + '.' + it.getName();
0167                         break;
0168 
0169                     case INDI_LIGHT:
0170                         for (const auto &it : *prop.getLight())
0171                             properties << device + '.' + QString(prop.getName()) + '.' + it.getName();
0172                         break;
0173 
0174                     case INDI_BLOB:
0175                         for (const auto &it : *prop.getBLOB())
0176                             properties << device + '.' + QString(prop.getName()) + '.' + it.getName();
0177                         break;
0178 
0179                     case INDI_UNKNOWN:
0180                         qCWarning(KSTARS) << device << '.' << QString(prop.getName()) << " has an unknown type! Aborting...";
0181                         return properties;
0182                 }
0183             }
0184 
0185             return properties;
0186         }
0187     }
0188 
0189     qCWarning(KSTARS) << "Could not find device: " << device;
0190     return properties;
0191 }
0192 
0193 QString INDIDBus::getPropertyState(const QString &device, const QString &property)
0194 {
0195     QString status = "Invalid";
0196 
0197     for (auto &oneDevice : INDIListener::devices())
0198     {
0199         if (oneDevice->getDeviceName() == device)
0200         {
0201             auto prop = oneDevice->getProperty(property.toLatin1());
0202             if (prop)
0203             {
0204                 status = QString(pstateStr(prop.getState()));
0205                 return status;
0206             }
0207 
0208             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0209             return status;
0210         }
0211     }
0212 
0213     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0214     return status;
0215 }
0216 
0217 bool INDIDBus::sendProperty(const QString &device, const QString &property)
0218 {
0219     for (auto &oneDevice : INDIListener::devices())
0220     {
0221         ClientManager *cm = oneDevice->getDeviceInfo()->getDriverInfo()->getClientManager();
0222 
0223         if (oneDevice->getDeviceName() == device)
0224         {
0225             auto prop = oneDevice->getProperty(property.toLatin1());
0226             if (prop)
0227             {
0228                 switch (prop.getType())
0229                 {
0230                     case INDI_SWITCH:
0231                         prop.getSwitch()->setState(IPS_BUSY);
0232                         cm->sendNewProperty(prop.getSwitch());
0233                         break;
0234 
0235                     case INDI_TEXT:
0236                         prop.getText()->setState(IPS_BUSY);
0237                         cm->sendNewProperty(prop.getText());
0238                         break;
0239 
0240                     case INDI_NUMBER:
0241                         prop.getNumber()->setState(IPS_BUSY);
0242                         cm->sendNewProperty(prop.getNumber());
0243                         break;
0244 
0245                     default:
0246                         qCWarning(KSTARS) << "Only switch, text, and number properties are supported.";
0247                         return false;
0248                 }
0249 
0250                 return true;
0251             }
0252 
0253             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0254             return false;
0255         }
0256     }
0257 
0258     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0259     return false;
0260 }
0261 
0262 QString INDIDBus::getLight(const QString &device, const QString &property, const QString &lightName)
0263 {
0264     QString status = "Invalid";
0265 
0266     for (auto &oneDevice : INDIListener::devices())
0267     {
0268         if (oneDevice->getDeviceName() == device)
0269         {
0270             auto prop = oneDevice->getProperty(property.toLatin1());
0271             if (prop)
0272             {
0273                 auto lp = prop.getLight();
0274                 if (lp)
0275                 {
0276                     auto l = lp->findWidgetByName(lightName.toLatin1());
0277                     if (l)
0278                     {
0279                         status = QString(l->getStateAsString());
0280                         return status;
0281                     }
0282                 }
0283             }
0284 
0285             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0286             return status;
0287         }
0288     }
0289 
0290     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property;
0291     return status;
0292 }
0293 
0294 bool INDIDBus::setSwitch(const QString &device, const QString &property, const QString &switchName,
0295                          const QString &status)
0296 {
0297     if (status != "On" && status != "Off")
0298     {
0299         qCWarning(KSTARS) << "Invalid switch status requested: " << status;
0300         return false;
0301     }
0302 
0303     for (auto &oneDevice : INDIListener::devices())
0304     {
0305         if (oneDevice->getDeviceName() == device)
0306         {
0307             auto sp = oneDevice->getBaseDevice().getSwitch(property.toLatin1());
0308 
0309             if (sp.getRule() == ISR_1OFMANY && status == "Off")
0310             {
0311                 qCWarning(KSTARS) << "Cannot set ISR_1OFMANY switch to Off. At least one switch must be On.";
0312                 return false;
0313             }
0314 
0315             if (sp.getRule() == ISR_1OFMANY || sp.getRule() == ISR_ATMOST1)
0316                 sp.reset();
0317 
0318             auto sw = sp.findWidgetByName(switchName.toLatin1());
0319 
0320             if (sw)
0321             {
0322                 sw->setState(status == "On" ? ISS_ON : ISS_OFF);
0323                 return true;
0324             }
0325 
0326             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << switchName;
0327             return false;
0328         }
0329     }
0330 
0331     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << switchName;
0332     return false;
0333 }
0334 
0335 QString INDIDBus::getSwitch(const QString &device, const QString &property, const QString &switchName)
0336 {
0337     QString result("Invalid");
0338 
0339     for (auto &oneDevice : INDIListener::devices())
0340     {
0341         if (oneDevice->getDeviceName() == device)
0342         {
0343             auto sp = oneDevice->getBaseDevice().getSwitch(property.toLatin1());
0344             if (sp)
0345             {
0346                 auto sw = sp.findWidgetByName(switchName.toLatin1());
0347                 if (sw)
0348                 {
0349                     result = ((sw->getState() == ISS_ON) ? "On" : "Off");
0350                     return result;
0351                 }
0352 
0353                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << switchName;
0354                 return result;
0355             }
0356 
0357             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << switchName;
0358             return result;
0359         }
0360     }
0361 
0362     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << switchName;
0363     return result;
0364 }
0365 
0366 bool INDIDBus::setText(const QString &device, const QString &property, const QString &textName, const QString &text)
0367 {
0368     for (auto &oneDevice : INDIListener::devices())
0369     {
0370         if (oneDevice->getDeviceName() == device)
0371         {
0372             auto tp = oneDevice->getBaseDevice().getText(property.toLatin1());
0373 
0374             if (tp)
0375             {
0376                 auto t = tp.findWidgetByName(textName.toLatin1());
0377                 if (t)
0378                 {
0379                     t->setText(text.toLatin1());
0380                     return true;
0381                 }
0382 
0383                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0384                 return false;
0385             }
0386 
0387             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0388             return false;
0389         }
0390     }
0391 
0392     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0393     return false;
0394 }
0395 
0396 QString INDIDBus::getText(const QString &device, const QString &property, const QString &textName)
0397 {
0398     QString result("Invalid");
0399 
0400     for (auto &oneDevice : INDIListener::devices())
0401     {
0402         if (oneDevice->getDeviceName() == device)
0403         {
0404             auto tp = oneDevice->getBaseDevice().getText(property.toLatin1());
0405             if (tp)
0406             {
0407                 auto t = tp.findWidgetByName(textName.toLatin1());
0408                 if (t)
0409                 {
0410                     result = QString(t->getText());
0411                     return result;
0412                 }
0413 
0414                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0415                 return result;
0416             }
0417 
0418             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0419             return result;
0420         }
0421     }
0422 
0423     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << textName;
0424     return result;
0425 }
0426 
0427 bool INDIDBus::setNumber(const QString &device, const QString &property, const QString &numberName, double value)
0428 {
0429     for (auto &oneDevice : INDIListener::devices())
0430     {
0431         if (oneDevice->getDeviceName() == device)
0432         {
0433             auto np = oneDevice->getBaseDevice().getNumber(property.toLatin1());
0434 
0435             if (np)
0436             {
0437                 auto n = np.findWidgetByName(numberName.toLatin1());
0438                 if (n)
0439                 {
0440                     n->setValue(value);
0441                     return true;
0442                 }
0443 
0444                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0445                 return false;
0446             }
0447 
0448             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0449             return false;
0450         }
0451     }
0452 
0453     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0454     return false;
0455 }
0456 
0457 double INDIDBus::getNumber(const QString &device, const QString &property, const QString &numberName)
0458 {
0459     double result = NaN::d;
0460 
0461     for (auto &oneDevice : INDIListener::devices())
0462     {
0463         if (oneDevice->getDeviceName() == device)
0464         {
0465             auto np = oneDevice->getBaseDevice().getNumber(property.toLatin1());
0466             if (np)
0467             {
0468                 auto n = np.findWidgetByName(numberName.toLatin1());
0469                 if (n)
0470                 {
0471                     result = n->getValue();
0472                     return result;
0473                 }
0474 
0475                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0476                 return result;
0477             }
0478 
0479             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0480             return result;
0481         }
0482     }
0483 
0484     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << numberName;
0485     return result;
0486 }
0487 
0488 QByteArray INDIDBus::getBLOBData(const QString &device, const QString &property, const QString &blobName,
0489                                  QString &blobFormat, int &size)
0490 {
0491     QByteArray array;
0492     size = -1;
0493 
0494     for (auto &oneDevice : INDIListener::devices())
0495     {
0496         if (oneDevice->getDeviceName() == device)
0497         {
0498             auto bp = oneDevice->getBaseDevice().getBLOB(property.toLatin1());
0499             if (bp)
0500             {
0501                 auto b = bp.findWidgetByName(blobName.toLatin1());
0502                 if (b)
0503                 {
0504                     const char *rawData = static_cast<const char *>(b->getBlob());
0505                     array               = QByteArray::fromRawData(rawData, b->getSize());
0506                     size                = b->getBlobLen();
0507                     blobFormat          = QString(b->getFormat()).trimmed();
0508 
0509                     return array;
0510                 }
0511 
0512                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0513                 return array;
0514             }
0515 
0516             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0517             return array;
0518         }
0519     }
0520 
0521     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0522     return array;
0523 }
0524 
0525 QString INDIDBus::getBLOBFile(const QString &device, const QString &property, const QString &blobName,
0526                               QString &blobFormat, int &size)
0527 {
0528     QString filename;
0529     size = -1;
0530 
0531     for (auto &oneDevice : INDIListener::devices())
0532     {
0533         if (oneDevice->getDeviceName() == device)
0534         {
0535             auto bp = oneDevice->getBaseDevice().getBLOB(property.toLatin1());
0536             if (bp)
0537             {
0538                 auto b = bp.findWidgetByName(blobName.toLatin1());
0539                 if (b)
0540                 {
0541                     filename   = QString(static_cast<char *>(b->aux2));
0542                     size       = b->bloblen;
0543                     blobFormat = QString(b->format).trimmed();
0544 
0545                     return filename;
0546                 }
0547 
0548                 qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0549                 return filename;
0550             }
0551 
0552             qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0553             return filename;
0554         }
0555     }
0556 
0557     qCWarning(KSTARS) << "Could not find property: " << device << '.' << property << '.' << blobName;
0558     return filename;
0559 }