LCOV - code coverage report
Current view: top level - libMagAOX/app - indiDriver.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 34.8 % 89 31
Test Date: 2026-04-15 19:34:29 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              :    /// Mutex protecting the lifecycle and use of m_outGoing.
      79              :    /** This is intentionally separate from MagAOXApp::m_indiMutex so callers can
      80              :      * reach sendNewProperty() regardless of whether they already hold the app's
      81              :      * INDI lock.
      82              :      */
      83              :    std::mutex m_outGoingMutex;
      84              : 
      85              : public:
      86              : 
      87              :    /// Public c'tor
      88              :    /** Call pcf::IndiDriver c'tor, and then opens the FIFOs specified
      89              :      * by parent.  If this fails, then m_good is set to false.
      90              :      * test this with good().
      91              :      */
      92              :    indiDriver( parentT * parent,
      93              :                const std::string &szName,
      94              :                const std::string &szDriverVersion,
      95              :                const std::string &szProtocolVersion
      96              :              );
      97              : 
      98              :    /// D'tor, deletes the IndiClient pointer.
      99              :    ~indiDriver();
     100              : 
     101              :    /// Get the value of the good flag.
     102              :    /**
     103              :      * \returns the value of m_good, true or false.
     104              :      */
     105            3 :    bool good(){ return m_good;}
     106              : 
     107              :    // override callbacks
     108              :    virtual void handleDefProperty( const pcf::IndiProperty &ipRecv );
     109              : 
     110              :    virtual void handleGetProperties( const pcf::IndiProperty &ipRecv );
     111              : 
     112              :    virtual void handleNewProperty( const pcf::IndiProperty &ipRecv );
     113              : 
     114              :    virtual void handleSetProperty( const pcf::IndiProperty &ipRecv );
     115              : 
     116              :    /// Define the execute virtual function.  This runs the processIndiRequests function in this thread, and does not return.
     117              :    virtual void execute(void);
     118              : 
     119              :    /// Define the update virt. func. here so the uptime message isn't sent
     120              :    virtual void update();
     121              : 
     122              :    /// Send a newProperty command to another INDI driver
     123              :    /** Uses the IndiClient member of this class, which is initialized the first time if necessary.
     124              :      *
     125              :      * \returns 0 on success
     126              :      * \returns -1 on any errors (which are logged).
     127              :      */
     128              :    virtual int sendNewProperty( const pcf::IndiProperty &ipRecv );
     129              : 
     130              : };
     131              : 
     132              : template<class parentT>
     133           12 : indiDriver<parentT>::indiDriver ( parentT * parent,
     134              :                                   const std::string &szName,
     135              :                                   const std::string &szDriverVersion,
     136              :                                   const std::string &szProtocolVersion
     137           36 :                                 ) : pcf::IndiDriver(szName, szDriverVersion, szProtocolVersion)
     138              : {
     139           12 :    m_parent = parent;
     140              : 
     141              :    int fd;
     142              : 
     143           12 :    errno = 0;
     144           12 :    fd = open( parent->driverInName().c_str(), O_RDWR);
     145           12 :    if(fd < 0)
     146              :    {
     147            9 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening input INDI FIFO."});
     148            9 :       m_good = false;
     149            9 :       return;
     150              :    }
     151            3 :    setInputFd(fd);
     152              : 
     153            3 :    errno = 0;
     154            3 :    fd = open( parent->driverOutName().c_str(), O_RDWR);
     155            3 :    if(fd < 0)
     156              :    {
     157            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening output INDI FIFO."});
     158            0 :       m_good = false;
     159            0 :       return;
     160              :    }
     161            3 :    setOutputFd(fd);
     162              : 
     163              :    // Open the ctrl fifo and write a single byte to it to trigger a restart
     164              :    // of the xindidriver process.
     165              :    // This allows indiserver to refresh everything.
     166            3 :    errno = 0;
     167            3 :    fd = open( parent->driverCtrlName().c_str(), O_RDWR);
     168            3 :    if(fd < 0)
     169              :    {
     170            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening control INDI FIFO."});
     171            0 :       m_good = false;
     172            0 :       return;
     173              :    }
     174            3 :    char c = 0;
     175            3 :    int wrno = write(fd, &c, 1);
     176            3 :    if(wrno < 0)
     177              :    {
     178            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error writing to control INDI FIFO."});
     179            0 :       m_good = false;
     180              :    }
     181              : 
     182              : 
     183            3 :    close(fd);
     184            0 : }
     185              : 
     186              : template<class parentT>
     187           24 : indiDriver<parentT>::~indiDriver()
     188              : {
     189           12 :    std::lock_guard<std::mutex> lock(m_outGoingMutex);
     190           12 :    if(m_outGoing) delete m_outGoing;
     191              : 
     192           36 : }
     193              : template<class parentT>
     194            0 : void indiDriver<parentT>::handleDefProperty( const pcf::IndiProperty &ipRecv )
     195              : {
     196            0 :    if(m_parent) m_parent->handleDefProperty(ipRecv);
     197            0 : }
     198              : 
     199              : template<class parentT>
     200            0 : void indiDriver<parentT>::handleGetProperties( const pcf::IndiProperty &ipRecv )
     201              : {
     202            0 :    if(m_parent) m_parent->handleGetProperties(ipRecv);
     203            0 : }
     204              : 
     205              : template<class parentT>
     206            0 : void indiDriver<parentT>::handleNewProperty( const pcf::IndiProperty &ipRecv )
     207              : {
     208            0 :    if(m_parent) m_parent->handleNewProperty(ipRecv);
     209            0 : }
     210              : 
     211              : template<class parentT>
     212            0 : void indiDriver<parentT>::handleSetProperty( const pcf::IndiProperty &ipRecv )
     213              : {
     214            0 :    if(m_parent) m_parent->handleSetProperty(ipRecv);
     215            0 : }
     216              : 
     217              : template<class parentT>
     218            3 : void indiDriver<parentT>::execute()
     219              : {
     220            3 :    processIndiRequests(false);
     221            3 : }
     222              : 
     223              : template<class parentT>
     224            3 : void  indiDriver<parentT>::update()
     225              : {
     226            3 :    return;
     227              : }
     228              : 
     229              : template<class parentT>
     230            0 : int  indiDriver<parentT>::sendNewProperty( const pcf::IndiProperty &ipRecv )
     231              : {
     232            0 :    std::lock_guard<std::mutex> lock(m_outGoingMutex);
     233              : 
     234              :    //If there is an existing client, check if it has exited.
     235            0 :    if( m_outGoing != nullptr)
     236              :    {
     237            0 :       if(m_outGoing->getQuitProcess())
     238              :       {
     239            0 :          parentT::template log<logger::text_log>("INDI client disconnected.");
     240            0 :          m_outGoing->quitProcess();
     241            0 :          m_outGoing->deactivate();
     242            0 :          delete m_outGoing;
     243            0 :          m_outGoing = nullptr;
     244              :       }
     245              :    }
     246              : 
     247              :    //Connect if needed
     248            0 :    if( m_outGoing == nullptr)
     249              :    {
     250              :       try
     251              :       {
     252            0 :          m_outGoing = new indiClient(m_parent->configName()+"-client", m_serverIPAddress, m_serverPort);
     253            0 :          m_outGoing->activate();
     254              :       }
     255            0 :       catch(...)
     256              :       {
     257            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception thrown while creating IndiClient connection"});
     258            0 :          return -1;
     259              :       }
     260              : 
     261            0 :       if(m_outGoing == nullptr)
     262              :       {
     263            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "Failed to allocate IndiClient connection"});
     264            0 :          return -1;
     265              :       }
     266              : 
     267            0 :       parentT::template log<logger::text_log>("INDI client connected and activated");
     268              :    }
     269              : 
     270              :    try
     271              :    {
     272            0 :       m_outGoing->sendNewProperty(ipRecv);
     273            0 :       if(m_outGoing->getQuitProcess())
     274              :       {
     275            0 :          parentT::template log<logger::software_error>({__FILE__, __LINE__, "INDI client appears to be disconnected -- NEW not sent."});
     276            0 :          return -1;
     277              :       }
     278              : 
     279              :       //m_outGoing->quitProcess();
     280              :       //delete m_outGoing;
     281              :       //m_outGoing = nullptr;
     282            0 :       return 0;
     283              :    }
     284            0 :    catch(std::exception & e)
     285              :    {
     286            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, std::string("Exception from IndiClient: ") + e.what()});
     287            0 :       return -1;
     288              :    }
     289            0 :    catch(...)
     290              :    {
     291            0 :       parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception from IndiClient"});
     292            0 :       return -1;
     293              :    }
     294              : 
     295              :    //Should never get here, but we are exiting for some reason sometimes.
     296              :    parentT::template log<logger::software_error>({__FILE__, __LINE__, "fall through in sendNewProperty"});
     297              :    return -1;
     298            0 : }
     299              : 
     300              : } //namespace app
     301              : } //namespace MagAOX
     302              : 
     303              : #endif //app_magAOXIndiDriver_hpp
        

Generated by: LCOV version 2.0-1