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
|