/* Device Manager Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. JM Changelog 2004-16-1: Start */ #include "Options.h" #include "devicemanager.h" #include "indimenu.h" #include "indiproperty.h" #include "indigroup.h" #include "indidevice.h" #include "indi/indicom.h" #include "kstars.h" #include "kstarsdatetime.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************* ** The device manager contain devices running from one indiserver ** This allow KStars to control multiple devices distributed acorss ** multiple servers seemingly in a way that is completely transparent ** to devices and drivers alike. ** The device Manager can be thought of as the 'networking' parent ** of devices, while indimenu is 'GUI' parent of devices *******************************************************************/ DeviceManager::DeviceManager(INDIMenu *INDIparent, int inID) { parent = INDIparent; mgrID = inID; indi_dev.setAutoDelete(true); serverFD = -1; serverFP = NULL; XMLParser = NULL; sNotifier = NULL; } DeviceManager::~DeviceManager() { if (serverFP) fclose(serverFP); if (serverFD >= 0) close(serverFD); if (XMLParser) { delLilXML(XMLParser); XMLParser = NULL; } indi_dev.clear(); } bool DeviceManager::indiConnect(TQString inHost, TQString inPort) { host = inHost; port = inPort; TQString errMsg; struct sockaddr_in pin; struct hostent *serverHostName = gethostbyname(host.ascii()); errMsg = TQString("Connection to INDI host at %1 on port %2 failed.").arg(host).arg(port); memset(&pin, 0, sizeof(pin)); pin.sin_family = AF_INET; pin.sin_addr.s_addr = ((struct in_addr *) (serverHostName->h_addr))->s_addr; pin.sin_port = htons(port.toInt()); if ( (serverFD = socket(AF_INET, SOCK_STREAM, 0)) == -1) { KMessageBox::error(0, i18n("Cannot create socket")); return false; } if ( ::connect(serverFD, (struct sockaddr*) &pin, sizeof(pin)) == -1) { KMessageBox::error(0, errMsg); serverFD = -1; return false; } // callback notified sNotifier = new TQSocketNotifier( serverFD, TQSocketNotifier::Read, this); TQObject::connect( sNotifier, TQT_SIGNAL(activated(int)), this, TQT_SLOT(dataReceived())); if (XMLParser) delLilXML(XMLParser); XMLParser = newLilXML(); // ready for fprintf serverFP = fdopen(serverFD, "w"); if (serverFP == NULL) { KMessageBox::error(0, i18n("Cannot read server file descriptor")); serverFD = -1; return false; } setbuf (serverFP, NULL); fprintf(serverFP, "Also\n"); fprintf(serverFP, "\n", INDIVERSION); // We made it! return true; } void DeviceManager::dataReceived() { char ibuf[32]; /* not so much user input lags */ char errmsg[ERRMSG_SIZE]; int i, nr; /* read INDI command */ nr = read (serverFD, ibuf, sizeof(ibuf)-1); if (nr <= 0) { if (nr < 0) strcpy (errmsg, "INDI: input error."); else strcpy (errmsg, "INDI: agent closed connection."); tcflush(serverFD, TCIFLUSH); sNotifier->disconnect(); close(serverFD); parent->removeDeviceMgr(mgrID); KMessageBox::error(0, TQString::fromLatin1(errmsg)); return; } ibuf[ sizeof( ibuf )-1 ] = '\0'; /* process each char */ for (i = 0; i < nr; i++) { if (!XMLParser) return; XMLEle *root = readXMLEle (XMLParser, (int)ibuf[i], errmsg); if (root) { //prXMLEle (stdout, root, 0); if (dispatchCommand(root, errmsg) < 0) { fprintf(stderr, "%s", errmsg); prXMLEle (stdout, root, 0); } delXMLEle (root); } else if (*errmsg) { kdDebug() << errmsg << endl; } } } int DeviceManager::dispatchCommand(XMLEle *root, char errmsg[]) { if (!strcmp (tagXMLEle(root), "message")) return messageCmd(root, errmsg); else if (!strcmp (tagXMLEle(root), "delProperty")) return delPropertyCmd(root, errmsg); /* Get the device, if not available, create it */ INDI_D *dp = findDev (root, 1, errmsg); if (dp == NULL) return -1; if (!strcmp (tagXMLEle(root), "defTextVector")) return dp->buildTextGUI(root, errmsg); else if (!strcmp (tagXMLEle(root), "defNumberVector")) return dp->buildNumberGUI(root, errmsg); else if (!strcmp (tagXMLEle(root), "defSwitchVector")) return dp->buildSwitchesGUI(root, errmsg); else if (!strcmp (tagXMLEle(root), "defLightVector")) return dp->buildLightsGUI(root, errmsg); else if (!strcmp (tagXMLEle(root), "defBLOBVector")) return dp->buildBLOBGUI(root, errmsg); else if (!strcmp (tagXMLEle(root), "setTextVector") || !strcmp (tagXMLEle(root), "setNumberVector") || !strcmp (tagXMLEle(root), "setSwitchVector") || !strcmp (tagXMLEle(root), "setLightVector") || !strcmp (tagXMLEle(root), "setBLOBVector")) return dp->setAnyCmd(root, errmsg); return (-1); } /* delete the property in the given device, including widgets and data structs. * when last property is deleted, delete the device too. * if no property name attribute at all, delete the whole device regardless. * return 0 if ok, else -1 with reason in errmsg[]. */ int DeviceManager::delPropertyCmd (XMLEle *root, char errmsg[]) { XMLAtt *ap; INDI_D *dp; INDI_P *pp; /* dig out device and optional property name */ dp = findDev (root, 0, errmsg); if (!dp) return (-1); checkMsg(root, dp); ap = findXMLAtt (root, "name"); /* Delete property if it exists, otherwise, delete the whole device */ if (ap) { pp = dp->findProp(TQString(valuXMLAtt(ap))); if(pp) return dp->removeProperty(pp); else return (-1); } // delete the whole device else return removeDevice(dp->name, errmsg); } int DeviceManager::removeDevice(TQString devName, char errmsg[]) { // remove all devices if devName == NULL if (devName == NULL) { indi_dev.clear(); return (0); } for (unsigned int i=0; i < indi_dev.count(); i++) { if (indi_dev.at(i)->name == devName) { kdDebug() << "Device Manager: Device found, deleting " << devName << endl; indi_dev.remove(i); return (0); } } snprintf(errmsg, ERRMSG_SIZE, "Device %.32s not found" , devName.ascii()); return -1; } INDI_D * DeviceManager::findDev (TQString devName, char errmsg[]) { /* search for existing */ for (unsigned int i = 0; i < indi_dev.count(); i++) { if (indi_dev.at(i)->name == devName) return (indi_dev.at(i)); } snprintf (errmsg, ERRMSG_SIZE, "INDI: no such device %.32s", devName.ascii()); kdDebug() << errmsg; return NULL; } /* add new device to mainrc_w using info in dep. - * if trouble return NULL with reason in errmsg[] - */ INDI_D * DeviceManager::addDevice (XMLEle *dep, char errmsg[]) { INDI_D *dp; XMLAtt *ap; /* allocate new INDI_D on indi_dev */ ap = findAtt (dep, "device", errmsg); if (!ap) return NULL; if (parent->currentLabel.isEmpty()) parent->setCustomLabel(valuXMLAtt(ap)); dp = new INDI_D(parent, this, TQString(valuXMLAtt(ap)), parent->currentLabel); indi_dev.append(dp); emit newDevice(); // Reset label parent->currentLabel = ""; /* ok */ return dp; } INDI_D * DeviceManager::findDev (XMLEle *root, int create, char errmsg[]) { XMLAtt *ap; char *dn; /* get device name */ ap = findAtt (root, "device", errmsg); if (!ap) return (NULL); dn = valuXMLAtt(ap); /* search for existing */ for (uint i = 0; i < indi_dev.count(); i++) { if (indi_dev.at(i)->name == TQString(dn)) return (indi_dev.at(i)); } /* not found, create if ok */ if (create) return (addDevice (root, errmsg)); snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.32s> no such device %.32s", tagXMLEle(root), dn); return NULL; } /* a general message command received from the device. * return 0 if ok, else -1 with reason in errmsg[]. */ int DeviceManager::messageCmd (XMLEle *root, char errmsg[]) { checkMsg (root, findDev (root, 0, errmsg)); return (0); } /* display message attribute. * N.B. don't put carriage control in msg, we take care of that. */ void DeviceManager::checkMsg (XMLEle *root, INDI_D *dp) { XMLAtt *ap; ap = findXMLAtt(root, "message"); if (ap) doMsg(root, dp); } /* display valu of message and timestamp in dp's scrolled area, if any, else general. * prefix our time stamp if not included. * N.B. don't put carriage control in msg, we take care of that. */ void DeviceManager::doMsg (XMLEle *msg, INDI_D *dp) { TQTextEdit *txt_w; XMLAtt *message; XMLAtt *timestamp; if (dp == NULL) { kdDebug() << "Warning: dp is null." << endl; return; } txt_w = dp->msgST_w; /* prefix our timestamp if not with msg */ timestamp = findXMLAtt (msg, "timestamp"); if (timestamp) txt_w->insert(TQString(valuXMLAtt(timestamp)) + TQString(" ")); else txt_w->insert( KStarsDateTime::currentDateTime().toString("yyyy/mm/dd - h:m:s ap ")); /* finally! the msg */ message = findXMLAtt(msg, "message"); txt_w->insert( TQString(valuXMLAtt(message)) + TQString("\n")); if ( Options::indiMessages() ) parent->ksw->statusBar()->changeItem( TQString(valuXMLAtt(message)), 0); } void DeviceManager::sendNewText (INDI_P *pp) { INDI_E *lp; fprintf(serverFP, "pg->dp->name.ascii()); fprintf(serverFP, " name='%s'\n>", pp->name.ascii()); for (lp = pp->el.first(); lp != NULL; lp = pp->el.next()) { fprintf(serverFP, " \n", lp->name.ascii()); fprintf(serverFP, " %s\n", lp->text.ascii()); fprintf(serverFP, " \n"); } fprintf(serverFP, "\n"); } void DeviceManager::sendNewNumber (INDI_P *pp) { INDI_E *lp; fprintf(serverFP, "pg->dp->name.ascii()); fprintf(serverFP, " name='%s'\n>", pp->name.ascii()); for (lp = pp->el.first(); lp != NULL; lp = pp->el.next()) { fprintf(serverFP, " \n", lp->name.ascii()); fprintf(serverFP, " %g\n", lp->targetValue); fprintf(serverFP, " \n"); } fprintf(serverFP, "\n"); } void DeviceManager::sendNewSwitch (INDI_P *pp, int index) { INDI_E *lp; int i=0; fprintf (serverFP,"pg->dp->name.ascii()); fprintf (serverFP," name='%s'>\n", pp->name.ascii()); for (lp = pp->el.first(); lp != NULL; lp = pp->el.next(), i++) if (i == index) { fprintf (serverFP," \n", lp->name.ascii()); fprintf (serverFP," %s\n", lp->state == PS_ON ? "On" : "Off"); fprintf (serverFP," \n"); break; } fprintf (serverFP, "\n"); } void DeviceManager::startBlob (TQString devName, TQString propName, TQString timestamp) { fprintf (serverFP, "\n", timestamp.ascii()); } void DeviceManager::sendOneBlob(TQString blobName, unsigned int blobSize, TQString blobFormat, unsigned char * blobBuffer) { fprintf (serverFP, " \n", blobFormat.ascii()); for (unsigned i = 0; i < blobSize; i += 72) fprintf (serverFP, " %.72s\n", blobBuffer+i); fprintf (serverFP, " \n"); } void DeviceManager::finishBlob() { fprintf (serverFP, "\n"); } #include "devicemanager.moc"