Line data Source code
1 : /** \file xt1121DCDU.hpp
2 : * \brief The MagAO-X xt1121-based D.C. Distribution Unit controller.
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup xt1121DCDU_files
7 : */
8 :
9 : #ifndef xt1121DCDU_hpp
10 : #define xt1121DCDU_hpp
11 :
12 :
13 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14 : #include "../../magaox_git_version.h"
15 :
16 : /** \defgroup xt1121DCDU xt1121-based DC distribution unit
17 : * \brief Control of MagAO-X D.C. power distrubition via the xt1121 DIO module.
18 : *
19 : * <a href="../handbook/operating/software/apps/xt1121DCDU.html">Application Documentation</a>
20 : *
21 : * \ingroup apps
22 : *
23 : */
24 :
25 : /** \defgroup xt1121DCDU_files xt1121 DCDU Files
26 : * \ingroup xt1121DCDU
27 : */
28 :
29 : namespace MagAOX
30 : {
31 : namespace app
32 : {
33 :
34 : /// MagAO-X application to control D.C. distribution via an xt1121 DIO unit.
35 : /** The device outlets are organized into channels. See \ref dev::outletController for details of configuring the channels.
36 : *
37 : *
38 : * \ingroup xt1121DCDU
39 : */
40 : class xt1121DCDU : public MagAOXApp<>, public dev::outletController<xt1121DCDU>
41 : {
42 :
43 : protected:
44 :
45 : std::string m_deviceName; ///< The device address
46 :
47 : std::vector<int> m_channelNumbers; ///< Vector of outlet numbers, used to construct the channel names to monitor as outlets 0-7.
48 :
49 : int m_outletStateDelay {5000}; ///< The maximum time to wait for an outlet to change state [msec].
50 :
51 :
52 : pcf::IndiProperty ip_ch0;
53 : pcf::IndiProperty ip_ch1;
54 : pcf::IndiProperty ip_ch2;
55 : pcf::IndiProperty ip_ch3;
56 : pcf::IndiProperty ip_ch4;
57 : pcf::IndiProperty ip_ch5;
58 : pcf::IndiProperty ip_ch6;
59 : pcf::IndiProperty ip_ch7;
60 :
61 :
62 :
63 : public:
64 :
65 : /// Default c'tor.
66 : xt1121DCDU();
67 :
68 : /// D'tor, declared and defined for noexcept.
69 0 : ~xt1121DCDU() noexcept
70 0 : {}
71 :
72 : /// Setup the configuration system (called by MagAOXApp::setup())
73 : virtual void setupConfig();
74 :
75 : /// load the configuration system results (called by MagAOXApp::setup())
76 : virtual void loadConfig();
77 :
78 : /// Startup functions
79 : /** Setsup the INDI vars.
80 : * Checks if the device was found during loadConfig.
81 : */
82 : virtual int appStartup();
83 :
84 : /// Implementation of the FSM for the xt1121 DCDU.
85 : virtual int appLogic();
86 :
87 : /// Do any needed shutdown tasks. Currently nothing in this app.
88 : virtual int appShutdown();
89 :
90 : /// Update a single outlet state
91 : /**
92 : *
93 : * \returns 0 on success
94 : * \returns -1 on error
95 : */
96 : virtual int updateOutletState( int outletNum /**< [in] the outlet number to update */);
97 :
98 : /// Turn on an outlet.
99 : /**
100 : * \returns 0 on success
101 : * \returns -1 on error
102 : */
103 : virtual int turnOutletOn( int outletNum /**< [in] the outlet number to turn on */);
104 :
105 : /// Turn off an outlet.
106 : /**
107 : * \returns 0 on success
108 : * \returns -1 on error
109 : */
110 : virtual int turnOutletOff( int outletNum /**< [in] the outlet number to turn off */);
111 :
112 : protected:
113 :
114 : ///Helper function to get the xt1121Ctrl channel name for the given channel number.
115 : /**
116 : * \returns chXX where XX is 00 to 15, set by chno.
117 : * \returns empty string if chno is not valid.
118 : */
119 : std::string xtChannelName( int chno);
120 :
121 : ///Helper function to get a pointer to the right INDI property for an outlet number.
122 : /**
123 : * \returns a pointer to one of the INDI properties if outletNum is valid
124 : * \returns nullptr if outletNum is not valid.
125 : */
126 : pcf::IndiProperty * xtChannelProperty( int outletNum /**< [in] the outlet number */);
127 :
128 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch0);
129 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch1);
130 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch2);
131 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch3);
132 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch4);
133 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch5);
134 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch6);
135 0 : INDI_SETCALLBACK_DECL(xt1121DCDU, ip_ch7);
136 : };
137 :
138 0 : xt1121DCDU::xt1121DCDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
139 : {
140 0 : m_firstOne = true;
141 0 : m_powerMgtEnabled = true;
142 :
143 0 : setNumberOfOutlets(8);
144 :
145 0 : return;
146 0 : }
147 :
148 0 : void xt1121DCDU::setupConfig()
149 : {
150 0 : config.add("device.name", "", "device.name", argType::Required, "device", "name", false, "string", "The device INDI name.");
151 :
152 0 : config.add("device.channelNumbers", "", "device.channelNumbers", argType::Required, "device", "channelNumbers", false, "vector<int>", "The channel numbers to use for the outlets, in order.");
153 :
154 :
155 0 : dev::outletController<xt1121DCDU>::setupConfig(config);
156 :
157 0 : }
158 :
159 :
160 0 : void xt1121DCDU::loadConfig()
161 : {
162 0 : config(m_deviceName, "device.name");
163 :
164 0 : m_channelNumbers = {0,1,2,3,4,5,6,7};
165 0 : config(m_channelNumbers, "device.channelNumbers");
166 :
167 0 : dev::outletController<xt1121DCDU>::loadConfig(config);
168 :
169 0 : }
170 :
171 :
172 :
173 0 : int xt1121DCDU::appStartup()
174 : {
175 0 : if(m_channelNumbers.size() != 8)
176 : {
177 0 : return log<text_log,-1>("Something other than 8 channel numbers specified.", logPrio::LOG_CRITICAL);
178 : }
179 :
180 0 : REG_INDI_SETPROP(ip_ch0, m_deviceName, xtChannelName(m_channelNumbers[0]));
181 0 : REG_INDI_SETPROP(ip_ch1, m_deviceName, xtChannelName(m_channelNumbers[1]));
182 0 : REG_INDI_SETPROP(ip_ch2, m_deviceName, xtChannelName(m_channelNumbers[2]));
183 0 : REG_INDI_SETPROP(ip_ch3, m_deviceName, xtChannelName(m_channelNumbers[3]));
184 0 : REG_INDI_SETPROP(ip_ch4, m_deviceName, xtChannelName(m_channelNumbers[4]));
185 0 : REG_INDI_SETPROP(ip_ch5, m_deviceName, xtChannelName(m_channelNumbers[5]));
186 0 : REG_INDI_SETPROP(ip_ch6, m_deviceName, xtChannelName(m_channelNumbers[6]));
187 0 : REG_INDI_SETPROP(ip_ch7, m_deviceName, xtChannelName(m_channelNumbers[7]));
188 :
189 0 : if(dev::outletController<xt1121DCDU>::setupINDI() < 0)
190 : {
191 0 : return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
192 : }
193 :
194 0 : state(stateCodes::NOTCONNECTED);
195 :
196 0 : return 0;
197 : }
198 :
199 0 : int xt1121DCDU::appLogic()
200 : {
201 0 : if( state() == stateCodes::POWERON )
202 : {
203 0 : state(stateCodes::READY);
204 : }
205 :
206 :
207 0 : if(state() == stateCodes::READY)
208 : {
209 0 : std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
210 :
211 0 : int rv = updateOutletStates();
212 :
213 0 : if(rv < 0) return log<software_error,-1>({__FILE__, __LINE__});
214 :
215 0 : dev::outletController<xt1121DCDU>::updateINDI();
216 :
217 0 : return 0;
218 0 : }
219 :
220 0 : state(stateCodes::FAILURE);
221 0 : log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
222 0 : return -1;
223 :
224 : }
225 :
226 0 : int xt1121DCDU::appShutdown()
227 : {
228 : //don't bother
229 0 : return 0;
230 : }
231 :
232 0 : int xt1121DCDU::updateOutletState( int outletNum )
233 : {
234 0 : pcf::IndiProperty * ip = xtChannelProperty(outletNum);
235 :
236 0 : if(ip == nullptr)
237 : {
238 0 : return log<software_error, -1>({__FILE__, __LINE__, "bad outlet number"});
239 : }
240 :
241 0 : int os = OUTLET_STATE_UNKNOWN;
242 0 : if(ip->find("current"))
243 : {
244 0 : if((*ip)["current"].get<int>() == 0) os = OUTLET_STATE_OFF;
245 0 : else if((*ip)["current"].get<int>() == 1) os = OUTLET_STATE_ON;
246 : }
247 :
248 0 : m_outletStates[outletNum] = os;
249 :
250 0 : return 0;
251 :
252 : }
253 :
254 0 : int xt1121DCDU::turnOutletOn( int outletNum )
255 : {
256 0 : std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
257 :
258 0 : pcf::IndiProperty * ip = xtChannelProperty(outletNum);
259 :
260 0 : if(ip == nullptr)
261 : {
262 0 : return log<software_error, -1>({__FILE__, __LINE__, "bad outlet number"});
263 : }
264 :
265 0 : return sendNewProperty(*ip, "target", 1);
266 :
267 0 : }
268 :
269 0 : int xt1121DCDU::turnOutletOff( int outletNum )
270 : {
271 0 : std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
272 :
273 0 : pcf::IndiProperty * ip = xtChannelProperty(outletNum);
274 :
275 0 : if(ip == nullptr)
276 : {
277 0 : return log<software_error, -1>({__FILE__, __LINE__, "bad outlet number"});
278 : }
279 :
280 0 : return sendNewProperty(*ip, "target", 0);
281 :
282 0 : }
283 :
284 0 : std::string xt1121DCDU::xtChannelName( int chno)
285 : {
286 0 : switch(chno)
287 : {
288 0 : case 0:
289 0 : return "ch00";
290 0 : case 1:
291 0 : return "ch01";
292 0 : case 2:
293 0 : return "ch02";
294 0 : case 3:
295 0 : return "ch03";
296 0 : case 4:
297 0 : return "ch04";
298 0 : case 5:
299 0 : return "ch05";
300 0 : case 6:
301 0 : return "ch06";
302 0 : case 7:
303 0 : return "ch07";
304 0 : case 8:
305 0 : return "ch08";
306 0 : case 9:
307 0 : return "ch09";
308 0 : case 10:
309 0 : return "ch10";
310 0 : case 11:
311 0 : return "ch11";
312 0 : case 12:
313 0 : return "ch12";
314 0 : case 13:
315 0 : return "ch13";
316 0 : case 14:
317 0 : return "ch14";
318 0 : case 15:
319 0 : return "ch15";
320 0 : case 16:
321 0 : return "ch16";
322 0 : default:
323 0 : return "";
324 : }
325 : }
326 0 : pcf::IndiProperty * xt1121DCDU::xtChannelProperty( int outletNum )
327 : {
328 0 : switch(outletNum)
329 : {
330 0 : case 0:
331 0 : return &ip_ch0;
332 0 : case 1:
333 0 : return &ip_ch1;
334 0 : case 2:
335 0 : return &ip_ch2;
336 0 : case 3:
337 0 : return &ip_ch3;
338 0 : case 4:
339 0 : return &ip_ch4;
340 0 : case 5:
341 0 : return &ip_ch5;
342 0 : case 6:
343 0 : return &ip_ch6;
344 0 : case 7:
345 0 : return &ip_ch7;
346 0 : default:
347 0 : return nullptr;
348 : }
349 : }
350 :
351 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch0)(const pcf::IndiProperty &ipRecv)
352 : {
353 0 : ip_ch0 = ipRecv;
354 :
355 0 : return updateOutletState(0);
356 : }
357 :
358 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch1)(const pcf::IndiProperty &ipRecv)
359 : {
360 0 : ip_ch1 = ipRecv;
361 :
362 0 : return updateOutletState(1);
363 : }
364 :
365 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch2)(const pcf::IndiProperty &ipRecv)
366 : {
367 0 : ip_ch2 = ipRecv;
368 :
369 0 : return updateOutletState(2);
370 : }
371 :
372 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch3)(const pcf::IndiProperty &ipRecv)
373 : {
374 0 : ip_ch3 = ipRecv;
375 :
376 0 : return updateOutletState(3);
377 : }
378 :
379 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch4)(const pcf::IndiProperty &ipRecv)
380 : {
381 0 : ip_ch4 = ipRecv;
382 :
383 0 : return updateOutletState(4);
384 : }
385 :
386 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch5)(const pcf::IndiProperty &ipRecv)
387 : {
388 0 : ip_ch5 = ipRecv;
389 :
390 0 : return updateOutletState(5);
391 : }
392 :
393 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch6)(const pcf::IndiProperty &ipRecv)
394 : {
395 0 : ip_ch6 = ipRecv;
396 :
397 0 : return updateOutletState(6);
398 : }
399 :
400 0 : INDI_SETCALLBACK_DEFN(xt1121DCDU, ip_ch7)(const pcf::IndiProperty &ipRecv)
401 : {
402 0 : ip_ch7 = ipRecv;
403 :
404 0 : return updateOutletState(7);
405 : }
406 :
407 : } //namespace app
408 : } //namespace MagAOX
409 :
410 : #endif //xt1121DCDU_hpp
|