API
indiDriver.hpp
Go to the documentation of this file.
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  indiClient( const std::string & clientName,
34  const std::string & hostAddress,
35  const int hostPort
36  ) : pcf::IndiClient( clientName, "none", "1.7", hostAddress, hostPort)
37  {
38  }
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  void execute()
45  {
46  processIndiRequests(false);
47  }
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.
93 
94  /// Get the value of the good flag.
95  /**
96  * \returns the value of m_good, true or false.
97  */
98  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>
127  const std::string &szName,
128  const std::string &szDriverVersion,
129  const std::string &szProtocolVersion
130  ) : pcf::IndiDriver(szName, szDriverVersion, szProtocolVersion)
131 {
132  m_parent = parent;
133 
134  int fd;
135 
136  errno = 0;
137  fd = open( parent->driverInName().c_str(), O_RDWR);
138  if(fd < 0)
139  {
140  parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening input INDI FIFO."});
141  m_good = false;
142  return;
143  }
144  setInputFd(fd);
145 
146  errno = 0;
147  fd = open( parent->driverOutName().c_str(), O_RDWR);
148  if(fd < 0)
149  {
150  parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening output INDI FIFO."});
151  m_good = false;
152  return;
153  }
154  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  errno = 0;
160  fd = open( parent->driverCtrlName().c_str(), O_RDWR);
161  if(fd < 0)
162  {
163  parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening control INDI FIFO."});
164  m_good = false;
165  return;
166  }
167  char c = 0;
168  int wrno = write(fd, &c, 1);
169  if(wrno < 0)
170  {
171  parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error writing to control INDI FIFO."});
172  m_good = false;
173  }
174 
175 
176  close(fd);
177 }
178 
179 template<class parentT>
181 {
182  if(m_outGoing) delete m_outGoing;
183 
184 }
185 template<class parentT>
186 void indiDriver<parentT>::handleDefProperty( const pcf::IndiProperty &ipRecv )
187 {
188  if(m_parent) m_parent->handleDefProperty(ipRecv);
189 }
190 
191 template<class parentT>
192 void indiDriver<parentT>::handleGetProperties( const pcf::IndiProperty &ipRecv )
193 {
194  if(m_parent) m_parent->handleGetProperties(ipRecv);
195 }
196 
197 template<class parentT>
198 void indiDriver<parentT>::handleNewProperty( const pcf::IndiProperty &ipRecv )
199 {
200  if(m_parent) m_parent->handleNewProperty(ipRecv);
201 }
202 
203 template<class parentT>
204 void indiDriver<parentT>::handleSetProperty( const pcf::IndiProperty &ipRecv )
205 {
206  if(m_parent) m_parent->handleSetProperty(ipRecv);
207 }
208 
209 template<class parentT>
211 {
212  processIndiRequests(false);
213 }
214 
215 template<class parentT>
217 {
218  return;
219 }
220 
221 template<class parentT>
222 int indiDriver<parentT>::sendNewProperty( const pcf::IndiProperty &ipRecv )
223 {
224  //If there is an existing client, check if it has exited.
225  if( m_outGoing != nullptr)
226  {
227  if(m_outGoing->getQuitProcess())
228  {
229  parentT::template log<logger::text_log>("INDI client disconnected.");
230  m_outGoing->quitProcess();
231  m_outGoing->deactivate();
232  delete m_outGoing;
233  m_outGoing = nullptr;
234  }
235  }
236 
237  //Connect if needed
238  if( m_outGoing == nullptr)
239  {
240  try
241  {
242  m_outGoing = new indiClient(m_parent->configName()+"-client", m_serverIPAddress, m_serverPort);
243  m_outGoing->activate();
244  }
245  catch(...)
246  {
247  parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception thrown while creating IndiClient connection"});
248  return -1;
249  }
250 
251  if(m_outGoing == nullptr)
252  {
253  parentT::template log<logger::software_error>({__FILE__, __LINE__, "Failed to allocate IndiClient connection"});
254  return -1;
255  }
256 
257  parentT::template log<logger::text_log>("INDI client connected and activated");
258  }
259 
260  try
261  {
262  m_outGoing->sendNewProperty(ipRecv);
263  if(m_outGoing->getQuitProcess())
264  {
265  parentT::template log<logger::software_error>({__FILE__, __LINE__, "INDI client appears to be disconnected -- NEW not sent."});
266  return -1;
267  }
268 
269  //m_outGoing->quitProcess();
270  //delete m_outGoing;
271  //m_outGoing = nullptr;
272  return 0;
273  }
274  catch(std::exception & e)
275  {
276  parentT::template log<logger::software_error>({__FILE__, __LINE__, std::string("Exception from IndiClient: ") + e.what()});
277  return -1;
278  }
279  catch(...)
280  {
281  parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception from IndiClient"});
282  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
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
Simple INDI Client class.
Definition: indiDriver.hpp:28
void execute()
Implementation of the pcf::IndiClient interface, called by activate to actually begins the INDI event...
Definition: indiDriver.hpp:44
indiClient(const std::string &clientName, const std::string &hostAddress, const int hostPort)
Constructor, which establishes the INDI client connection.
Definition: indiDriver.hpp:33
~indiDriver()
D'tor, deletes the IndiClient pointer.
Definition: indiDriver.hpp:180
virtual void handleSetProperty(const pcf::IndiProperty &ipRecv)
Definition: indiDriver.hpp:204
virtual void handleDefProperty(const pcf::IndiProperty &ipRecv)
Definition: indiDriver.hpp:186
bool m_good
Flag to hold the status of this connection.
Definition: indiDriver.hpp:76
int m_serverPort
The port of the server for the INDI Client connection.
Definition: indiDriver.hpp:71
virtual void execute(void)
Define the execute virtual function. This runs the processIndiRequests function in this thread,...
Definition: indiDriver.hpp:210
indiDriver(parentT *parent, const std::string &szName, const std::string &szDriverVersion, const std::string &szProtocolVersion)
Public c'tor.
Definition: indiDriver.hpp:126
virtual void handleNewProperty(const pcf::IndiProperty &ipRecv)
Definition: indiDriver.hpp:198
virtual int sendNewProperty(const pcf::IndiProperty &ipRecv)
Send a newProperty command to another INDI driver.
Definition: indiDriver.hpp:222
indiClient * m_outGoing
An INDI Client is used to send commands to other drivers.
Definition: indiDriver.hpp:65
virtual void handleGetProperties(const pcf::IndiProperty &ipRecv)
Definition: indiDriver.hpp:192
std::string m_serverIPAddress
The IP address of the server for the INDI Client connection.
Definition: indiDriver.hpp:68
_parentT parentT
The parent MagAOX app.
Definition: indiDriver.hpp:57
parentT * m_parent
This objects parent class.
Definition: indiDriver.hpp:62
bool good()
Get the value of the good flag.
Definition: indiDriver.hpp:98
virtual void update()
Define the update virt. func. here so the uptime message isn't sent.
Definition: indiDriver.hpp:216
const pcf::IndiProperty & ipRecv
Definition: dm.hpp:24