Line data Source code
1 : /** \file kTracker.hpp
2 : * \brief The MagAO-X K-mirror rotation tracker header file
3 : *
4 : * \ingroup kTracker_files
5 : */
6 :
7 : #ifndef kTracker_hpp
8 : #define kTracker_hpp
9 :
10 :
11 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12 : #include "../../magaox_git_version.h"
13 :
14 : #include <mx/math/gslInterpolation.hpp>
15 : #include <mx/ioutils/readColumns.hpp>
16 :
17 : /** \defgroup kTracker
18 : * \brief The MagAO-X application to track pupil rotation with the k-mirror.
19 : *
20 : * <a href="../handbook/operating/software/apps/kTracker.html">Application Documentation</a>
21 : *
22 : * \ingroup apps
23 : *
24 : */
25 :
26 : /** \defgroup kTracker_files
27 : * \ingroup kTracker
28 : */
29 :
30 : namespace MagAOX
31 : {
32 : namespace app
33 : {
34 :
35 : /// The MagAO-X ADC Tracker
36 : /**
37 : * \ingroup kTracker
38 : */
39 : class kTracker : public MagAOXApp<true>
40 : {
41 :
42 : //Give the test harness access.
43 : friend class kTracker_test;
44 :
45 : protected:
46 :
47 : /** \name Configurable Parameters
48 : *@{
49 : */
50 :
51 :
52 : float m_zero {0}; ///< The starting point for the K-mirorr at zd=0.
53 :
54 : int m_sign {1}; ///< The sign to apply to the zd to rotate the k-mirror
55 :
56 : std::string m_devName {"stagek"}; ///< The device name of the K-mirror stage. Default is 'stagek'
57 : std::string m_tcsDevName {"tcsi"}; ///< The device name of the TCS Interface providing 'teldata.zd'. Default is 'tcsi'
58 :
59 : float m_updateInterval {10};
60 :
61 : ///@}
62 :
63 : bool m_tracking {false}; ///< The interval at which to update positions, in seconds. Default is 10 secs.
64 :
65 : float m_zd {0};
66 :
67 : public:
68 : /// Default c'tor.
69 : kTracker();
70 :
71 : /// D'tor, declared and defined for noexcept.
72 0 : ~kTracker() noexcept
73 0 : {}
74 :
75 : virtual void setupConfig();
76 :
77 : /// Implementation of loadConfig logic, separated for testing.
78 : /** This is called by loadConfig().
79 : */
80 : int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
81 :
82 : virtual void loadConfig();
83 :
84 : /// Startup function
85 : /**
86 : *
87 : */
88 : virtual int appStartup();
89 :
90 : /// Implementation of the FSM for kTracker.
91 : /**
92 : * \returns 0 on no critical error
93 : * \returns -1 on an error requiring shutdown
94 : */
95 : virtual int appLogic();
96 :
97 : /// Shutdown the app.
98 : /**
99 : *
100 : */
101 : virtual int appShutdown();
102 :
103 :
104 : /** @name INDI
105 : *
106 : * @{
107 : */
108 : protected:
109 :
110 : pcf::IndiProperty m_indiP_tracking;
111 :
112 : pcf::IndiProperty m_indiP_teldata;
113 :
114 :
115 : pcf::IndiProperty m_indiP_kpos;
116 :
117 : public:
118 0 : INDI_NEWCALLBACK_DECL(kTracker, m_indiP_tracking);
119 :
120 :
121 0 : INDI_SETCALLBACK_DECL(kTracker, m_indiP_teldata);
122 :
123 :
124 :
125 : ///@}
126 : };
127 :
128 0 : kTracker::kTracker() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
129 : {
130 :
131 0 : return;
132 0 : }
133 :
134 0 : void kTracker::setupConfig()
135 : {
136 0 : config.add("k.zero", "", "k.zero", argType::Required, "k", "zero", false, "float", "The k-mirror zero position. Default is -40.0.");
137 :
138 0 : config.add("k.sign", "", "k.sign", argType::Required, "k", "sign", false, "int", "The k-mirror rotation sign. Default is +1.");
139 :
140 :
141 :
142 0 : config.add("k.devName", "", "k.devName", argType::Required, "k", "devName", false, "string", "The device name of the k-mirrorstage. Default is 'stagek'");
143 :
144 0 : config.add("tcs.devName", "", "tcs.devName", argType::Required, "tcs", "devName", false, "string", "The device name of the TCS Interface providing 'teldata.zd'. Default is 'tcsi'");
145 :
146 0 : config.add("tracking.updateInterval", "", "tracking.updateInterval", argType::Required, "tracking", "updateInterval", false, "float", "The interval at which to update positions, in seconds. Default is 10 secs.");
147 0 : }
148 :
149 0 : int kTracker::loadConfigImpl( mx::app::appConfigurator & _config )
150 : {
151 0 : _config(m_zero, "k.zero");
152 0 : _config(m_sign, "k.sign");
153 0 : _config(m_devName, "k.devName");
154 :
155 0 : _config(m_tcsDevName, "tcs.devName");
156 :
157 0 : _config(m_updateInterval, "tracking.updateInterval");
158 :
159 0 : return 0;
160 : }
161 :
162 0 : void kTracker::loadConfig()
163 : {
164 0 : loadConfigImpl(config);
165 0 : }
166 :
167 0 : int kTracker::appStartup()
168 : {
169 :
170 :
171 0 : createStandardIndiToggleSw( m_indiP_tracking, "tracking");
172 0 : registerIndiPropertyNew( m_indiP_tracking, INDI_NEWCALLBACK(m_indiP_tracking));
173 :
174 :
175 0 : REG_INDI_SETPROP(m_indiP_teldata, m_tcsDevName, "teldata");
176 :
177 0 : m_indiP_kpos = pcf::IndiProperty(pcf::IndiProperty::Number);
178 0 : m_indiP_kpos.setDevice(m_devName);
179 0 : m_indiP_kpos.setName("position");
180 0 : m_indiP_kpos.add(pcf::IndiElement("target"));
181 :
182 0 : state(stateCodes::READY);
183 :
184 0 : return 0;
185 : }
186 :
187 0 : int kTracker::appLogic()
188 : {
189 :
190 : static double lastupdate = 0;
191 :
192 0 : if(m_tracking && mx::sys::get_curr_time() - lastupdate > m_updateInterval)
193 : {
194 0 : float k = m_zero + m_sign*0.5*m_zd;
195 :
196 0 : std::cerr << "Sending k-mirror to: " << k << "\n";
197 :
198 0 : m_indiP_kpos["target"] = k;
199 0 : sendNewProperty (m_indiP_kpos);
200 :
201 0 : lastupdate = mx::sys::get_curr_time();
202 :
203 :
204 : }
205 0 : else if(!m_tracking) lastupdate = 0;
206 :
207 0 : return 0;
208 : }
209 :
210 0 : int kTracker::appShutdown()
211 : {
212 0 : return 0;
213 : }
214 :
215 0 : INDI_NEWCALLBACK_DEFN(kTracker, m_indiP_tracking)(const pcf::IndiProperty &ipRecv)
216 : {
217 0 : if(ipRecv.getName() != m_indiP_tracking.getName())
218 : {
219 0 : log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
220 0 : return -1;
221 : }
222 :
223 0 : if(!ipRecv.find("toggle")) return 0;
224 :
225 0 : if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
226 : {
227 0 : updateSwitchIfChanged(m_indiP_tracking, "toggle", pcf::IndiElement::On, INDI_IDLE);
228 :
229 0 : m_tracking = true;
230 :
231 0 : log<text_log>("started ADC rotation tracking");
232 : }
233 : else
234 : {
235 0 : updateSwitchIfChanged(m_indiP_tracking, "toggle", pcf::IndiElement::Off, INDI_IDLE);
236 :
237 0 : m_tracking = false;
238 :
239 0 : log<text_log>("stopped ADC rotation tracking");
240 : }
241 :
242 0 : return 0;
243 : }
244 :
245 :
246 0 : INDI_SETCALLBACK_DEFN(kTracker, m_indiP_teldata)(const pcf::IndiProperty &ipRecv)
247 : {
248 0 : if(ipRecv.getName() != m_indiP_teldata.getName())
249 : {
250 0 : log<software_error>({__FILE__,__LINE__,"wrong INDI property received"});
251 :
252 0 : return -1;
253 : }
254 :
255 0 : if(!ipRecv.find("zd")) return 0;
256 :
257 0 : m_zd = ipRecv["zd"].get<float>();
258 :
259 0 : return 0;
260 : }
261 :
262 : } //namespace app
263 : } //namespace MagAOX
264 :
265 : #endif //kTracker_hpp
266 :
|