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
|