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