API
 
Loading...
Searching...
No Matches
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
21namespace MagAOX
22{
23namespace app
24{
25
26///Simple INDI Client class
27class indiClient : public pcf::IndiClient
28{
29
30public:
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
51template<class _parentT>
52class indiDriver : public pcf::IndiDriver
53{
54public:
55
56 ///The parent MagAOX app.
57 typedef _parentT parentT;
58
59protected:
60
61 ///This objects parent class
62 parentT * m_parent {nullptr};
63
64 ///An INDI Client is used to send commands to other drivers.
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
73private:
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
85public:
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 */
93 const std::string &szName,
94 const std::string &szDriverVersion,
95 const std::string &szProtocolVersion
96 );
97
98 /// D'tor, deletes the IndiClient pointer.
100
101 /// Get the value of the good flag.
102 /**
103 * \returns the value of m_good, true or false.
104 */
105 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
132template<class parentT>
134 const std::string &szName,
135 const std::string &szDriverVersion,
136 const std::string &szProtocolVersion
137 ) : pcf::IndiDriver(szName, szDriverVersion, szProtocolVersion)
138{
139 m_parent = parent;
140
141 int fd;
142
143 errno = 0;
144 fd = open( parent->driverInName().c_str(), O_RDWR);
145 if(fd < 0)
146 {
147 parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening input INDI FIFO."});
148 m_good = false;
149 return;
150 }
151 setInputFd(fd);
152
153 errno = 0;
154 fd = open( parent->driverOutName().c_str(), O_RDWR);
155 if(fd < 0)
156 {
157 parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening output INDI FIFO."});
158 m_good = false;
159 return;
160 }
161 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 errno = 0;
167 fd = open( parent->driverCtrlName().c_str(), O_RDWR);
168 if(fd < 0)
169 {
170 parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error opening control INDI FIFO."});
171 m_good = false;
172 return;
173 }
174 char c = 0;
175 int wrno = write(fd, &c, 1);
176 if(wrno < 0)
177 {
178 parentT::template log<logger::software_error>({__FILE__, __LINE__, errno, "Error writing to control INDI FIFO."});
179 m_good = false;
180 }
181
182
183 close(fd);
184}
185
186template<class parentT>
188{
189 std::lock_guard<std::mutex> lock(m_outGoingMutex);
190 if(m_outGoing) delete m_outGoing;
191
192}
193template<class parentT>
194void indiDriver<parentT>::handleDefProperty( const pcf::IndiProperty &ipRecv )
195{
196 if(m_parent) m_parent->handleDefProperty(ipRecv);
197}
198
199template<class parentT>
200void indiDriver<parentT>::handleGetProperties( const pcf::IndiProperty &ipRecv )
201{
202 if(m_parent) m_parent->handleGetProperties(ipRecv);
203}
204
205template<class parentT>
206void indiDriver<parentT>::handleNewProperty( const pcf::IndiProperty &ipRecv )
207{
208 if(m_parent) m_parent->handleNewProperty(ipRecv);
209}
210
211template<class parentT>
212void indiDriver<parentT>::handleSetProperty( const pcf::IndiProperty &ipRecv )
213{
214 if(m_parent) m_parent->handleSetProperty(ipRecv);
215}
216
217template<class parentT>
219{
220 processIndiRequests(false);
221}
222
223template<class parentT>
225{
226 return;
227}
228
229template<class parentT>
230int indiDriver<parentT>::sendNewProperty( const pcf::IndiProperty &ipRecv )
231{
232 std::lock_guard<std::mutex> lock(m_outGoingMutex);
233
234 //If there is an existing client, check if it has exited.
235 if( m_outGoing != nullptr)
236 {
237 if(m_outGoing->getQuitProcess())
238 {
239 parentT::template log<logger::text_log>("INDI client disconnected.");
240 m_outGoing->quitProcess();
241 m_outGoing->deactivate();
242 delete m_outGoing;
243 m_outGoing = nullptr;
244 }
245 }
246
247 //Connect if needed
248 if( m_outGoing == nullptr)
249 {
250 try
251 {
252 m_outGoing = new indiClient(m_parent->configName()+"-client", m_serverIPAddress, m_serverPort);
253 m_outGoing->activate();
254 }
255 catch(...)
256 {
257 parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception thrown while creating IndiClient connection"});
258 return -1;
259 }
260
261 if(m_outGoing == nullptr)
262 {
263 parentT::template log<logger::software_error>({__FILE__, __LINE__, "Failed to allocate IndiClient connection"});
264 return -1;
265 }
266
267 parentT::template log<logger::text_log>("INDI client connected and activated");
268 }
269
270 try
271 {
272 m_outGoing->sendNewProperty(ipRecv);
273 if(m_outGoing->getQuitProcess())
274 {
275 parentT::template log<logger::software_error>({__FILE__, __LINE__, "INDI client appears to be disconnected -- NEW not sent."});
276 return -1;
277 }
278
279 //m_outGoing->quitProcess();
280 //delete m_outGoing;
281 //m_outGoing = nullptr;
282 return 0;
283 }
284 catch(std::exception & e)
285 {
286 parentT::template log<logger::software_error>({__FILE__, __LINE__, std::string("Exception from IndiClient: ") + e.what()});
287 return -1;
288 }
289 catch(...)
290 {
291 parentT::template log<logger::software_error>({__FILE__, __LINE__, "Exception from IndiClient"});
292 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}
299
300} //namespace app
301} //namespace MagAOX
302
303#endif //app_magAOXIndiDriver_hpp
The base-class for XWCTk applications.
Simple INDI Client class.
void execute()
Implementation of the pcf::IndiClient interface, called by activate to actually begins the INDI event...
indiClient(const std::string &clientName, const std::string &hostAddress, const int hostPort)
Constructor, which establishes the INDI client connection.
~indiDriver()
D'tor, deletes the IndiClient pointer.
virtual void handleSetProperty(const pcf::IndiProperty &ipRecv)
virtual void handleDefProperty(const pcf::IndiProperty &ipRecv)
bool m_good
Flag to hold the status of this connection.
int m_serverPort
The port of the server for the INDI Client connection.
virtual void execute(void)
Define the execute virtual function. This runs the processIndiRequests function in this thread,...
indiDriver(parentT *parent, const std::string &szName, const std::string &szDriverVersion, const std::string &szProtocolVersion)
Public c'tor.
virtual void handleNewProperty(const pcf::IndiProperty &ipRecv)
virtual int sendNewProperty(const pcf::IndiProperty &ipRecv)
Send a newProperty command to another INDI driver.
std::mutex m_outGoingMutex
Mutex protecting the lifecycle and use of m_outGoing.
indiClient * m_outGoing
An INDI Client is used to send commands to other drivers.
virtual void handleGetProperties(const pcf::IndiProperty &ipRecv)
std::string m_serverIPAddress
The IP address of the server for the INDI Client connection.
_parentT parentT
The parent MagAOX app.
parentT * m_parent
This objects parent class.
bool good()
Get the value of the good flag.
virtual void update()
Define the update virt. func. here so the uptime message isn't sent.
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:19