API
 
Loading...
Searching...
No Matches
indiUtils.hpp
Go to the documentation of this file.
1/** \file indiUtils.hpp
2 * \brief MagAO-X INDI Utilities
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * History:
6 * - 2019-01-03 created by JRM
7 *
8 * \ingroup app_files
9 */
10
11#ifndef app_indiUtils_hpp
12#define app_indiUtils_hpp
13
14#include <iostream>
15#include <limits>
16
17#include "../../INDI/libcommon/IndiProperty.hpp"
18#include "../../INDI/libcommon/IndiElement.hpp"
19
20
21namespace MagAOX
22{
23namespace app
24{
25namespace indi
26{
27
28#define INDI_IDLE (pcf::IndiProperty::Idle)
29#define INDI_OK (pcf::IndiProperty::Ok)
30#define INDI_BUSY (pcf::IndiProperty::Busy)
31#define INDI_ALERT (pcf::IndiProperty::Alert)
32
33
34/// Add a standard INDI Text element
35/**
36 * \returns 0 on success
37 * \returns -1 on error
38 */
39inline
40int addTextElement( pcf::IndiProperty & prop, ///< [out] the property to which to add the elemtn
41 const std::string & name, ///< [in] the name of the element
42 const std::string & label = "" ///< [in] [optional] the GUI label suggestion for this property
43 )
44{
45 prop.add(pcf::IndiElement(name, 0));
46
47 //Don't set "" just in case libcommon does something with defaults
48 if(label != "")
49 {
50 prop[name].setLabel(label);
51 }
52
53 return 0;
54}
55
56
57/// Add a standard INDI Number element
58/**
59 * \returns 0 on success
60 * \returns -1 on error
61 */
62template<typename T>
63int addNumberElement( pcf::IndiProperty & prop, ///< [out] the property to which to add the elemtn
64 const std::string & name, ///< [in] the name of the element
65 const T & min, ///< [in] the minimum value for the element
66 const T & max, ///< [in] the minimum value for the element
67 const T & step, ///< [in] the step size of the lement
68 const std::string & format, ///< [in] the _ value for the elements, applied to both target and current. Set to "" to use the MagAO-X standard for type.
69 const std::string & label = "" ///< [in] [optional] the GUI label suggestion for this property
70 )
71{
72 prop.add(pcf::IndiElement(name, 0));
73 prop[name].setMin(min);
74 prop[name].setMax(max);
75 prop[name].setStep(step);
76 prop[name].setFormat(format);
77
78 //Don't set "" just in case libcommon does something with defaults
79 if(label != "")
80 {
81 prop[name].setLabel(label);
82 }
83
84 return 0;
85}
86
87/// Update the value of the INDI element, but only if it has changed.
88/** Only sends the set property message if the new value is different.
89 * For properties with more than one element that may have changed, you should use the vector version below.
90 *
91 * \todo this needs a const char specialization to std::string
92 *
93 */
94template<typename T, class indiDriverT>
95void updateIfChanged( pcf::IndiProperty & p, ///< [in/out] The property containing the element to possibly update
96 const std::string & el, ///< [in] The element name
97 const T & newVal, ///< [in] the new value
98 indiDriverT * indiDriver, ///< [in] the MagAOX INDI driver to use
99 pcf::IndiProperty::PropertyStateType newState = pcf::IndiProperty::Ok
100 )
101{
102 if( !indiDriver ) return;
103
104 try
105 {
106 //This is same code in IndiElement
107 std::stringstream ssValue;
108 ssValue.precision( 15 );
109 ssValue << std::boolalpha << newVal;
110
111 pcf::IndiProperty::PropertyStateType oldState = p.getState();
112
113 //Do comparison in string space, not raw value
114 if(p[el].getValue() != ssValue.str()|| oldState != newState)
115 {
116 p[el].set(newVal);
117 p.setTimeStamp(pcf::TimeStamp());
118 p.setState (newState);
119 indiDriver->sendSetProperty (p);
120 }
121 }
122 catch(std::exception & e)
123 {
124 std::cerr << "Exception caught at " << __FILE__ << " " << __LINE__ << " ";
125 std::cerr << "from " << p.getName() << "." << el << ": ";
126 std::cerr << e.what() << "\n";
127 }
128 catch(...)
129 {
130 std::cerr << "Exception caught at " << __FILE__ << " " << __LINE__ << " ";
131 std::cerr << "from " << p.getName() << "." << el << "\n";
132 }
133
134}
135
136/// Update the elements of an INDI propery, but only if there has been a change in at least one.
137/** Only sends the set property message if at least one of the new values is different, or if the state has changed.
138 *
139 * \todo this needs a const char specialization to std::string
140 *
141 */
142template<typename T, class indiDriverT>
143void updateIfChanged( pcf::IndiProperty & p, ///< [in/out] The property containing the element to possibly update
144 const std::vector<std::string> & els, ///< [in] The element names
145 const std::vector<T> & newVals, ///< [in] the new values
146 indiDriverT * indiDriver, ///< [in] the MagAOX INDI driver to use
147 pcf::IndiProperty::PropertyStateType newState = pcf::IndiProperty::Ok
148 )
149{
150 if( !indiDriver ) return;
151
152 size_t n = 0; //loop index outside so we can use it for error reporting.
153
154 try
155 {
156 //First we look for any changes
157 bool changed = false;
158 pcf::IndiProperty::PropertyStateType oldState = p.getState();
159
160 if(oldState != newState) changed = true;
161
162 for(n=0; n< els.size() && changed != true; ++n)
163 {
164 //This is same code in IndiElement
165 std::stringstream ssValue;
166 ssValue.precision( 15 );
167 ssValue << std::boolalpha << newVals[n];
168
169 //compare in string space
170 if(p[els[n]].getValue() != ssValue.str()) changed = true;
171 }
172
173 //and if there are changes, we send an update
174 if(changed)
175 {
176 for(n=0; n< els.size(); ++n)
177 {
178 p[els[n]].set(newVals[n]);
179 }
180 p.setTimeStamp(pcf::TimeStamp());
181 p.setState (newState);
182 indiDriver->sendSetProperty (p);
183 }
184 }
185 catch(std::exception & e)
186 {
187 std::cerr << "Exception caught at " << __FILE__ << " " << __LINE__ << " ";
188 if(n < els.size())
189 {
190 std::cerr << "from " << p.getName() << "." << els[n] << ": ";
191 }
192 std::cerr << e.what() << "\n";
193 }
194 catch(...)
195 {
196 std::cerr << "Exception caught at " << __FILE__ << " " << __LINE__ << " ";
197 if(n < els.size())
198 {
199 std::cerr << "from " << p.getName() << "." << els[n] << "\n";
200 }
201 }
202}
203
204/// Update the value of the INDI element, but only if it has changed.
205/** Only sends the set property message if the new value is different.
206 *
207 * \todo investigate how this handles floating point values and string conversions.
208 * \todo this needs a const char specialization to std::string
209 *
210 */
211template<class indiDriverT>
212void updateSwitchIfChanged( pcf::IndiProperty & p, ///< [in/out] The property containing the element to possibly update
213 const std::string & el, ///< [in] The element name
214 const pcf::IndiElement::SwitchStateType & newVal, ///< [in] the new value
215 indiDriverT * indiDriver, ///< [in] the MagAOX INDI driver to use
216 pcf::IndiProperty::PropertyStateType newState = pcf::IndiProperty::Ok
217 )
218{
219 if( !indiDriver ) return;
220
221 try
222 {
223 pcf::IndiElement::SwitchStateType oldVal = p[el].getSwitchState();
224
225 pcf::IndiProperty::PropertyStateType oldState = p.getState();
226
227 if(oldVal != newVal || oldState != newState)
228 {
229 p[el].setSwitchState(newVal);
230 p.setTimeStamp(pcf::TimeStamp());
231 p.setState (newState);
232 indiDriver->sendSetProperty (p);
233 }
234 }
235 catch(...)
236 {
237 std::cerr << "INDI Exception at " << __FILE__ << " " << __LINE__ << "\n";
238 std::cerr << "from " << p.getName() << "." << el << "\n";
239 }
240}
241
242
243/// Update the values of a one-of-many INDI switch vector, but only if it has changed.
244/** Only sends the set property message if the new settings are different.
245 *
246 *
247 */
248template<class indiDriverT>
249void updateSelectionSwitchIfChanged( pcf::IndiProperty & p, ///< [in/out] The property containing the element to possibly update
250 const std::string & el, ///< [in] The element name which is now on
251 indiDriverT * indiDriver, ///< [in] the MagAOX INDI driver to use
252 pcf::IndiProperty::PropertyStateType newState = pcf::IndiProperty::Ok
253 )
254{
255 if( !indiDriver ) return;
256
257 if(!p.find(el))
258 {
259 std::cerr << "INDI error at " << __FILE__ << " " << __LINE__ << "\n";
260 std::cerr << p.getName() << " does not have " << el << "\n";
261 return;
262 }
263
264 try
265 {
266
267 bool changed = false;
268 for(auto elit = p.getElements().begin(); elit != p.getElements().end(); ++elit)
269 {
270 if( elit->first == el )
271 {
272 if(elit->second.getSwitchState() != pcf::IndiElement::On)
273 {
274 p[elit->first].setSwitchState(pcf::IndiElement::On);
275 changed = true;
276 }
277 }
278 else
279 {
280 if(elit->second.getSwitchState() != pcf::IndiElement::Off)
281 {
282 p[elit->first].setSwitchState(pcf::IndiElement::Off);
283 changed = true;
284 }
285 }
286 }
287
288 pcf::IndiProperty::PropertyStateType oldState = p.getState();
289
290 if(changed || oldState != newState)
291 {
292 p.setState (newState);
293 p.setTimeStamp(pcf::TimeStamp());
294 indiDriver->sendSetProperty (p);
295 }
296
297 }
298 catch(...)
299 {
300 std::cerr << "INDI Exception at " << __FILE__ << " " << __LINE__ << "\n";
301 std::cerr << "from " << p.getName() << "." << el << "\n";
302 }
303}
304
305/// Parse an INDI key into the device and property names
306/** We often represent an INDI property as a unique key in the form
307 * `deviceName.propName`. This function parses such a key into its
308 * parts.
309 *
310 * \returns 0 on success
311 * \returns -1 if the provided key is not at least 3 characters long
312 * \returns -2 if no '.' is found
313 * \returns -3 if '.' is the first character
314 * \returns -4 if '.' is the last character
315 */
316inline
317int parseIndiKey( std::string & devName, ///< [out] the device name
318 std::string & propName, ///< [out] the property name
319 const std::string & key ///< [in] the key to parse
320 )
321{
322 if(key.size() < 3)
323 {
324 return -1;
325 }
326
327 size_t p = key.find('.');
328
329 if(p == std::string::npos)
330 {
331 devName = "";
332 propName = "";
333 return -2;
334 }
335
336 if(p == 0)
337 {
338 devName = "";
339 propName = "";
340 return -3;
341 }
342
343 if(p == key.size()-1)
344 {
345 devName = "";
346 propName = "";
347 return -4;
348 }
349
350 devName = key.substr(0, p);
351 propName = key.substr(p+1);
352
353 return 0;
354}
355
356} //namespace indi
357} //namespace app
358} //namespace MagAOX
359
360#endif //app_magAOXIndiDriver_hpp
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
Definition indiUtils.hpp:95
void updateSelectionSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the values of a one-of-many INDI switch vector, but only if it has changed.
int parseIndiKey(std::string &devName, std::string &propName, const std::string &key)
Parse an INDI key into the device and property names.
int addTextElement(pcf::IndiProperty &prop, const std::string &name, const std::string &label="")
Add a standard INDI Text element.
Definition indiUtils.hpp:40
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
int addNumberElement(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="")
Add a standard INDI Number element.
Definition indiUtils.hpp:63
Definition dm.hpp:24