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);
73void DeviceManager::startServer()
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();
116 if (mode == DeviceManager::M_LOCAL)
120void DeviceManager::stopServer()
125void DeviceManager::connectToServer()
127 connect(&serverSocket, SIGNAL(readyRead()),
this, SLOT(dataReceived()));
129 for (
int i = 0; i < INDI_MAX_TRIES; i++)
145void DeviceManager::enableBLOB(
bool enable,
QString device,
QString 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()
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.")
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)
210 emit newServerInput();
213void DeviceManager::dataReceived()
215 char errmsg[ERRMSG_SIZE];
216 int nr = 0, err_code = 0;
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)
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)
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)
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);
546 serverFP <<
QString(
" </oneNumber>\n");
548 serverFP <<
QString(
"</newNumberVector>\n");
551void DeviceManager::sendNewSwitch(
INDI_P *pp,
INDI_E *lp)
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)
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)
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()
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).
void setOutputChannelMode(OutputChannelMode mode)
static KStarsDateTime currentDateTime()
char * toString(const EngineQuery &query)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
virtual void close() override
void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
virtual bool waitForConnected(int msecs)
QString applicationDirPath()
QString errorString() const const
void append(QList< T > &&value)
bool isEmpty() const const
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant property(const char *name) const const
virtual void close() override
QByteArray readAllStandardError()
void setReadChannel(ProcessChannel channel)
bool waitForStarted(int msecs)
QString & append(QChar ch)
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