LCOV - code coverage report
Current view: top level - libMagAOX/app - indiDriver.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 33.7 % 86 29
Test Date: 2026-01-03 21:03:39 Functions: 41.7 % 12 5

            Line data    Source code
       1              : /** \file indiDriver.hpp
       2              :   * \brief MagAO-X INDI Driver Wrapper
       3              :   * \author Jared R. Males (jaredmales@gmail.com)
       4              :   *
       5              :   * History:
       6              :   * - 2018-05-26 created by JRM
       7              :   *
       8              :   * \ingroup app_files
       9              :   */
      10              : 
      11              : #ifndef app_indiDriver_hpp
      12              : #define app_indiDriver_hpp
      13              : 
      14              : #include "../../INDI/libcommon/IndiDriver.hpp"
      15              : #include "../../INDI/libcommon/IndiElement.hpp"
      16              : 
      17              : #include "../../INDI/libcommon/IndiClient.hpp"
      18              : 
      19              : #include "MagAOXApp.hpp"
      20              : 
      21              : namespace MagAOX
      22              : {
      23              : namespace app
      24              : {
      25              : 
      26              : ///Simple INDI Client class
      27              : class indiClient : public pcf::IndiClient
      28              : {
      29              : 
      30              : public:
      31              : 
      32              :    /// Constructor, which establishes the INDI client connection.
      33            0 :    indiClient( const std::string & clientName,
      34              :                const std::string & hostAddress,
      35              :                const int hostPort
      36            0 :              ) : pcf::IndiClient( clientName, "none", "1.7", hostAddress, hostPort)
      37              :    {
      38            0 :    }
      39              : 
      40              : 
      41              :    /// Implementation of the pcf::IndiClient interface, called by activate to actually begins the INDI event loop.
      42              :    /** This is necessary to detect server restarts.
      43              :      */
      44            0 :    void execute()
      45              :    {
      46            0 :       processIndiRequests(false);
      47            0 :    }
      48              : 
      49              : };
      50              : 
      51              : template<class _parentT>
      52              : class indiDriver : public pcf::IndiDriver
      53              : {
      54              : public:
      55              : 
      56              :    ///The parent MagAOX app.
      57              :    typedef _parentT parentT;
      58              : 
      59              : protected:
      60              : 
      61              :    ///This objects parent class
      62              :    parentT * m_parent {nullptr};
      63              : 
      64              :    ///An INDI Client is used to send commands to other drivers.
      65              :    indiClient * m_outGoing {nullptr};
      66              : 
      67              :    ///The IP address of the server for the INDI Client connection
      68              :    std::string m_serverIPAddress {"127.0.01"};
      69              : 
      70              :    ///The port of the server for the INDI Client connection
      71              :    int m_serverPort {7624};
      72              : 
      73              : private:
      74              : 
      75              :    /// Flag to hold the status of this connection.
      76              :    bool m_good {true};
      77              : 
      78              : public:
      79              : 
      80              :    /// Public c'tor
      81              :    /** Call pcf::IndiDriver c'tor, and then opens the FIFOs specified
      82              :      * by parent.  If this fails, then m_good is set to false.
      83              :      * test this with good().
      84              :      */
      85              :    indiDriver( parentT * parent,
      86              :                const std::string &szName,
      87              :                const std::string &szDriverVersion,
      88              :                const std::string &szProtocolVersion
      89              :              );
      90              : 
      91              :    /// D'tor, deletes the IndiClient pointer.
      92              :    ~indiDriver();
      93              : 
      94              :    /// Get the value of the good flag.
      95              :    /**
      96              :      * \returns the value of m_good, true or false.
      97              :      */
      98            3 :    bool good(){ return m_good;}
      99              : 
     100              :    // override callbacks
     101              :    virtual void handleDefProperty( const pcf::IndiProperty &ipRecv );
     102              : 
     103              :    virtual void handleGetProperties( const pcf::IndiProperty &ipRecv );
     104              : 
     105              :    virtual void handleNewProperty( const pcf::IndiProperty &ipRecv );
     106              : 
     107              :    virtual void handleSetProperty( const pcf::IndiProperty &ipRecv );
     108              : 
     109              :    /// Define the execute virtual function.  This runs the processIndiRequests function in this thread, and does not return.
     110              :    virtual void execute(void);
     111              : 
     112              :    /// Define the update virt. func. here so the uptime message isn't sent
     113              :    virtual void update();
     114              : 
     115              :    /// Send a newProperty command to another INDI driver
     116              :    /** Uses the IndiClient member of this class, which is initialized the first time if necessary.
     117              :      *
     118              :      * \returns 0 on success
     119              :      * \returns -1 on any errors (which are logged).
     120              :      */
     121              :    virtual int sendNewProperty( const pcf::IndiProperty &ipRecv );
     122              : 
     123              : };
     124              : 
     125              : template<class parentT>
     126           12 : indiDriver<parentT>::indiDriver ( parentT * parent,
     127              :                                   const std::string &szName,
     128              :                                   const std::string &szDriverVersion,
     129              :                                   const std::string &szProtocolVersion
     130           24 :                                 ) : pcf::IndiDriver(szName, szDriverVersion, szProtocolVersion)
     131              : {
     132           12 :    m_parent = parent;
     133              : 
     134              :    int fd;
     135              : 
     136           12 :    errno = 0;
     137           12 :    fd = open( parent->driverInName().c_str(), O_RDWR);
     138           12 :    if(fd < 0)
     139              :    {
     140            9 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening input INDI FIFO."});
     141            9 :       m_good = false;
     142            9 :       return;
     143              :    }
     144            3 :    setInputFd(fd);
     145              : 
     146            3 :    errno = 0;
     147            3 :    fd = open( parent->driverOutName().c_str(), O_RDWR);
     148            3 :    if(fd < 0)
     149              :    {
     150            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening output INDI FIFO."});
     151            0 :       m_good = false;
     152            0 :       return;
     153              :    }
     154            3 :    setOutputFd(fd);
     155              : 
     156              :    // Open the ctrl fifo and write a single byte to it to trigger a restart
     157              :    // of the xindidriver process.
     158              :    // This allows indiserver to refresh everything.
     159            3 :    errno = 0;
     160            3 :    fd = open( parent->driverCtrlName().c_str(), O_RDWR);
     161            3 :    if(fd < 0)
     162              :    {
     163            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening control INDI FIFO."});
     164            0 :       m_good = false;
     165            0 :       return;
     166              :    }
     167            3 :    char c = 0;
     168            3 :    int wrno = write(fd, &c, 1);
     169            3 :    if(wrno < 0)
     170              :    {
     171            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error writing to control INDI FIFO."});
     172            0 :       m_good = false;
     173              :    }
     174              : 
     175              : 
     176            3 :    close(fd);
     177            0 : }
     178              : 
     179              : template<class parentT>
     180           24 : indiDriver<parentT>::~indiDriver()
     181              : {
     182            0 :    if(m_outGoing) delete m_outGoing;
     183              : 
     184           24 : }
     185              : template<class parentT>
     186            0 : void indiDriver<parentT>::handleDefProperty( const pcf::IndiProperty &ipRecv )
     187              : {
     188            0 :    if(m_parent) m_parent->handleDefProperty(ipRecv);
     189            0 : }
     190              : 
     191              : template<class parentT>
     192            0 : void indiDriver<parentT>::handleGetProperties( const pcf::IndiProperty &ipRecv )
     193              : {
     194            0 :    if(m_parent) m_parent->handleGetProperties(ipRecv);
     195            0 : }
     196              : 
     197              : template<class parentT>
     198            0 : void indiDriver<parentT>::handleNewProperty( const pcf::IndiProperty &ipRecv )
     199              : {
     200            0 :    if(m_parent) m_parent->handleNewProperty(ipRecv);
     201            0 : }
     202              : 
     203              : template<class parentT>
     204            0 : void indiDriver<parentT>::handleSetProperty( const pcf::IndiProperty &ipRecv )
     205              : {
     206            0 :    if(m_parent) m_parent->handleSetProperty(ipRecv);
     207            0 : }
     208              : 
     209              : template<class parentT>
     210            3 : void indiDriver<parentT>::execute()
     211              : {
     212            3 :    processIndiRequests(false);
     213            3 : }
     214              : 
     215              : template<class parentT>
     216            3 : void  indiDriver<parentT>::update()
     217              : {
     218            3 :    return;
     219              : }
     220              : 
     221              : template<class parentT>
     222            0 : int  indiDriver<parentT>::sendNewProperty( const pcf::IndiProperty &ipRecv )
     223              : {
     224              :    //If there is an existing client, check if it has exited.
     225            0 :    if( m_outGoing != nullptr)
     226              :    {
     227            0 :       if(m_outGoing->getQuitProcess())
     228              :       {
     229            0 :          parentT::template log<logger::text_log>("INDI client disconnected.");
     230            0 :          m_outGoing->quitProcess();
     231            0 :          m_outGoing->deactivate();
     232            0 :          delete m_outGoing;
     233            0 :          m_outGoing = nullptr;
     234              :       }
     235              :    }
     236              : 
     237              :    //Connect if needed
     238            0 :    if( m_outGoing == nullptr)
     239              :    {
     240              :       try
     241              :       {
     242            0 :          m_outGoing = new indiClient(m_parent->configName()+"-client", m_serverIPAddress, m_serverPort);
     243            0 :          m_outGoing->activate();
     244              :       }
     245            0 :       catch(...)
     246              :       {
     247            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception thrown while creating IndiClient connection"});
     248            0 :          return -1;
     249              :       }
     250              : 
     251            0 :       if(m_outGoing == nullptr)
     252              :       {
     253            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "Failed to allocate IndiClient connection"});
     254            0 :          return -1;
     255              :       }
     256              : 
     257            0 :       parentT::template log<logger::text_log>("INDI client connected and activated");
     258              :    }
     259              : 
     260              :    try
     261              :    {
     262            0 :       m_outGoing->sendNewProperty(ipRecv);
     263            0 :       if(m_outGoing->getQuitProcess())
     264              :       {
     265            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "INDI client appears to be disconnected -- NEW not sent."});
     266            0 :          return -1;
     267              :       }
     268              : 
     269              :       //m_outGoing->quitProcess();
     270              :       //delete m_outGoing;
     271              :       //m_outGoing = nullptr;
     272            0 :       return 0;
     273              :    }
     274            0 :    catch(std::exception & e)
     275              :    {
     276            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, std::string("Exception from IndiClient: ") + e.what()});
     277            0 :       return -1;
     278              :    }
     279            0 :    catch(...)
     280              :    {
     281            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception from IndiClient"});
     282            0 :       return -1;
     283              :    }
     284              : 
     285              :    //Should never get here, but we are exiting for some reason sometimes.
     286              :    parentT::template log<logger::software_error>({__FILE__, __LINE__, "fall through in sendNewProperty"});
     287              :    return -1;
     288              : }
     289              : 
     290              : } //namespace app
     291              : } //namespace MagAOX
     292              : 
     293              : #endif //app_magAOXIndiDriver_hpp
        

Generated by: LCOV version 2.0-1