• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kstars

indidevice.cpp

Go to the documentation of this file.
00001 /*  INDI frontend for KStars
00002     Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
00003                    Elwood C. Downey.
00004 
00005     This application is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     JM Changelog:
00011     2003-04-28 Used indimenu.c as a template. C --> C++, Xm --> KDE/Qt
00012     2003-05-01 Added tab for devices and a group feature
00013     2003-05-02 Added scrolling area. Most things are rewritten
00014     2003-05-05 Device/Group seperation
00015     2003-05-29 Replaced raw INDI time with KStars's timedialog
00016     2003-08-02 Upgrading to INDI v 1.11
00017     2003-08-09 Initial support for non-sidereal tracking
00018     2004-01-15 redesigning the GUI to support INDI v1.2 and fix previous GUI bugs
00019                and problems. The new GUI can easily incoperate extensions to the INDI
00020            protocol as required. 
00021 
00022  */
00023 
00024 #include "indiproperty.h"
00025 #include "indigroup.h"
00026 #include "indidevice.h"
00027 #include "devicemanager.h"
00028 #include "indimenu.h"
00029 #include "indidriver.h"
00030 #include "indistd.h"
00031 #include "indi/indicom.h"
00032 #include "kstars.h"
00033 #include "skyobject.h"
00034 #include "timedialog.h"
00035 #include "geolocation.h"
00036 #include "indi/base64.h"
00037 
00038 #include <sys/socket.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 #include <netdb.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <termios.h>
00045 #include <zlib.h>
00046 
00047 #include <qlineedit.h>
00048 #include <qtextedit.h>
00049 #include <qframe.h>
00050 #include <qtabwidget.h>
00051 #include <qcheckbox.h>
00052 #include <qlabel.h>
00053 #include <qpushbutton.h>
00054 #include <qlayout.h>
00055 #include <qtooltip.h>
00056 #include <qwhatsthis.h>
00057 #include <qbuttongroup.h>
00058 #include <qscrollview.h>
00059 #include <qsocketnotifier.h>
00060 #include <qvbox.h>
00061 #include <qdatetime.h>
00062 #include <qtable.h>
00063 #include <qstring.h>
00064 #include <qptrlist.h>
00065 
00066 #include <kled.h>
00067 #include <klineedit.h>
00068 #include <kpushbutton.h>
00069 #include <kapplication.h>
00070 #include <klocale.h>
00071 #include <kmessagebox.h>
00072 #include <klistview.h>
00073 #include <kdebug.h>
00074 #include <kcombobox.h>
00075 #include <knuminput.h>
00076 #include <kdialogbase.h>
00077 #include <kstatusbar.h>
00078 #include <kpopupmenu.h>
00079 
00080 #define NINDI_STD   26
00081 /* INDI standard property used across all clients to enable interoperability. */
00082 
00083 const char * indi_std[NINDI_STD] = 
00084   {"CONNECTION", "DEVICE_PORT", "TIME", "SDTIME", "GEOGRAPHIC_COORD", "EQUATORIAL_COORD", "EQUATORIAL_EOD_COORD", "HORIZONTAL_COORD", "ABORT_MOTION", "ON_COORD_SET", "SOLAR_SYSTEM", "MOVEMENT", "PARK", "CCD_EXPOSE_DURATION", "CCD_TEMPERATURE", "CCD_FRAME", "CCD_FRAME_TYPE", "CCD_BINNING", "CCD_INFO", "CCDPREVIEW_STREAM", "CCDPREVIEW_CTRL", "VIDEO_STREAM", "FOCUS_SPEED", "FOCUS_MOTION", "FOCUS_TIMER", "FILTER_SLOT" };
00085 
00086 /*******************************************************************
00087 ** INDI Device: The work-horse. Responsible for handling its
00088 ** child properties and managing signal and changes.
00089 *******************************************************************/
00090 INDI_D::INDI_D(INDIMenu *menuParent, DeviceManager *parentManager, QString inName, QString inLabel) 
00091 {
00092   name      = inName;
00093   label     = inLabel;
00094   parent    = menuParent;
00095   parentMgr = parentManager;
00096   
00097   gl.setAutoDelete(true);
00098 
00099  deviceVBox     = menuParent->addVBoxPage(inLabel);
00100  groupContainer = new QTabWidget(deviceVBox);
00101  
00102  msgST_w        = new QTextEdit(deviceVBox);
00103  msgST_w->setReadOnly(true);
00104  msgST_w->setMaximumHeight(100);
00105 
00106  dataBuffer = (unsigned char *) malloc (1);
00107  
00108  stdDev     = new INDIStdDevice(this, parent->ksw);
00109 
00110  curGroup       = NULL;
00111 
00112  INDIStdSupport = false;
00113 
00114 }
00115 
00116 INDI_D::~INDI_D()
00117 {
00118    gl.clear();
00119    delete(deviceVBox);
00120    delete (stdDev);
00121    free (dataBuffer);
00122    dataBuffer = NULL;
00123    deviceVBox = NULL;
00124    stdDev     = NULL;
00125 }
00126 
00127 void INDI_D::registerProperty(INDI_P *pp)
00128 {
00129    
00130    if (isINDIStd(pp))
00131     pp->pg->dp->INDIStdSupport = true;
00132     
00133     stdDev->registerProperty(pp);
00134      
00135 }
00136 
00137 bool INDI_D::isINDIStd(INDI_P *pp)
00138 {
00139   for (uint i=0; i < NINDI_STD; i++)
00140     if (!strcmp(pp->name.ascii(), indi_std[i]))
00141     {
00142       pp->stdID = i;
00143       return true;
00144     }
00145       
00146   return false;
00147 }
00148 
00149 /* Remove a property from a group, if there are no more properties 
00150  * left in the group, then delete the group as well */
00151 int INDI_D::removeProperty(INDI_P *pp)
00152 {
00153     for (unsigned int i=0; i < gl.count(); i++)
00154        if (gl.at(i)->removeProperty(pp))
00155        {
00156          if (gl.at(i)->pl.count() == 0)
00157         gl.remove(i);
00158          return 0;
00159     }
00160 
00161 
00162     kdDebug() << "INDI: Device " << name << " has no property named " << pp->name << endl;
00163     return (-1);
00164 }
00165 
00166 /* implement any <set???> received from the device.
00167  * return 0 if ok, else -1 with reason in errmsg[]
00168  */
00169 int INDI_D::setAnyCmd (XMLEle *root, char errmsg[])
00170 {
00171     XMLAtt *ap;
00172     INDI_P *pp;
00173     
00174     ap = findAtt (root, "name", errmsg);
00175     if (!ap)
00176         return (-1);
00177 
00178     pp = findProp (valuXMLAtt(ap));
00179     if (!pp)
00180     {
00181         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.32s> device %.32s has no property named %.64s",
00182                         tagXMLEle(root), name.ascii(), valuXMLAtt(ap));
00183         return (-1);
00184     }
00185 
00186     parentMgr->checkMsg (root, this);
00187 
00188     return (setValue (pp, root, errmsg));
00189 }
00190 
00191 /* set the given GUI property according to the XML command.
00192  * return 0 if ok else -1 with reason in errmsg
00193  */
00194 int INDI_D::setValue (INDI_P *pp, XMLEle *root, char errmsg[])
00195 {
00196     XMLAtt *ap;
00197 
00198     /* set overall property state, if any */
00199     ap = findXMLAtt (root, "state");
00200     if (ap)
00201     {
00202         if (crackLightState (valuXMLAtt(ap), &pp->state) == 0)
00203           pp->drawLt (pp->state);
00204         else
00205         {
00206         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> bogus state %.64s for %.64s %.64s",
00207                         tagXMLEle(root), valuXMLAtt(ap), name.ascii(), pp->name.ascii());
00208         return (-1);
00209         }
00210     }
00211     
00212     /* allow changing the timeout */
00213     ap = findXMLAtt (root, "timeout");
00214     if (ap)
00215         pp->timeout = atof(valuXMLAtt(ap));
00216 
00217     /* process specific GUI features */
00218     switch (pp->guitype)
00219     {
00220     case PG_NONE:
00221         break;
00222 
00223     case PG_NUMERIC:    /* FALLTHRU */
00224     case PG_TEXT:
00225         return (setTextValue (pp, root, errmsg));
00226         break;
00227 
00228     case PG_BUTTONS:    
00229     case PG_LIGHTS:
00230     case PG_RADIO:      
00231     case PG_MENU:
00232         return (setLabelState (pp, root, errmsg));
00233         break;
00234         
00235     case PG_BLOB:
00236         return (setBLOB(pp, root, errmsg));
00237         break;
00238 
00239     default:
00240         break;
00241     }
00242 
00243     return (0);
00244 }
00245 
00246 
00247 /* set the given TEXT or NUMERIC property from the given element.
00248  * root should have <text> or <number> child.
00249  * return 0 if ok else -1 with reason in errmsg
00250  */
00251 int INDI_D::setTextValue (INDI_P *pp, XMLEle *root, char errmsg[])
00252 {
00253     XMLEle *ep;
00254     XMLAtt *ap;
00255     INDI_E *lp;
00256     QString elementName;
00257     char iNumber[32];
00258     double min, max;
00259     
00260     for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
00261     {
00262         if (strcmp (tagXMLEle(ep), "oneText") && strcmp(tagXMLEle(ep), "oneNumber"))
00263         continue;
00264 
00265         ap = findXMLAtt(ep, "name");
00266         if (!ap)
00267         {
00268             kdDebug() << "Error: unable to find attribute 'name' for property " << pp->name << endl;
00269             return (-1);
00270         }
00271 
00272         elementName = valuXMLAtt(ap);
00273         
00274         lp = pp->findElement(elementName);
00275         
00276         if (!lp)
00277         {
00278           snprintf(errmsg, ERRMSG_SIZE, "Error: unable to find element '%.64s' in property '%.64s'", elementName.ascii(), pp->name.ascii());
00279           return (-1);
00280         }
00281         
00282         //fprintf(stderr, "tag okay, getting perm\n");
00283        switch (pp->perm)
00284        {
00285        case PP_RW:  // FALLTHRU
00286        case PP_RO:
00287          if (pp->guitype == PG_TEXT)
00288          {
00289             lp->text = QString(pcdataXMLEle(ep));
00290         lp->read_w->setText(lp->text);
00291              }
00292          else if (pp->guitype == PG_NUMERIC)
00293          {
00294            lp->value = atof(pcdataXMLEle(ep));
00295            numberFormat(iNumber, lp->format.ascii(), lp->value);
00296            lp->text = iNumber;
00297            lp->read_w->setText(lp->text);
00298            
00299            ap = findXMLAtt (ep, "min");
00300            if (ap) { min = atof(valuXMLAtt(ap)); lp->setMin(min); }
00301            ap = findXMLAtt (ep, "max");
00302            if (ap) { max = atof(valuXMLAtt(ap)); lp->setMax(max); }
00303            
00304            /*if (lp->spin_w)
00305            {
00306             lp->spin_w->setValue(lp->value);
00307         lp->spinChanged(lp->value);
00308          }*/
00309           
00310          }
00311          break;
00312 
00313     case PP_WO:
00314         if (pp->guitype == PG_TEXT)
00315           lp->write_w->setText(QString(pcdataXMLEle(ep)));
00316         else if (pp->guitype == PG_NUMERIC)
00317         {
00318           lp->value = atof(pcdataXMLEle(ep));
00319           numberFormat(iNumber, lp->format.ascii(), lp->value);
00320           lp->text = iNumber;
00321 
00322           if (lp->spin_w)
00323                 lp->spin_w->setValue(lp->value);
00324           else
00325             lp->write_w->setText(lp->text);
00326         
00327            ap = findXMLAtt (ep, "min");
00328            if (ap) { min = (int) atof(valuXMLAtt(ap)); lp->setMin(min); }
00329            ap = findXMLAtt (ep, "max");
00330            if (ap) { max = (int) atof(valuXMLAtt(ap)); lp->setMax(max); }
00331         }
00332         break;
00333 
00334       }
00335        }
00336 
00337        /* handle standard cases if needed */
00338        stdDev->setTextValue(pp);
00339         
00340     // suppress warning
00341     errmsg = errmsg;
00342 
00343     return (0);
00344 }
00345 
00346 /* set the given BUTTONS or LIGHTS property from the given element.
00347  * root should have some <switch> or <light> children.
00348  * return 0 if ok else -1 with reason in errmsg
00349  */
00350 int INDI_D::setLabelState (INDI_P *pp, XMLEle *root, char errmsg[])
00351 {
00352     int menuChoice=0;
00353     unsigned i=0;
00354     XMLEle *ep;
00355     XMLAtt *ap;
00356         INDI_E *lp = NULL;
00357     int islight;
00358     PState state;
00359 
00360     /* for each child element */
00361     for (ep = nextXMLEle (root, 1), i=0; ep != NULL; ep = nextXMLEle (root, 0), i++)
00362     {
00363         
00364         /* only using light and switch */
00365         islight = !strcmp (tagXMLEle(ep), "oneLight");
00366         if (!islight && strcmp (tagXMLEle(ep), "oneSwitch"))
00367         continue;
00368 
00369         ap =  findXMLAtt (ep, "name");
00370         /* no name */
00371         if (!ap)
00372         {
00373         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s %.64s requires name",
00374                             tagXMLEle(root), name.ascii(), pp->name.ascii(), tagXMLEle(ep));
00375         return (-1);
00376         }
00377 
00378         if ((islight && crackLightState (pcdataXMLEle(ep), &state) < 0)
00379             || (!islight && crackSwitchState (pcdataXMLEle(ep), &state) < 0))
00380         {
00381         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown state %.64s for %.64s %.64s %.64s",
00382                         tagXMLEle(root), pcdataXMLEle(ep), name.ascii(), pp->name.ascii(), tagXMLEle(ep));
00383         return (-1);
00384         }
00385 
00386         /* find matching label */
00387         //fprintf(stderr, "Find matching label. Name from XML is %s\n", valuXMLAtt(ap));
00388         lp = pp->findElement(QString(valuXMLAtt(ap)));
00389 
00390         if (!lp)
00391         {
00392         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s has no choice named %.64s",
00393                             tagXMLEle(root), name.ascii(), pp->name.ascii(), valuXMLAtt(ap));
00394         return (-1);
00395         }
00396 
00397         QFont buttonFont;
00398         /* engage new state */
00399         lp->state = state;
00400 
00401         switch (pp->guitype)
00402         {
00403          case PG_BUTTONS:
00404           if (islight)
00405            break;
00406 
00407                 lp->push_w->setDown(state == PS_ON ? true : false);
00408         buttonFont = lp->push_w->font();
00409         buttonFont.setBold(state == PS_ON ? TRUE : FALSE);
00410         lp->push_w->setFont(buttonFont);
00411 
00412         break;
00413 
00414          case PG_RADIO:
00415                  lp->check_w->setChecked(state == PS_ON ? true : false);
00416          break;
00417          case PG_MENU:
00418            if (state == PS_ON)
00419            {
00420             if (menuChoice)
00421             {
00422                 snprintf(errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s has multiple ON states", tagXMLEle(root), name.ascii(), pp->name.ascii());
00423             return (-1);
00424                 }
00425             menuChoice = 1;
00426             pp->om_w->setCurrentItem(i);
00427            }
00428            break;
00429            
00430          case PG_LIGHTS:
00431           lp->drawLt();
00432           break;
00433 
00434          default:
00435           break;
00436        }
00437 
00438     }
00439     
00440     stdDev->setLabelState(pp);
00441 
00442     return (0);
00443 }
00444 
00445 /* Set BLOB vector. Process incoming data stream
00446  * Return 0 if okay, -1 if error 
00447 */
00448 int INDI_D::setBLOB(INDI_P *pp, XMLEle * root, char errmsg[])
00449 {
00450   
00451   XMLEle *ep;
00452   INDI_E *blobEL;
00453   
00454   for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0))
00455   {
00456     
00457     if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
00458     {
00459       
00460       blobEL = pp->findElement(QString(findXMLAttValu (ep, "name")));
00461       
00462       if (blobEL)
00463     return processBlob(blobEL, ep, errmsg);
00464       else
00465       {
00466     sprintf (errmsg, "INDI: set %64s.%64s.%64s not found", name.ascii(), pp->name.ascii(), findXMLAttValu(ep, "name"));
00467     return (-1);
00468       }
00469     }
00470   }
00471   
00472   return (0);
00473   
00474 }
00475 
00476 /* Process incoming data stream
00477  * Return 0 if okay, -1 if error 
00478 */
00479 int INDI_D::processBlob(INDI_E *blobEL, XMLEle *ep, char errmsg[])
00480 {
00481   XMLAtt *ap;
00482   int blobSize=0, r=0, dataType=0;
00483   uLongf dataSize=0;
00484   QString dataFormat;
00485   char *baseBuffer;
00486   unsigned char *blobBuffer(NULL);
00487   bool iscomp(false);
00488   
00489   ap = findXMLAtt(ep, "size");
00490   if (!ap)
00491   {
00492     sprintf (errmsg, "INDI: set %64s size not found", blobEL->name.ascii());
00493     return (-1);
00494   }
00495   
00496   dataSize = atoi(valuXMLAtt(ap));
00497   
00498   ap = findXMLAtt(ep, "format");
00499   if (!ap)
00500   {
00501     sprintf (errmsg, "INDI: set %64s format not found", blobEL->name.ascii());
00502     return (-1);
00503   }
00504   
00505   dataFormat = QString(valuXMLAtt(ap));
00506   
00507   baseBuffer = (char *) malloc ( (3*pcdatalenXMLEle(ep)/4) * sizeof (char));
00508   blobSize   = from64tobits (baseBuffer, pcdataXMLEle(ep));
00509   blobBuffer = (unsigned char *) baseBuffer;
00510   
00511   /* Blob size = 0 when only state changes */
00512   if (dataSize == 0)
00513   {
00514     free (blobBuffer);
00515     return (0);
00516   }
00517   else if (blobSize < 0)
00518   {
00519     free (blobBuffer);
00520     sprintf (errmsg, "INDI: %64s.%64s.%64s bad base64", name.ascii(), blobEL->pp->name.ascii(), blobEL->name.ascii());
00521     return (-1);
00522   }
00523   
00524   iscomp = (dataFormat.find(".z") != -1);
00525   
00526   dataFormat.remove(".z");
00527   
00528   if (dataFormat == ".fits") dataType = DATA_FITS;
00529   else if (dataFormat == ".stream") dataType = DATA_STREAM;
00530   else if (dataFormat == ".ccdpreview") dataType = DATA_CCDPREVIEW;   
00531   else dataType = DATA_OTHER;
00532   
00533   //kdDebug() << "We're getting data with size " << dataSize << endl;
00534   //kdDebug() << "data format " << dataFormat << endl;
00535 
00536   if (iscomp)
00537   {
00538     
00539     dataBuffer = (unsigned char *) realloc (dataBuffer,  (dataSize * sizeof(unsigned char)));
00540     r = uncompress(dataBuffer, &dataSize, blobBuffer, (uLong) blobSize);
00541     if (r != Z_OK)
00542     {
00543       sprintf(errmsg, "INDI: %64s.%64s.%64s compression error: %d", name.ascii(), blobEL->pp->name.ascii(), blobEL->name.ascii(), r);    
00544       free (blobBuffer);
00545       return -1;
00546     }
00547 
00548     //kdDebug() << "compressed" << endl;
00549   }
00550   else
00551   {
00552     //kdDebug() << "uncompressed!!" << endl;
00553     dataBuffer = (unsigned char *) realloc (dataBuffer,  (dataSize * sizeof(unsigned char)));
00554     memcpy(dataBuffer, blobBuffer, dataSize);
00555   }
00556   
00557   stdDev->handleBLOB(dataBuffer, dataSize, dataFormat);
00558 
00559   free (blobBuffer);
00560   
00561   return (0);
00562   
00563 }
00564 
00565 bool INDI_D::isOn()
00566 {
00567 
00568   INDI_P *prop;
00569 
00570   prop = findProp(QString("CONNECTION"));
00571   if (!prop)
00572    return false;
00573 
00574   return (prop->isOn(QString("CONNECT")));
00575 }
00576 
00577 INDI_P * INDI_D::addProperty (XMLEle *root, char errmsg[])
00578 {
00579     INDI_P *pp = NULL;
00580     INDI_G *pg = NULL;
00581     XMLAtt *ap = NULL;
00582 
00583         // Search for group tag
00584     ap = findAtt (root, "group", errmsg);
00585         if (!ap)
00586         {
00587                 kdDebug() << QString(errmsg) << endl;
00588                 return NULL;
00589         }
00590     // Find an existing group, if none found, create one
00591         pg = findGroup(QString(valuXMLAtt(ap)), 1, errmsg);
00592 
00593     if (!pg)
00594      return NULL;
00595 
00596         /* get property name and add new property to dp */
00597     ap = findAtt (root, "name", errmsg);
00598     if (ap == NULL)
00599         return NULL;
00600 
00601     if (findProp (valuXMLAtt(ap)))
00602     {
00603         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s %.64s %.64s> already exists.\n", tagXMLEle(root),
00604                             name.ascii(), valuXMLAtt(ap));
00605         return NULL;
00606     }
00607 
00608     /* Remove Vertical spacer from group layout, this is done everytime
00609       * a new property arrives. The spacer is then appended to the end of the 
00610       * properties */
00611     pg->propertyLayout->removeItem(pg->VerticalSpacer);
00612     
00613     pp = new INDI_P(pg, QString(valuXMLAtt(ap)));
00614 
00615     /* init state */
00616     ap = findAtt (root, "state", errmsg);
00617     if (!ap)
00618     {
00619         delete(pp);
00620         return (NULL);
00621     }
00622 
00623     if (crackLightState (valuXMLAtt(ap), &pp->state) < 0)
00624     {
00625         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> bogus state %.64s for %.64s %.64s",
00626                 tagXMLEle(root), valuXMLAtt(ap), pp->pg->dp->name.ascii(), pp->name.ascii());
00627         delete(pp);
00628         return (NULL);
00629     }
00630 
00631     /* init timeout */
00632     ap = findAtt (root, "timeout", NULL);
00633     /* default */
00634     pp->timeout = ap ? atof(valuXMLAtt(ap)) : 0;
00635 
00636     /* log any messages */
00637     parentMgr->checkMsg (root, this);
00638 
00639     pp->addGUI(root);
00640 
00641     /* ok! */
00642     return (pp);
00643 }
00644 
00645 INDI_P * INDI_D::findProp (QString name)
00646 {
00647        for (unsigned int i = 0; i < gl.count(); i++)
00648     for (unsigned int j = 0; j < gl.at(i)->pl.count(); j++)
00649         if (name == gl.at(i)->pl.at(j)->name)
00650         return (gl.at(i)->pl.at(j));
00651 
00652     return NULL;
00653 }
00654 
00655 INDI_G *  INDI_D::findGroup (QString grouptag, int create, char errmsg[])
00656 {
00657   INDI_G *ig;
00658   
00659   for (ig = gl.first(); ig != NULL; ig = gl.next() )
00660     if (ig->name == grouptag)
00661     {
00662       curGroup = ig;
00663       return ig;
00664     }
00665 
00666   /* couldn't find an existing group, create a new one if create is 1*/
00667   if (create)
00668   {
00669     if (grouptag.isEmpty())
00670       grouptag = "Group_1";
00671       
00672     curGroup = new INDI_G(this, grouptag);
00673     gl.append(curGroup);
00674         return curGroup;
00675   }
00676 
00677   snprintf (errmsg, ERRMSG_SIZE, "INDI: group %.64s not found in %.64s", grouptag.ascii(), name.ascii());
00678   return NULL;
00679 }
00680 
00681 
00682 /* find "perm" attribute in root, crack and set *pp.
00683  * return 0 if ok else -1 with excuse in errmsg[]
00684  */
00685 
00686  int INDI_D::findPerm (INDI_P *pp, XMLEle *root, PPerm *permp, char errmsg[])
00687 {
00688     XMLAtt *ap;
00689 
00690     ap = findXMLAtt(root, "perm");
00691     if (!ap) {
00692         snprintf (errmsg, ERRMSG_SIZE,"INDI: <%.64s %.64s %.64s> missing attribute 'perm'",
00693                     tagXMLEle(root), pp->pg->dp->name.ascii(), pp->name.ascii());
00694         return (-1);
00695     }
00696     if (!strcmp(valuXMLAtt(ap), "ro") || !strcmp(valuXMLAtt(ap), "r"))
00697         *permp = PP_RO;
00698     else if (!strcmp(valuXMLAtt(ap), "wo"))
00699         *permp = PP_WO;
00700     else if (!strcmp(valuXMLAtt(ap), "rw") || !strcmp(valuXMLAtt(ap), "w"))
00701         *permp = PP_RW;
00702     else {
00703         snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown perm %.64s for %.64s %.64s",
00704                 tagXMLEle(root), valuXMLAtt(ap), pp->pg->dp->name.ascii(), pp->name.ascii());
00705         return (-1);
00706     }
00707 
00708     return (0);
00709 }
00710 
00711 /* convert the given light/property state string to the PState at psp.
00712  * return 0 if successful, else -1 and leave *psp unchanged.
00713  */
00714 int INDI_D::crackLightState (char *name, PState *psp)
00715 {
00716     typedef struct
00717     {
00718         PState s;
00719         const char *name;
00720     } PSMap;
00721 
00722     PSMap psmap[] =
00723     {
00724         {PS_IDLE,  "Idle"},
00725         {PS_OK,    "Ok"},
00726         {PS_BUSY,  "Busy"},
00727         {PS_ALERT, "Alert"},
00728     };
00729 
00730     for (int i = 0; i < 4; i++)
00731         if (!strcmp (psmap[i].name, name)) {
00732         *psp = psmap[i].s;
00733         return (0);
00734         }
00735 
00736     return (-1);
00737 }
00738 
00739 /* convert the given switch state string to the PState at psp.
00740  * return 0 if successful, else -1 and leave *psp unchanged.
00741  */
00742 int INDI_D::crackSwitchState (char *name, PState *psp)
00743 {
00744     typedef struct
00745     {
00746         PState s;
00747         const char *name;
00748     } PSMap;
00749 
00750     PSMap psmap[] =
00751     {
00752         {PS_ON,  "On"},
00753         {PS_OFF, "Off"},
00754     };
00755 
00756 
00757     for (int i = 0; i < 2; i++)
00758         if (!strcmp (psmap[i].name, name))
00759         {
00760         *psp = psmap[i].s;
00761         return (0);
00762         }
00763 
00764     return (-1);
00765 }
00766 
00767 int INDI_D::buildTextGUI(XMLEle *root, char errmsg[])
00768 {
00769         INDI_P *pp = NULL;
00770     PPerm p;
00771 
00772     /* build a new property */
00773     pp = addProperty (root, errmsg);
00774 
00775     if (pp == NULL)
00776         return (-1);
00777 
00778     /* get the permission, it will determine layout issues */
00779     if (findPerm (pp, root, &p, errmsg))
00780     {
00781         delete(pp);
00782         return (-1);
00783     }
00784 
00785     /* we know it will be a general text GUI */
00786     pp->guitype = PG_TEXT;
00787     pp->perm = p;
00788     
00789     if (pp->buildTextGUI(root, errmsg) < 0)
00790     {
00791       delete (pp);
00792       return (-1);
00793     }
00794     
00795     pp->pg->addProperty(pp);
00796     
00797     return (0);
00798 }
00799 
00800 /* build GUI for a number property.
00801  * return 0 if ok, else -1 with reason in errmsg[]
00802  */
00803 int INDI_D::buildNumberGUI (XMLEle *root, char *errmsg)
00804 {
00805         INDI_P *pp = NULL;
00806         PPerm p;
00807 
00808         /* build a new property */
00809     pp = addProperty (root, errmsg);
00810 
00811     if (pp == NULL)
00812         return (-1);
00813 
00814     /* get the permission, it will determine layout issues */
00815     if (findPerm (pp, root, &p, errmsg))
00816     {
00817         delete(pp);
00818         return (-1);
00819     }
00820      
00821     /* we know it will be a number GUI */
00822     pp->guitype = PG_NUMERIC;
00823     pp->perm = p;
00824     
00825     if (pp->buildNumberGUI(root, errmsg) < 0)
00826     {
00827       delete (pp);
00828       return (-1);
00829     }
00830     
00831     pp->pg->addProperty(pp);
00832     
00833     return (0);
00834 }
00835     
00836 /* build GUI for switches property.
00837  * rule and number of will determine exactly how the GUI is built.
00838  * return 0 if ok, else -1 with reason in errmsg[]
00839  */
00840 int INDI_D::buildSwitchesGUI (XMLEle *root, char errmsg[])
00841 {
00842     INDI_P *pp;
00843     XMLAtt *ap;
00844     XMLEle *ep;
00845     int n, err;
00846 
00847     /* build a new property */
00848     pp = addProperty (root, errmsg);
00849     if (!pp)
00850         return (-1);
00851 
00852     ap = findAtt (root, "rule", errmsg);
00853     if (!ap)
00854     {
00855         delete(pp);
00856         return (-1);
00857     }
00858 
00859     /* decide GUI. might use MENU if OneOf but too many for button array */
00860     if (!strcmp (valuXMLAtt(ap), "OneOfMany") || !strcmp (valuXMLAtt(ap), "AtMostOne"))
00861     {
00862         /* count number of switches -- make menu if too many */
00863         for ( ep = nextXMLEle(root, 1) , n = 0 ; ep != NULL; ep = nextXMLEle(root, 0))
00864         if (!strcmp (tagXMLEle(ep), "defSwitch"))
00865             n++;
00866             
00867         if (n > MAXRADIO)
00868         {
00869             pp->guitype = PG_MENU;
00870         err = pp->buildMenuGUI (root, errmsg);
00871         if (err < 0)
00872         {
00873             delete(pp);
00874             pp=0;
00875             return err;
00876         }
00877             
00878         pp->pg->addProperty(pp);
00879         return (err);
00880         }
00881 
00882         /* otherwise, build 1-4 button layout */
00883         pp->guitype = PG_BUTTONS;
00884         
00885         err = pp->buildSwitchesGUI(root, errmsg);
00886         if (err < 0)
00887         {
00888           delete (pp);
00889           pp=0;
00890           return err;
00891         }
00892           
00893         pp->pg->addProperty(pp);
00894         return (err);
00895 
00896     }
00897     else if (!strcmp (valuXMLAtt(ap), "AnyOfMany"))
00898     {
00899         /* 1-4 checkboxes layout */
00900         pp->guitype = PG_RADIO;
00901         
00902         err = pp->buildSwitchesGUI(root, errmsg);
00903         if (err < 0)
00904         {
00905           delete (pp);
00906           pp=0;
00907           return err;
00908         }
00909           
00910         pp->pg->addProperty(pp);
00911         return (err);
00912     }
00913     
00914     snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown rule %.64s for %.64s %.64s",
00915                 tagXMLEle(root), valuXMLAtt(ap), name.ascii(), pp->name.ascii());
00916         
00917     delete(pp);
00918     return (-1);
00919 }
00920     
00921 
00922 
00923 /* build GUI for a lights GUI.
00924  * return 0 if ok, else -1 with reason in errmsg[] */
00925 int INDI_D::buildLightsGUI (XMLEle *root, char errmsg[])
00926 {
00927     INDI_P *pp;
00928 
00929     // build a new property
00930     pp = addProperty (root, errmsg);
00931     if (!pp)
00932         return (-1);
00933 
00934     pp->guitype = PG_LIGHTS;
00935     
00936     if (pp->buildLightsGUI(root, errmsg) < 0)
00937     {
00938       delete (pp);
00939       return (-1);
00940     }
00941     
00942     pp->pg->addProperty(pp);
00943     return (0);
00944 }
00945 
00946 /* build GUI for a BLOB GUI.
00947  * return 0 if ok, else -1 with reason in errmsg[] */
00948 int INDI_D::buildBLOBGUI  (XMLEle *root, char errmsg[])
00949 {
00950   INDI_P *pp;
00951   PPerm p;
00952 
00953   // build a new property
00954   pp = addProperty (root, errmsg);
00955   if (!pp)
00956     return (-1);
00957 
00958   /* get the permission, it will determine layout issues */
00959   if (findPerm (pp, root, &p, errmsg))
00960   {
00961     delete(pp);
00962     return (-1);
00963   }
00964      
00965   /* we know it will be a number GUI */
00966   pp->perm = p;
00967   pp->guitype = PG_BLOB;
00968     
00969   if (pp->buildBLOBGUI(root, errmsg) < 0)
00970   {
00971     delete (pp);
00972     return (-1);
00973   }
00974     
00975   pp->pg->addProperty(pp);
00976   return (0);
00977 }
00978 
00979 INDI_E * INDI_D::findElem(QString name)
00980 {
00981   INDI_G *grp;
00982   INDI_P *prop;
00983   INDI_E *el;
00984   
00985   for (grp = gl.first(); grp != NULL; grp = gl.next())
00986     {
00987        for (prop = grp->pl.first(); prop != NULL; prop = grp->pl.next())
00988        {
00989          el = prop->findElement(name);
00990          if (el != NULL) return el;
00991        }
00992      }
00993      
00994   return NULL;
00995 
00996 }
00997 
00998 
00999 #include "indidevice.moc"

kstars

Skip menu "kstars"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • keduca
  • kstars
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal