7#include "devicemanager.h" 
   11#include "indiproperty.h" 
   13#include "indidevice.h" 
   15#include "indidriver.h" 
   17#include "kstarsdatetime.h" 
   21#include <config-kstars.h> 
   35const int INDI_MAX_TRIES = 3;
 
   45DeviceManager::DeviceManager(INDIMenu *INDIparent, 
QString inHost, uint inPort, ManagerMode inMode)
 
   48    serverProcess = 
nullptr;
 
   55DeviceManager::~DeviceManager()
 
   60        serverProcess->close();
 
   62    delete (serverProcess);
 
   69    while (!indi_dev.isEmpty())
 
   70        delete indi_dev.takeFirst();
 
   73void DeviceManager::startServer()
 
   75    serverProcess = 
new KProcess;
 
   77    if (managed_devices.isEmpty())
 
   79        kWarning() << 
"managed_devices was not set! Cannot start server!";
 
   83    if (Options::indiServerIsInternal())
 
   87        *serverProcess << Options::indiServer();
 
   88    *serverProcess << 
"-v" 
   91    foreach (IDevice *device, managed_devices)
 
   94        if (device->type == KSTARS_CCD)
 
   96            *serverProcess << 
"-m" 
  102    foreach (IDevice *device, managed_devices)
 
  103        *serverProcess << device->driver;
 
  105    if (mode == DeviceManager::M_LOCAL)
 
  107        connect(serverProcess, SIGNAL(readyReadStandardError()), 
this, SLOT(processStandardError()));
 
  112    serverProcess->start();
 
  114    serverProcess->waitForStarted();
 
  116    if (mode == DeviceManager::M_LOCAL)
 
  120void DeviceManager::stopServer()
 
  122    serverProcess->terminate();
 
  125void DeviceManager::connectToServer()
 
  127    connect(&serverSocket, SIGNAL(readyRead()), 
this, SLOT(dataReceived()));
 
  129    for (
int i = 0; i < INDI_MAX_TRIES; i++)
 
  131        serverSocket.connectToHost(host, port);
 
  132        if (serverSocket.waitForConnected(1000))
 
  145void DeviceManager::enableBLOB(
bool enable, 
QString device, 
QString property)
 
  147    QTextStream serverFP(&serverSocket);
 
  154        openTag = QString(
"<enableBLOB device='%1' name='%2'>").
arg(device).
arg(
property);
 
  156        openTag = QString(
"<enableBLOB device='%1'>").
arg(device);
 
  160        serverFP << QString(
"%1Also</enableBLOB>\n").arg(openTag);
 
  161        kDebug() << QString(
"%1Also</enableBLOB>\n").arg(openTag);
 
  165        serverFP << QString(
"%1Never</enableBLOB>\n").arg(openTag);
 
  166        kDebug() << QString(
"%1Never</enableBLOB>\n").arg(openTag);
 
  170void DeviceManager::connectionSuccess()
 
  172    QTextStream serverFP(&serverSocket);
 
  175        delLilXML(XMLParser);
 
  176    XMLParser = newLilXML();
 
  178    serverFP << QString(
"<getProperties version='%1'/>\n").arg(INDIVERSION);
 
  181void DeviceManager::connectionError()
 
  183    QString errMsg = QString(
"Connection to INDI host at %1 on port %2 encountered an error: %3.")
 
  186                         .arg(serverSocket.errorString());
 
  189    emit deviceManagerError(
this);
 
  192void DeviceManager::appendManagedDevices(
QList<IDevice *> &processed_devices)
 
  194    managed_devices = processed_devices;
 
  196    foreach (IDevice *device, managed_devices)
 
  198        device->unique_label = parent->getUniqueDeviceLabel(device->tree_label);
 
  200        device->deviceManager = 
this;
 
  204void DeviceManager::processStandardError()
 
  206    if (serverProcess == 
nullptr)
 
  209    serverBuffer.
append(serverProcess->readAllStandardError());
 
  210    emit newServerInput();
 
  213void DeviceManager::dataReceived()
 
  215    char errmsg[ERRMSG_SIZE];
 
  216    int nr = 0, err_code = 0;
 
  217    QTextStream serverFP(&serverSocket);
 
  218    QString ibuf, err_cmd;
 
  220    ibuf = serverFP.readAll();
 
  224    for (
int i = 0; i < nr; i++)
 
  229        XMLEle *root = readXMLEle(XMLParser, ibuf[i].toAscii(), errmsg);
 
  232            if ((err_code = dispatchCommand(root, err_cmd)) < 0)
 
  235                if (err_code != INDI_PROPERTY_DUPLICATED)
 
  238                    fprintf(stderr, 
"Dispatch command error: %d for command %s\n", err_code, qPrintable(err_cmd));
 
  239                    prXMLEle(stderr, root, 0);
 
  247            kDebug() << 
"XML Root Error: " << errmsg;
 
  252int DeviceManager::dispatchCommand(XMLEle *root, 
QString &errmsg)
 
  254    if (!strcmp(tagXMLEle(root), 
"message"))
 
  255        return messageCmd(root, errmsg);
 
  256    else if (!strcmp(tagXMLEle(root), 
"delProperty"))
 
  257        return delPropertyCmd(root, errmsg);
 
  260    INDI_D *dp = findDev(root, 1, errmsg);
 
  264        errmsg = 
"No device available and none was created";
 
  265        return INDI_DEVICE_NOT_FOUND;
 
  268    if (!strcmp(tagXMLEle(root), 
"defTextVector"))
 
  269        return dp->buildTextGUI(root, errmsg);
 
  270    else if (!strcmp(tagXMLEle(root), 
"defNumberVector"))
 
  271        return dp->buildNumberGUI(root, errmsg);
 
  272    else if (!strcmp(tagXMLEle(root), 
"defSwitchVector"))
 
  273        return dp->buildSwitchesGUI(root, errmsg);
 
  274    else if (!strcmp(tagXMLEle(root), 
"defLightVector"))
 
  275        return dp->buildLightsGUI(root, errmsg);
 
  276    else if (!strcmp(tagXMLEle(root), 
"defBLOBVector"))
 
  277        return dp->buildBLOBGUI(root, errmsg);
 
  278    else if (!strcmp(tagXMLEle(root), 
"setTextVector") || !strcmp(tagXMLEle(root), 
"setNumberVector") ||
 
  279             !strcmp(tagXMLEle(root), 
"setSwitchVector") || !strcmp(tagXMLEle(root), 
"setLightVector") ||
 
  280             !strcmp(tagXMLEle(root), 
"setBLOBVector"))
 
  281        return dp->setAnyCmd(root, errmsg);
 
  283    else if (QString(tagXMLEle(root)).startsWith(
"new"))
 
  286    return INDI_DISPATCH_ERROR;
 
  294int DeviceManager::delPropertyCmd(XMLEle *root, 
QString &errmsg)
 
  301    dp = findDev(root, 0, errmsg);
 
  303        return INDI_DEVICE_NOT_FOUND;
 
  307    ap = findXMLAtt(root, 
"name");
 
  312        pp = dp->findProp(QString(valuXMLAtt(ap)));
 
  315            return dp->removeProperty(pp);
 
  317            return INDI_PROPERTY_INVALID;
 
  321        return removeDevice(dp->name, errmsg);
 
  324int DeviceManager::removeDevice(
const QString &devName, 
QString &errmsg)
 
  327    if (devName == 
nullptr)
 
  329        while (!indi_dev.isEmpty())
 
  330            delete indi_dev.takeFirst();
 
  334    for (
int i = 0; i < indi_dev.size(); i++)
 
  336        if (indi_dev[i]->name == devName)
 
  338            delete indi_dev.takeAt(i);
 
  343    errmsg = QString(
"Device %1 not found").
arg(devName);
 
  344    return INDI_DEVICE_NOT_FOUND;
 
  350    for (
int i = 0; i < indi_dev.size(); i++)
 
  352        if (indi_dev[i]->name == devName)
 
  356    errmsg = QString(
"INDI: no such device %1").
arg(devName);
 
  364INDI_D *DeviceManager::addDevice(XMLEle *dep, 
QString &errmsg)
 
  368    QString device_name, unique_label;
 
  369    IDevice *targetDevice = 
nullptr;
 
  372    ap = findAtt(dep, 
"device", errmsg);
 
  375        errmsg = QString(
"Unable to find device attribute in XML tree. Cannot add device.");
 
  376        kDebug() << errmsg << 
endl;
 
  380    device_name = QString(valuXMLAtt(ap));
 
  382    if (mode != M_CLIENT)
 
  383        foreach (IDevice *device, managed_devices)
 
  390            if (device->name == device_name && device->state == IDevice::DEV_TERMINATE)
 
  392                device->state = IDevice::DEV_START;
 
  393                unique_label = device->unique_label = parent->getUniqueDeviceLabel(device->tree_label);
 
  394                targetDevice                        = device;
 
  401        unique_label = parent->getUniqueDeviceLabel(device_name);
 
  403    dp = 
new INDI_D(parent, 
this, device_name, unique_label, targetDevice);
 
  407    enableBLOB(
true, device_name);
 
  409    connect(dp->stdDev, SIGNAL(newTelescope()), parent->ksw->indiDriver(), SLOT(newTelescopeDiscovered()),
 
  416INDI_D *DeviceManager::findDev(XMLEle *root, 
int create, 
QString &errmsg)
 
  418    XMLAtt *ap = findAtt(root, 
"device", errmsg);
 
  424        errmsg = QString(
"No device attribute found in element %1").
arg(tagXMLEle(root));
 
  430    for (
int i = 0; i < indi_dev.size(); i++)
 
  432        if (indi_dev[i]->name == QString(dn))
 
  438        return (addDevice(root, errmsg));
 
  440    errmsg = QString(
"INDI: <%1> no such device %2").
arg(tagXMLEle(root)).
arg(dn);
 
  447int DeviceManager::messageCmd(XMLEle *root, 
QString &errmsg)
 
  449    checkMsg(root, findDev(root, 0, errmsg));
 
  456void DeviceManager::checkMsg(XMLEle *root, 
INDI_D *dp)
 
  459    ap = findXMLAtt(root, 
"message");
 
  469void DeviceManager::doMsg(XMLEle *msg, 
INDI_D *dp)
 
  477        kDebug() << 
"Warning: dp is null.";
 
  484    timestamp = findXMLAtt(msg, 
"timestamp");
 
  492    message = findXMLAtt(msg, 
"message");
 
  503    if (Options::showINDIMessages())
 
  504        parent->ksw->statusBar()->changeItem(QString(valuXMLAtt(message)), 0);
 
  507void DeviceManager::sendNewText(
INDI_P *pp)
 
  511    QTextStream serverFP(&serverSocket);
 
  513    serverFP << QString(
"<newTextVector\n");
 
  514    serverFP << QString(
"  device='%1'\n").arg(qPrintable(pp->pg->dp->name));
 
  515    serverFP << QString(
"  name='%1'\n>").arg(qPrintable(pp->name));
 
  520        serverFP << QString(
"  <oneText\n");
 
  521        serverFP << QString(
"    name='%1'>\n").arg(qPrintable(lp->name));
 
  522        serverFP << QString(
"      %1\n").arg(qPrintable(lp->text));
 
  523        serverFP << QString(
"  </oneText>\n");
 
  525    serverFP << QString(
"</newTextVector>\n");
 
  528void DeviceManager::sendNewNumber(
INDI_P *pp)
 
  532    QTextStream serverFP(&serverSocket);
 
  534    serverFP << QString(
"<newNumberVector\n");
 
  535    serverFP << QString(
"  device='%1'\n").arg(qPrintable(pp->pg->dp->name));
 
  536    serverFP << QString(
"  name='%1'\n>").arg(qPrintable(pp->name));
 
  540        serverFP << QString(
"  <oneNumber\n");
 
  541        serverFP << QString(
"    name='%1'>\n").arg(qPrintable(lp->name));
 
  542        if (lp->text.
isEmpty() || lp->spin_w)
 
  543            serverFP << QString(
"      %1\n").arg(lp->targetValue);
 
  545            serverFP << QString(
"      %1\n").arg(lp->text);
 
  546        serverFP << QString(
"  </oneNumber>\n");
 
  548    serverFP << QString(
"</newNumberVector>\n");
 
  551void DeviceManager::sendNewSwitch(
INDI_P *pp, 
INDI_E *lp)
 
  553    QTextStream serverFP(&serverSocket);
 
  555    serverFP << QString(
"<newSwitchVector\n");
 
  556    serverFP << QString(
"  device='%1'\n").arg(qPrintable(pp->pg->dp->name));
 
  557    serverFP << QString(
"  name='%1'>\n").arg(qPrintable(pp->name));
 
  558    serverFP << QString(
"  <oneSwitch\n");
 
  559    serverFP << QString(
"    name='%1'>\n").arg(qPrintable(lp->name));
 
  560    serverFP << QString(
"      %1\n").arg(lp->switch_state == ISS_ON ? 
"On" : 
"Off");
 
  561    serverFP << QString(
"  </oneSwitch>\n");
 
  563    serverFP << QString(
"</newSwitchVector>\n");
 
  566void DeviceManager::startBlob(
const QString &devName, 
const QString &propName, 
const QString ×tamp)
 
  568    QTextStream serverFP(&serverSocket);
 
  570    serverFP << QString(
"<newBLOBVector\n");
 
  571    serverFP << QString(
"  device='%1'\n").arg(qPrintable(devName));
 
  572    serverFP << QString(
"  name='%1'\n").arg(qPrintable(propName));
 
  573    serverFP << QString(
"  timestamp='%1'>\n").arg(qPrintable(timestamp));
 
  576void DeviceManager::sendOneBlob(
const QString &blobName, 
unsigned int blobSize, 
const QString &blobFormat,
 
  577                                unsigned char *blobBuffer)
 
  579    QTextStream serverFP(&serverSocket);
 
  581    serverFP << QString(
"  <oneBLOB\n");
 
  582    serverFP << QString(
"    name='%1'\n").arg(qPrintable(blobName));
 
  583    serverFP << QString(
"    size='%1'\n").arg(blobSize);
 
  584    serverFP << QString(
"    format='%1'>\n").arg(qPrintable(blobFormat));
 
  586    for (
unsigned i = 0; i < blobSize; i += 72)
 
  587        serverFP << QString().sprintf(
"    %.72s\n", blobBuffer + i);
 
  589    serverFP << QString(
"   </oneBLOB>\n");
 
  592void DeviceManager::finishBlob()
 
  594    QTextStream serverFP(&serverSocket);
 
  596    serverFP << QString(
"</newBLOBVector>\n");
 
  599#include "devicemanager.moc" 
INDI_D represents an INDI GUI Device.
 
INDI_E represents an INDI GUI element (Number, Text, Switch, Light, or BLOB) within an INDI property.
 
INDI_P represents a single INDI property (Switch, Text, Number, Light, or BLOB).
 
static KStarsDateTime currentDateTime()
 
char * toString(const EngineQuery &query)
 
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
 
QString applicationDirPath()
 
void append(QList< T > &&value)
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
QVariant property(const char *name) const const
 
QString arg(Args &&... args) const const
 
bool isEmpty() const const
 
qsizetype length() const const
 
QString number(double n, char format, int precision)
 
QTextStream & endl(QTextStream &stream)
 
bool movePosition(MoveOperation operation, MoveMode mode, int n)
 
void insertPlainText(const QString &text)
 
void setTextCursor(const QTextCursor &cursor)
 
QTextCursor textCursor() const const