Line data Source code
1 : /** \file zaberCtrl.hpp
2 : * \brief The MagAO-X Zaber Stage Controller header file
3 : *
4 : * \ingroup zaberCtrl_files
5 : */
6 :
7 : #ifndef zaberCtrl_hpp
8 : #define zaberCtrl_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 : /** \defgroup zaberCtrl
15 : * \brief The MagAO-X application to control a single Zaber stage
16 : *
17 : * <a href="../handbook/operating/software/apps/zaberCtrl.html">Application Documentation</a>
18 : *
19 : * \ingroup apps
20 : *
21 : */
22 :
23 : /** \defgroup zaberCtrl_files
24 : * \ingroup zaberCtrl
25 : */
26 :
27 : namespace MagAOX
28 : {
29 : namespace app
30 : {
31 :
32 : /// The MagAO-X Zaber Stage Controller
33 : /** Interacts with the stage through a zaberLowLevel process via INDI.
34 : *
35 : * \ingroup zaberCtrl
36 : */
37 : class zaberCtrl : public MagAOXApp<>, public dev::stdMotionStage<zaberCtrl>, public dev::telemeter<zaberCtrl>
38 : {
39 :
40 : //Give the test harness access.
41 : friend class zaberCtrl_test;
42 :
43 : friend class dev::stdMotionStage<zaberCtrl>;
44 :
45 : friend class dev::telemeter<zaberCtrl>;
46 :
47 : protected:
48 :
49 : /** \name Configurable Parameters
50 : *@{
51 : */
52 :
53 : std::string m_lowLevelName {"zaberLowLevel"};
54 :
55 : std::string m_stageName; ///< The name of this stage used for accessing via zaberLowLevel
56 :
57 : double m_countsPerMillimeter {10078.740157480315}; ///< Counts per millimeter calibration of this stage.
58 :
59 : unsigned long m_maxRawPos {0}; ///< Maximum counts available on this stage.
60 :
61 : ///@}
62 :
63 : double m_rawPos {0}; ///< Current raw position in counts
64 : double m_tgtRawPos {0}; ///< Target raw position in counts
65 : double m_stageTemp{0}; ///< Temperature reported by the stage
66 :
67 : double m_maxPos {0}; ///< Maximum position in mm available on this stage
68 : double m_pos {0}; ///< Current position in mm
69 : double m_tgtPos {0}; ///< Target position in mm.
70 :
71 : int m_homingState{0}; ///< The homing state, tracks the stages of homing.
72 :
73 : public:
74 : /// Default c'tor.
75 : zaberCtrl();
76 :
77 : /// D'tor, declared and defined for noexcept.
78 33 : ~zaberCtrl() noexcept
79 33 : {}
80 :
81 : /// Setup the configuration of this stage controller.
82 : virtual void setupConfig();
83 :
84 : /// Implementation of loadConfig logic, separated for testing.
85 : /** This is called by loadConfig().
86 : */
87 : int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
88 :
89 : ///Load the stage configuration
90 : /** Calls loadConfigImpl()
91 : */
92 : virtual void loadConfig();
93 :
94 : /// Startup function
95 : /**
96 : *
97 : */
98 : virtual int appStartup();
99 :
100 : /// Implementation of the FSM for zaberCtrl.
101 : /**
102 : * \returns 0 on no critical error
103 : * \returns -1 on an error requiring shutdown
104 : */
105 : virtual int appLogic();
106 :
107 : /// Shutdown the app.
108 : /**
109 : *
110 : */
111 : virtual int appShutdown();
112 :
113 : /// Start a high-level homing sequence.
114 : /**
115 : *
116 : * \returns 0 on success.
117 : * \returns -1 on error.
118 : */
119 : int startHoming();
120 :
121 : /// Stop the stage motion immediately.
122 : /**
123 : * \returns 0 on success.
124 : * \returns -1 on error.
125 : */
126 : int stop();
127 :
128 : double presetNumber();
129 :
130 : /// Move to a new position in mm.
131 : /** \todo this actually should move to a preset position by nearest integet.. A moveToMM should be used for the mm command.
132 : *
133 : * \returns 0 on success.
134 : * \returns -1 on error.
135 : */
136 : int moveTo( const double & pos /**< [in] The new position in mm*/ );
137 :
138 : protected:
139 :
140 : //INDI properties for user interaction:
141 : pcf::IndiProperty m_indiP_pos;
142 : pcf::IndiProperty m_indiP_rawPos;
143 : pcf::IndiProperty m_indiP_maxPos;
144 : pcf::IndiProperty m_indiP_temp;
145 :
146 : public:
147 :
148 0 : INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_pos);
149 0 : INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_rawPos);
150 :
151 : //INDI properties for interacting with Low-Level
152 : pcf::IndiProperty m_indiP_stageState;
153 : pcf::IndiProperty m_indiP_stageMaxRawPos;
154 : pcf::IndiProperty m_indiP_stageRawPos;
155 : pcf::IndiProperty m_indiP_stageTgtPos;
156 : pcf::IndiProperty m_indiP_stageTemp;
157 :
158 : public:
159 0 : INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageState);
160 0 : INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageMaxRawPos);
161 0 : INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageRawPos);
162 0 : INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTgtPos);
163 0 : INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTemp);
164 :
165 : /** \name Telemeter Interface
166 : *
167 : * @{
168 : */
169 : int checkRecordTimes();
170 :
171 : int recordTelem( const telem_stage * );
172 :
173 : int recordTelem( const telem_zaber * );
174 :
175 : int recordZaber(bool force = false);
176 :
177 : ///@}
178 : };
179 :
180 165 : zaberCtrl::zaberCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
181 : {
182 33 : m_fractionalPresets = false;
183 33 : m_defaultPositions = false;
184 :
185 33 : return;
186 0 : }
187 :
188 0 : void zaberCtrl::setupConfig()
189 : {
190 0 : config.add("stage.lowLevelName", "", "stage.lowLevelName", argType::Required, "stage", "lowLevelName", false, "string", "The name of the low-level control process actually controlling this stage. Default is zaberLowLevel.");
191 :
192 0 : config.add("stage.stageName", "", "stage.stageName", argType::Required, "stage", "stageName", false, "string", "the name of this stage in the low-level process INDI properties. Default is the configuration name.");
193 :
194 0 : config.add("stage.countsPerMillimeter", "", "stage.countsPerMillimeter", argType::Required, "stage", "countsPerMillimeter", false, "float", "The counts per mm calibration of the stage. Default is 10078.74, which applies tot he X-LRQ-DE.");
195 :
196 0 : config.add("stage.maxCounts", "", "stage.maxCounts", argType::Required, "stage", "maxCounts", false, "unsigned long", "The maximum counts possible for this stage.");
197 :
198 0 : dev::stdMotionStage<zaberCtrl>::setupConfig(config);
199 :
200 0 : dev::telemeter<zaberCtrl>::setupConfig(config);
201 0 : }
202 :
203 :
204 0 : int zaberCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
205 : {
206 0 : _config(m_lowLevelName, "stage.lowLevelName");
207 :
208 0 : m_stageName = m_configName;
209 0 : _config(m_stageName, "stage.stageName");
210 :
211 0 : _config(m_countsPerMillimeter, "stage.countsPerMillimeter");
212 :
213 0 : _config(m_maxRawPos, "stage.maxCounts");
214 0 : m_maxPos = ((double) m_maxRawPos)/ m_countsPerMillimeter;
215 :
216 0 : dev::stdMotionStage<zaberCtrl>::loadConfig(_config);
217 :
218 0 : dev::telemeter<zaberCtrl>::loadConfig(_config);
219 :
220 0 : return 0;
221 : }
222 :
223 0 : void zaberCtrl::loadConfig()
224 : {
225 0 : loadConfigImpl(config);
226 0 : }
227 :
228 0 : int zaberCtrl::appStartup()
229 : {
230 :
231 0 : createStandardIndiNumber<float>( m_indiP_pos, "position", 0.0, m_maxPos, 1/m_countsPerMillimeter, "%.4f");
232 0 : m_indiP_pos["current"].set(0);
233 0 : m_indiP_pos["target"].set(0);
234 0 : if( registerIndiPropertyNew( m_indiP_pos, INDI_NEWCALLBACK(m_indiP_pos)) < 0)
235 : {
236 : #ifndef ZABERCTRL_TEST_NOLOG
237 0 : log<software_error>({__FILE__,__LINE__});
238 : #endif
239 0 : return -1;
240 : }
241 :
242 0 : createStandardIndiNumber<unsigned long>( m_indiP_rawPos, "rawpos", 0.0, m_maxRawPos, 1, "%lu");
243 0 : m_indiP_rawPos["current"].set(0);
244 0 : m_indiP_rawPos["target"].set(0);
245 0 : if( registerIndiPropertyNew( m_indiP_rawPos, INDI_NEWCALLBACK(m_indiP_rawPos)) < 0)
246 : {
247 : #ifndef ZABERCTRL_TEST_NOLOG
248 0 : log<software_error>({__FILE__,__LINE__});
249 : #endif
250 0 : return -1;
251 : }
252 :
253 0 : createROIndiNumber( m_indiP_maxPos, "maxpos", "Maximum Position");
254 0 : indi::addNumberElement( m_indiP_maxPos, "value", m_maxPos, m_maxPos, 0.0, "%0.4f");
255 0 : m_indiP_maxPos["value"].set<double>(m_maxPos);
256 0 : registerIndiPropertyReadOnly(m_indiP_maxPos);
257 :
258 0 : createROIndiNumber( m_indiP_temp, "temp", "Stage Temperature [C]");
259 0 : indi::addNumberElement( m_indiP_temp, "current", -50,100, 0, "%0.1f");
260 0 : registerIndiPropertyReadOnly(m_indiP_temp);
261 :
262 : //Register for the low level status reports
263 0 : REG_INDI_SETPROP(m_indiP_stageState, m_lowLevelName, "curr_state");
264 0 : REG_INDI_SETPROP(m_indiP_stageMaxRawPos, m_lowLevelName, std::string("max_pos"));
265 0 : REG_INDI_SETPROP(m_indiP_stageRawPos, m_lowLevelName, std::string("curr_pos"));
266 0 : REG_INDI_SETPROP(m_indiP_stageTgtPos, m_lowLevelName, std::string("tgt_pos"));
267 0 : REG_INDI_SETPROP(m_indiP_stageTemp, m_lowLevelName, std::string("temp"));
268 :
269 :
270 0 : if(m_presetNames.size() != m_presetPositions.size())
271 : {
272 0 : return log<text_log,-1>("must set a position for each preset", logPrio::LOG_CRITICAL);
273 : }
274 :
275 0 : m_presetNames.insert(m_presetNames.begin(), "none");
276 0 : m_presetPositions.insert(m_presetPositions.begin(), -1);
277 :
278 0 : dev::stdMotionStage<zaberCtrl>::appStartup();
279 :
280 0 : if(dev::telemeter<zaberCtrl>::appStartup() < 0)
281 : {
282 0 : return log<software_error,-1>({__FILE__,__LINE__});
283 : }
284 :
285 0 : return 0;
286 : }
287 :
288 0 : int zaberCtrl::appLogic()
289 : {
290 0 : if(state() == stateCodes::INITIALIZED)
291 : {
292 0 : state(stateCodes::NOTCONNECTED);
293 : }
294 :
295 0 : if(state() == stateCodes::NOTCONNECTED || state() == stateCodes::POWEROFF)
296 : {
297 : //Here do poweroff update
298 0 : if( stdMotionStage<zaberCtrl>::onPowerOff() < 0)
299 : {
300 0 : log<software_error>({__FILE__,__LINE__});
301 : }
302 :
303 0 : recordStage();
304 :
305 : //record telem if it's been longer than 10 sec:
306 0 : if(telemeter<zaberCtrl>::appLogic() < 0)
307 : {
308 0 : log<software_error>({__FILE__, __LINE__});
309 : }
310 :
311 0 : return 0;
312 : }
313 :
314 0 : if(state() == stateCodes::POWERON)
315 : {
316 0 : recordStage();
317 0 : return 0;
318 : }
319 :
320 0 : if(state() == stateCodes::NOTHOMED)
321 : {
322 0 : if(m_powerOnHome) startHoming();
323 : }
324 :
325 0 : if(state() == stateCodes::HOMING)
326 : {
327 0 : if(m_homingState == 2)
328 : {
329 0 : if(m_homePreset >= 0)
330 : {
331 0 : m_preset_target = m_presetPositions[m_homePreset];
332 0 : updateIfChanged(m_indiP_preset, "target", m_preset_target, INDI_BUSY);
333 :
334 : //sleep(2); //pause to give time for controller to update itself and throw a warning
335 :
336 0 : moveTo(m_preset_target);
337 : }
338 :
339 0 : m_homingState = 0;
340 : }
341 : }
342 : //Otherwise we don't do anything differently
343 0 : std::lock_guard<std::mutex> guard(m_indiMutex);
344 :
345 : static int last_moving = -10;
346 :
347 0 : bool changed = false;
348 0 : if(last_moving != m_moving)
349 : {
350 0 : changed = true;
351 0 : last_moving = m_moving;
352 : }
353 :
354 0 : if(changed)
355 : {
356 0 : if(m_moving)
357 : {
358 0 : m_indiP_pos.setState(INDI_BUSY);
359 0 : m_indiP_rawPos.setState(INDI_BUSY);
360 : }
361 : else
362 : {
363 0 : m_indiP_pos.setState(INDI_IDLE);
364 0 : m_indiP_pos["target"] = m_pos;
365 0 : m_indiP_rawPos.setState(INDI_IDLE);
366 0 : m_indiP_rawPos["target"] = m_rawPos;
367 : }
368 :
369 0 : m_indiDriver->sendSetProperty(m_indiP_pos);
370 0 : m_indiDriver->sendSetProperty(m_indiP_rawPos);
371 : }
372 :
373 0 : if(m_moving && m_movingState < 1)
374 : {
375 0 : updateIfChanged(m_indiP_pos, "current", m_pos, INDI_BUSY);
376 0 : updateIfChanged(m_indiP_rawPos, "current", m_rawPos, INDI_BUSY);
377 : }
378 : else
379 : {
380 0 : updateIfChanged(m_indiP_pos, "current", m_pos,INDI_IDLE);
381 0 : updateIfChanged(m_indiP_rawPos, "current", m_rawPos,INDI_IDLE);
382 : }
383 :
384 0 : int n = presetNumber();
385 0 : if(n == -1)
386 : {
387 0 : m_preset = 0;
388 0 : m_preset_target = 0;
389 : }
390 : else
391 : {
392 0 : m_preset = n+1;
393 0 : m_preset_target = n+1;
394 : }
395 :
396 0 : recordStage();
397 0 : recordZaber();
398 :
399 0 : dev::stdMotionStage<zaberCtrl>::updateINDI();
400 :
401 0 : if(telemeter<zaberCtrl>::appLogic() < 0)
402 : {
403 0 : log<software_error>({__FILE__, __LINE__});
404 0 : return 0;
405 : }
406 :
407 0 : return 0;
408 0 : }
409 :
410 0 : int zaberCtrl::appShutdown()
411 : {
412 0 : return 0;
413 : }
414 :
415 0 : int zaberCtrl::startHoming()
416 : {
417 0 : updateSwitchIfChanged(m_indiP_home, "request", pcf::IndiElement::Off, INDI_IDLE);
418 :
419 0 : pcf::IndiProperty indiP_stageHome = pcf::IndiProperty(pcf::IndiProperty::Text);
420 0 : indiP_stageHome.setDevice(m_lowLevelName);
421 0 : indiP_stageHome.setName("req_home");
422 0 : indiP_stageHome.setPerm(pcf::IndiProperty::ReadWrite);
423 0 : indiP_stageHome.setState(pcf::IndiProperty::Idle);
424 0 : indiP_stageHome.add(pcf::IndiElement(m_stageName));
425 :
426 0 : m_moving = 2;
427 0 : m_homingState = 1;
428 0 : if( sendNewProperty(indiP_stageHome, m_stageName, "1") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
429 :
430 0 : return 0;
431 0 : }
432 :
433 0 : int zaberCtrl::stop()
434 : {
435 0 : updateSwitchIfChanged(m_indiP_stop, "request", pcf::IndiElement::Off, INDI_IDLE);
436 :
437 0 : pcf::IndiProperty indiP_stageHalt = pcf::IndiProperty(pcf::IndiProperty::Text);
438 0 : indiP_stageHalt.setDevice(m_lowLevelName);
439 0 : indiP_stageHalt.setName("req_halt");
440 0 : indiP_stageHalt.setPerm(pcf::IndiProperty::ReadWrite);
441 0 : indiP_stageHalt.setState(pcf::IndiProperty::Idle);
442 0 : indiP_stageHalt.add(pcf::IndiElement(m_stageName));
443 :
444 0 : if( sendNewProperty(indiP_stageHalt, m_stageName, "1") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
445 :
446 0 : return 0;
447 0 : }
448 :
449 0 : double zaberCtrl::presetNumber()
450 : {
451 0 : for( size_t n=1; n < m_presetPositions.size(); ++n)
452 : {
453 0 : if( fabs(m_pos-m_presetPositions[n]) < 1./m_countsPerMillimeter) return n;
454 : }
455 :
456 0 : return 0;
457 : }
458 :
459 0 : int zaberCtrl::moveTo( const double & target)
460 : {
461 0 : if(target < 0) return 0;
462 :
463 0 : m_tgtRawPos = (target*m_countsPerMillimeter + 0.5);
464 :
465 0 : pcf::IndiProperty indiP_stageTgtPos = pcf::IndiProperty(pcf::IndiProperty::Number);
466 0 : indiP_stageTgtPos.setDevice(m_lowLevelName);
467 0 : indiP_stageTgtPos.setName("tgt_pos");
468 0 : indiP_stageTgtPos.setPerm(pcf::IndiProperty::ReadWrite);
469 0 : indiP_stageTgtPos.setState(pcf::IndiProperty::Idle);
470 0 : indiP_stageTgtPos.add(pcf::IndiElement(m_stageName));
471 :
472 0 : m_moving = 1;
473 0 : dev::stdMotionStage<zaberCtrl>::recordStage(true);
474 0 : recordZaber(true);
475 :
476 0 : if( sendNewProperty(indiP_stageTgtPos, m_stageName, m_tgtRawPos) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
477 :
478 0 : return 0;
479 0 : }
480 :
481 3 : INDI_NEWCALLBACK_DEFN( zaberCtrl, m_indiP_pos)(const pcf::IndiProperty &ipRecv)
482 : {
483 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_pos, ipRecv);
484 :
485 : double target =-1;
486 : if( ipRecv.find("target") ) //Just not our stage.
487 : {
488 : target = ipRecv["target"].get<double>();
489 : }
490 :
491 : if(target < 0)
492 : {
493 : return 0;
494 : /*if( ipRecv.find("current") ) //Just not our stage.
495 : {
496 : target = ipRecv["current"].get<double>();
497 : }
498 :
499 : if(target < 0 )
500 : {
501 : return log<text_log,-1>("no valid target position provided", logPrio::LOG_ERROR);
502 : }*/
503 : }
504 :
505 : if(m_moving != 0)
506 : {
507 : log<text_log>("abs move to " + std::to_string(target) + " rejected due to already moving");
508 : return 0;
509 : }
510 :
511 : log<text_log>("moving stage to " + std::to_string(target));
512 :
513 : std::lock_guard<std::mutex> guard(m_indiMutex);
514 :
515 : m_tgtPos = target;
516 :
517 : moveTo(m_tgtPos);
518 : updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
519 : updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
520 : return 0;
521 : }
522 :
523 3 : INDI_NEWCALLBACK_DEFN( zaberCtrl, m_indiP_rawPos)(const pcf::IndiProperty &ipRecv)
524 : {
525 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_rawPos, ipRecv);
526 :
527 : double target =-1;
528 : if( ipRecv.find("target") ) //Just not our stage.
529 : {
530 : target = ipRecv["target"].get<double>();
531 : }
532 :
533 : if(target < 0)
534 : {
535 : if( ipRecv.find("current") ) //Just not our stage.
536 : {
537 : target = ipRecv["current"].get<double>();
538 : }
539 :
540 : if(target < 0 )
541 : {
542 : return log<text_log,-1>("no valid target position provided", logPrio::LOG_ERROR);
543 : }
544 : }
545 :
546 : if(m_moving != 0)
547 : {
548 : log<text_log>("rel move rejected due to already moving");
549 : return 0;
550 : }
551 :
552 : log<text_log>("moving stage by " + std::to_string(target));
553 :
554 : std::lock_guard<std::mutex> guard(m_indiMutex);
555 :
556 : pcf::IndiProperty indiP_stageTgtPos = pcf::IndiProperty(pcf::IndiProperty::Text);
557 : indiP_stageTgtPos.setDevice(m_lowLevelName);
558 : indiP_stageTgtPos.setName("tgt_pos");
559 : indiP_stageTgtPos.setPerm(pcf::IndiProperty::ReadWrite);
560 : indiP_stageTgtPos.setState(pcf::IndiProperty::Idle);
561 : indiP_stageTgtPos.add(pcf::IndiElement(m_stageName));
562 :
563 : dev::stdMotionStage<zaberCtrl>::recordStage(true);
564 :
565 : if( sendNewProperty(indiP_stageTgtPos, m_stageName, target) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
566 :
567 :
568 : m_tgtRawPos = target;
569 : m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
570 : updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
571 : updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
572 : return 0;
573 : }
574 :
575 :
576 :
577 3 : INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageState)(const pcf::IndiProperty &ipRecv)
578 : {
579 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageState, ipRecv);
580 :
581 : if( ipRecv.find(m_stageName) != true ) //Just not our stage.
582 : {
583 : return 0;
584 : }
585 :
586 : m_indiP_stageState = ipRecv;
587 :
588 : std::string sstr = ipRecv[m_stageName].get<std::string>();
589 :
590 : std::lock_guard<std::mutex> guard(m_indiMutex);
591 :
592 : if(sstr == "POWEROFF")
593 : {
594 : state(stateCodes::POWEROFF);
595 : m_moving = -2;
596 : }
597 : else if(sstr == "POWERON")
598 : {
599 : state(stateCodes::POWERON);
600 : m_moving = -1;
601 : }
602 : else if(sstr == "NODEVICE")
603 : {
604 : state(stateCodes::NODEVICE);
605 : m_moving = -2;
606 : }
607 : else if(sstr == "NOTCONNECTED")
608 : {
609 : state(stateCodes::NOTCONNECTED);
610 : m_moving = -2;
611 : }
612 : else if(sstr == "CONNECTED")
613 : {
614 : state(stateCodes::CONNECTED);
615 : m_moving = -2;
616 : }
617 : else if(sstr == "NOTHOMED")
618 : {
619 : state(stateCodes::NOTHOMED);
620 : m_moving = -1;
621 : }
622 : else if(sstr == "HOMING")
623 : {
624 : state(stateCodes::HOMING);
625 : m_homingState = 1;
626 : m_moving = 2;
627 : }
628 : else if(sstr == "READY")
629 : {
630 : if(m_homingState == 0)
631 : {
632 : state(stateCodes::READY);
633 : }
634 : else
635 : {
636 : m_homingState = 2;
637 : }
638 : m_moving = 0;
639 : }
640 : else if(sstr == "OPERATING")
641 : {
642 : state(stateCodes::OPERATING);
643 : m_moving = 1;
644 : }
645 : else if(sstr == "SHUTDOWN")
646 : {
647 : state(stateCodes::NOTCONNECTED);
648 : m_moving = -2;
649 : }
650 : else if(sstr == "FAILURE")
651 : {
652 : state(stateCodes::FAILURE);
653 : m_moving = -2;
654 : }
655 : else if(sstr == "ERROR")
656 : {
657 : state(stateCodes::ERROR);
658 : m_moving = -2;
659 : }
660 : else
661 : {
662 : std::cerr << "else: " << sstr << "\n";
663 : state(stateCodes::UNINITIALIZED);
664 : m_moving = -2;
665 : }
666 : return 0;
667 : }
668 :
669 3 : INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageMaxRawPos )(const pcf::IndiProperty &ipRecv)
670 : {
671 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageMaxRawPos, ipRecv);
672 :
673 : if( ipRecv.find(m_stageName) != true ) //Just not our stage.
674 : {
675 : return 0;
676 : }
677 :
678 : std::lock_guard<std::mutex> guard(m_indiMutex);
679 :
680 : long maxRawPos = ipRecv[m_stageName].get<long>();
681 :
682 : if(maxRawPos > 10000000000000 || maxRawPos < 0) return 0; //Indicates a bad value
683 :
684 : if((unsigned long) maxRawPos != m_maxRawPos && (state() == stateCodes::CONNECTED|| state() == stateCodes::HOMING || state() == stateCodes::READY || state() == stateCodes::OPERATING))
685 : {
686 : log<text_log>("max position mismatch between config-ed value (" + std::to_string(m_maxRawPos) + ") and stage value (" + std::to_string(maxRawPos) + ")", logPrio::LOG_WARNING);
687 : }
688 :
689 : return 0;
690 : }
691 :
692 3 : INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageRawPos )(const pcf::IndiProperty &ipRecv)
693 : {
694 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageRawPos, ipRecv);
695 :
696 : if( ipRecv.find(m_stageName) != true ) //Just not our stage.
697 : {
698 : return 0;
699 : }
700 :
701 : std::lock_guard<std::mutex> guard(m_indiMutex);
702 :
703 : m_rawPos = ipRecv[m_stageName].get<double>();
704 :
705 : m_pos = m_rawPos / m_countsPerMillimeter;
706 :
707 : if(m_moving)
708 : {
709 : updateIfChanged(m_indiP_rawPos, "current", m_rawPos, INDI_BUSY);
710 : updateIfChanged(m_indiP_pos, "current", m_pos, INDI_BUSY);
711 : }
712 : else
713 : {
714 : updateIfChanged(m_indiP_rawPos, "current", m_rawPos, INDI_IDLE);
715 : updateIfChanged(m_indiP_pos, "current", m_pos, INDI_IDLE);
716 : }
717 :
718 : dev::stdMotionStage<zaberCtrl>::recordStage();
719 :
720 : return 0;
721 : }
722 :
723 3 : INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageTgtPos )(const pcf::IndiProperty &ipRecv)
724 : {
725 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageTgtPos, ipRecv);
726 :
727 : if( ipRecv.find(m_stageName) != true ) //Just not our stage.
728 : {
729 : return 0;
730 : }
731 :
732 : //Test for empty property to see if target reached
733 : std::string test = ipRecv[m_stageName].get<std::string>();
734 :
735 : if(test == "")
736 : {
737 : return 0;
738 : }
739 :
740 : std::lock_guard<std::mutex> guard(m_indiMutex);
741 :
742 : m_tgtRawPos = ipRecv[m_stageName].get<double>();
743 : m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
744 :
745 : if(m_moving)
746 : {
747 : updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
748 : updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
749 : }
750 : else
751 : {
752 : updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_IDLE);
753 : updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_IDLE);
754 : }
755 :
756 : return 0;
757 : }
758 :
759 3 : INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageTemp )(const pcf::IndiProperty &ipRecv)
760 : {
761 3 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageTemp, ipRecv);
762 :
763 : if( ipRecv.find(m_stageName) != true ) //Just not our stage.
764 : {
765 : return 0;
766 : }
767 :
768 : std::lock_guard<std::mutex> guard(m_indiMutex);
769 :
770 : m_stageTemp = ipRecv[m_stageName].get<double>();
771 :
772 : updateIfChanged(m_indiP_temp, "current", m_stageTemp);
773 :
774 : return 0;
775 : }
776 :
777 0 : int zaberCtrl::checkRecordTimes()
778 : {
779 0 : return telemeter<zaberCtrl>::checkRecordTimes(telem_stage(), telem_zaber());
780 : }
781 :
782 0 : int zaberCtrl::recordTelem( const telem_stage * )
783 : {
784 0 : return stdMotionStage<zaberCtrl>::recordStage(true);
785 : }
786 :
787 0 : int zaberCtrl::recordTelem( const telem_zaber * )
788 : {
789 0 : return recordZaber(true);
790 : }
791 :
792 0 : int zaberCtrl::recordZaber(bool force)
793 : {
794 0 : static double last_pos = m_pos - 1000;
795 0 : static double last_rawPos = m_rawPos;
796 0 : static double last_temp = m_stageTemp;
797 :
798 0 : if( m_pos != last_pos || m_rawPos != last_rawPos || m_stageTemp != last_temp || force)
799 : {
800 0 : telem<telem_zaber>({(float) m_pos, (float) m_rawPos, (float) m_stageTemp});
801 :
802 0 : last_pos = m_pos;
803 0 : last_rawPos = m_rawPos;
804 0 : last_temp = m_stageTemp;
805 : }
806 :
807 :
808 0 : return 0;
809 : }
810 :
811 : } //namespace app
812 : } //namespace MagAOX
813 :
814 : #endif //zaberCtrl_hpp
|