API
 
Loading...
Searching...
No Matches
pi335Ctrl.hpp
Go to the documentation of this file.
1/** \file pi335Ctrl.hpp
2 * \brief The MagAO-X XXXXXX header file
3 *
4 * \ingroup pi335Ctrl_files
5 */
6
7#ifndef pi335Ctrl_hpp
8#define pi335Ctrl_hpp
9
10#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
11#include "../../magaox_git_version.h"
12
13/** \defgroup pi335Ctrl
14 * \brief The MagAO-X application to interface with a PI-335 Controller
15 *
16 * <a href="..//apps_html/page_module_pi335Ctrl.html">Application Documentation</a>
17 *
18 * \ingroup apps
19 *
20 */
21
22/** \defgroup pi335Ctrl_files
23 * \ingroup pi335Ctrl
24 */
25
26namespace MagAOX
27{
28namespace app
29{
30
31/// The MagAO-X PI 335 Controller Interface
32/**
33 * \ingroup pi335Ctrl
34 */
35class pi335Ctrl : public MagAOXApp<true>, public tty::usbDevice, public dev::ioDevice, public dev::dm<pi335Ctrl, float>, public dev::shmimMonitor<pi335Ctrl>, public dev::telemeter<pi335Ctrl>
36{
37
38 // Give the test harness access.
39 friend class pi335Ctrl_test;
40
41 friend class dev::dm<pi335Ctrl, float>;
42
44
45 friend class dev::shmimMonitor<pi335Ctrl>;
46
48
49 friend class dev::telemeter<pi335Ctrl>;
50
52
53protected:
54 /** \name Configurable Parameters
55 *@{
56 */
57
58 float m_posTol{0.05}; ///< The tolerance for reporting a raw position rather than the setpoint.
59
60 float m_homePos1{17.5}; ///< Home position of axis 1. Default is 17.5
61 float m_homePos2{17.5}; ///< Home position of axis 2. Default is 17.5
62 float m_homePos3{0.0}; ///< Home position of axis 2. Default is 17.5
63
64 ///@}
65
66private:
67 std::string m_ctrl; ///< The controller connected.
68 std::string m_stage; ///< The stage connected.
69 int m_naxes{2}; ///< The number of axes, default is 2. Max is 3.
70
71 bool m_pos_3_sent{false};
72
73 bool m_actuallyATZ{true};
74
75protected:
76 float m_min1{0}; ///< The minimum value for axis 1
77 float m_max1{35}; ///< The maximum value for axis 1
78
79 float m_min2{0}; ///< The minimum value for axis 2
80 float m_max2{35}; ///< The maximum value for axis 2
81
82 float m_min3{0}; ///< The minimum value for axis 3
83 float m_max3{0}; ///< The maximum value for axis 3
84
85 double m_homingStart{0};
87
89
90 float m_pos1Set{0};
91 float m_pos1{0};
92
93 float m_pos2Set{0};
94 float m_pos2{0};
95
96 float m_pos3Set{0};
97 float m_pos3{0};
98
99 float m_sva1{0};
100 float m_sva2{0};
101 float m_sva3{0};
102
103public:
104 /// Default c'tor.
105 pi335Ctrl();
106
107 /// D'tor, declared and defined for noexcept.
109 {
110 }
111
112 virtual void setupConfig();
113
114 /// Implementation of loadConfig logic, separated for testing.
115 /** This is called by loadConfig().
116 */
117 int loadConfigImpl(mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/);
118
119 virtual void loadConfig();
120
121 /// Startup function
122 /**
123 *
124 */
125 virtual int appStartup();
126
127 /// Implementation of the FSM for pi335Ctrl.
128 /**
129 * \returns 0 on no critical error
130 * \returns -1 on an error requiring shutdown
131 */
132 virtual int appLogic();
133
134 /// Shutdown the app.
135 /**
136 *
137 */
138 virtual int appShutdown();
139
140 /// Test the connection to the device
141 /** Uses the *IDN? query
142 *
143 * \returns 0 if the E227 is found
144 * \returns -1 on an error
145 */
146 int testConnection();
147
148 int initDM();
149
150 /// Start the homing procedure
151 /** Checks that servos are off (the manual says this doesn't matter),
152 * and then begins homing by calling 'home_1()'.
153 * Sets FSM state to homing.
154 *
155 * \returns 0 on success (from 'home_1()')
156 * \returns -1 on error
157 */
158 int home();
159
160 /// Get the status of homing on an axiz
161 /** Homing is also autozero, ATZ. This uses the ATZ? query to
162 * check if the autozero procedure has completed on the given axis.
163 *
164 * \returns 0 if ATZ not complete
165 * \returns 1 if ATZ complete
166 * \returns -1 on an error
167 */
168 int homeState(int axis /**< [in] the axis to check, 0 or 1 */);
169
170 /// Begin homing (ATZ) axis 1
171 /** Repeats check that servos are off (the manual says this doesn't matter)
172 * and checks that 'm_homingStatte' is 0. Then sends 'ATZ 1 NaN'.
173 *
174 * \returns 0 on success
175 * \returns -1 on error
176 */
177 int home_1();
178
179 /// Begin homing (ATZ) axis 2
180 /** Repeats check that servos are off (the manual says this doesn't matter)
181 * and checks that 'm_homingStatte' is 1. Then sends 'ATZ 2 NaN'.
182 *
183 * \returns 0 on success
184 * \returns -1 on error
185 */
186 int home_2();
187
188 /// Begin homing (ATZ) axis 3
189 /** Repeats check that servos are off (the manual says this doesn't matter)
190 * and checks that 'm_homingStatte' is 1. Then sends 'ATZ 3 NaN'.
191 *
192 * \returns 0 on success
193 * \returns -1 on error
194 */
195 int home_3();
196
197 int finishInit();
198
199 /// Zero all commands on the DM
200 /** This does not update the shared memory buffer.
201 *
202 * \returns 0 on success
203 * \returns -1 on error
204 */
205 int zeroDM();
206
207 /// Send a command to the DM
208 /** This is called by the shmim monitoring thread in response to a semaphore trigger.
209 *
210 * \returns 0 on success
211 * \returns -1 on error
212 */
213 int commandDM(void *curr_src);
214
215 /// Release the DM, making it safe to turn off power.
216 /** The application will be state READY at the conclusion of this.
217 *
218 * \returns 0 on success
219 * \returns -1 on error
220 */
221 int releaseDM();
222
223 int setCom(const std::string &com);
224
225 int setCom(const std::string &com,
226 int axis);
227
228 int setCom(const std::string &com,
229 int axis,
230 const std::string &arg);
231
232 int getCom(std::string &resp,
233 const std::string &com,
234 int axis);
235
236 int getPos(float &pos,
237 int n);
238
239 /// Get the open loop control value
240 int getSva(float &sva,
241 int n);
242
243 /// Update the flat command and propagate
244 /** Writes the new desired position to the flat shmim, which is then propagated via the dmcomb
245 */
246 int updateFlat(float absPos1, ///< [in] The new position of axis 1
247 float absPos2, ///< [in] The new position of axis 2
248 float absPos3 ///< [in] The new position of axis 3
249 );
250
251 /// Send command to device to move axis 1
252 int move_1(float absPos);
253
254 /// Send command to device to move axis 2
255 int move_2(float absPos);
256
257 /// Send command to device to move axis 3
258 int move_3(float absPos);
259
260protected:
261 // declare our properties
262 pcf::IndiProperty m_indiP_pos1;
263 pcf::IndiProperty m_indiP_pos2;
264 pcf::IndiProperty m_indiP_pos3;
265
266public:
270
271 /** \name Telemeter Interface
272 * @{
273 */
274
275 int checkRecordTimes();
276
277 int recordTelem(const telem_pi335 *);
278
279 int recordPI335(bool force = false);
280
281 ///@}
282};
283
284pi335Ctrl::pi335Ctrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
285{
286 m_powerMgtEnabled = true;
287
288 return;
289}
290
292{
295
296 DM_SETUP_CONFIG(config);
297
299
300 config.add("stage.naxes", "", "stage.naxes", argType::Required, "stage", "naxes", false, "int", "Number of axes. Default is 2. Max is 3.");
301
302 config.add("stage.homePos1", "", "stage.homePos1", argType::Required, "stage", "homePos1", false, "float", "Home position of axis 1. Default is 17.5.");
303 config.add("stage.homePos2", "", "stage.homePos2", argType::Required, "stage", "homePos2", false, "float", "Home position of axis 2. Default is 17.5.");
304 config.add("stage.homePos3", "", "stage.homePos3", argType::Required, "stage", "homePos3", false, "float", "Home position of axis 3. Default is 17.5.");
305
306 config.add("dm.calibRelDir", "", "dm.calibRelDir", argType::Required, "dm", "calibRelDir", false, "string", "Used to find the default calib directory.");
307}
308
309int pi335Ctrl::loadConfigImpl(mx::app::appConfigurator &_config)
310{
311
312 this->m_baudRate = B115200; // default for E727 controller. Will be overridden by any config setting.
313
314 int rv = tty::usbDevice::loadConfig(_config);
315
316 if (rv != 0 && rv != TTY_E_NODEVNAMES && rv != TTY_E_DEVNOTFOUND)
317 {
319 }
320
322
323 m_calibRelDir = "ttmpupil";
324 config(m_calibRelDir, "dm.calibRelDir");
325
327
328 config(m_naxes, "stage.naxes");
329 config(m_homePos1, "stage.homePos1");
330 config(m_homePos2, "stage.homePos2");
331 config(m_homePos3, "stage.homePos3");
332
334
335 return 0;
336}
337
339{
340 loadConfigImpl(config);
341}
342
344{
346 {
347 log<text_log>("In appStartup but in state UNINITIALIZED.", logPrio::LOG_CRITICAL);
348 return -1;
349 }
350
351 ///\todo promote usbDevice to dev:: and make this part of its appStartup
352 // Get the USB device if it's in udev
353 if (m_deviceName != "")
354 {
355 log<text_log>(std::string("USB Device ") + m_idVendor + ":" + m_idProduct + ":" + m_serial + " found in udev as " + m_deviceName);
356 }
357
360
361 // set up the INDI properties
362 REG_INDI_NEWPROP(m_indiP_pos1, "pos_1", pcf::IndiProperty::Number);
363 m_indiP_pos1.add(pcf::IndiElement("current"));
364 m_indiP_pos1.add(pcf::IndiElement("target"));
365 m_indiP_pos1["current"] = -99999;
366 m_indiP_pos1["target"] = -99999;
367
368 REG_INDI_NEWPROP(m_indiP_pos2, "pos_2", pcf::IndiProperty::Number);
369 m_indiP_pos2.add(pcf::IndiElement("current"));
370 m_indiP_pos2.add(pcf::IndiElement("target"));
371 m_indiP_pos2["current"] = -99999;
372 m_indiP_pos2["target"] = -99999;
373
374 // Note: 3rd axis added in testConnection if it's found
375
377
378 return 0;
379}
380
382{
385
387
388 if (state() == stateCodes::POWERON)
389 {
390 if (!powerOnWaitElapsed())
391 {
392 return 0;
393 }
394 else
395 {
396 ///\todo promote usbDevice to dev:: and make this part of its appStartup
397 // Get the USB device if it's in udev
398 if (m_deviceName == "")
399 {
401 }
402 else
403 {
405 }
406 }
407 }
408
409 ///\todo promote usbDevice to dev:: and make this part of its appLogic
411 {
413 if (rv < 0 && rv != TTY_E_DEVNOTFOUND && rv != TTY_E_NODEVNAMES)
414 {
416 if (!stateLogged())
417 {
419 }
420 return -1;
421 }
422
424 {
426
427 if (!stateLogged())
428 {
429 log<text_log>(std::string("USB Device ") + m_idVendor + ":" + m_idProduct + ":" + m_serial + " not found in udev");
430 }
431 return 0;
432 }
433 else
434 {
436 if (!stateLogged())
437 {
438 log<text_log>(std::string("USB Device ") + m_idVendor + ":" + m_idProduct + ":" + m_serial + " found in udev as " + m_deviceName);
439 }
440 }
441 }
442
444 {
445 int rv;
446 { // scope for elPriv
447 elevatedPrivileges elPriv(this);
448 rv = connect();
449 }
450
451 if (rv < 0)
452 {
454 if (nrv < 0 && nrv != TTY_E_DEVNOTFOUND && nrv != TTY_E_NODEVNAMES)
455 {
457 if (!stateLogged())
459 return -1;
460 }
461
463 {
465
466 if (!stateLogged())
467 {
468 std::stringstream logs;
469 logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " no longer found in udev";
470 log<text_log>(logs.str());
471 }
472 return 0;
473 }
474
475 // if connect failed, and there is a device, then we have some other problem.
477 if (!stateLogged())
479 return -1;
480 }
481
482 if (testConnection() == 0)
483 {
485 }
486 else
487 {
488 return 0;
489 }
490 }
491
493 {
495 }
496
497 if (state() == stateCodes::HOMING)
498 {
499 int ax = m_homingState + 1;
500
501 int atz = homeState(ax);
502
503 if (!(atz == 0 || atz == 1))
504 {
506 log<software_error, -1>({__FILE__, __LINE__, "error getting ATZ? home state."});
507 }
508
509 if (atz == 1)
510 {
512
513 if (m_homingState == 1) // x complete
514 {
515 home_2();
516 }
517 else if (m_homingState == 2 && m_naxes == 2) // y complete, done
518 {
519 finishInit();
520 }
521 else if (m_homingState == 2 && m_naxes == 3) // y complete
522 {
523 home_3();
524 }
525 else if (m_homingState > 2)
526 {
527 finishInit();
528 }
529 }
530 }
531
533 {
534 if (m_flatSet)
536 else
538 }
539
540 if (state() == stateCodes::READY)
541 {
542 float pos1;
543 float sva1;
544 float pos2;
545 float sva2;
546 float pos3;
547 float sva3;
548
549 // Get a lock if we can
550 std::unique_lock<std::mutex> lock(m_indiMutex);
551
552 if (getPos(pos1, 1) < 0)
553 {
556 return 0;
557 }
558
559 lock.unlock();
560 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
561
562 m_pos1 = pos1;
563 if (fabs(m_pos1Set - m_pos1) > m_posTol)
564 {
566 }
567 else
568 {
570 }
571
572 lock.lock();
573 if (getSva(sva1, 1) < 0)
574 {
577 return 0;
578 }
579 m_sva1 = sva1;
580
581 lock.unlock();
582 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
583
584 lock.lock();
585 if (getPos(pos2, 2) < 0)
586 {
589 return 0;
590 }
591 lock.unlock();
592 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
593
594 m_pos2 = pos2;
595 if (fabs(m_pos2Set - m_pos2) > m_posTol) // sva2 != m_sva2)
596 {
598 }
599 else
600 {
602 }
603
604 lock.lock();
605 if (getSva(sva2, 2) < 0)
606 {
609 return 0;
610 }
611 lock.unlock();
612 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
613
614 m_sva2 = sva2;
615
616 if (m_naxes == 3)
617 {
618 lock.lock();
619 if (getPos(pos3, 3) < 0)
620 {
623 return 0;
624 }
625 lock.unlock();
626 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
627
628 m_pos3 = pos3;
629 if (fabs(m_pos3Set - m_pos3) > m_posTol)
630 {
632 }
633 else
634 {
636 }
637
638 lock.lock();
639 if (getSva(sva3, 2) < 0)
640 {
643 return 0;
644 }
645 lock.unlock();
646 mx::sys::milliSleep(1); // Put this thread to sleep to make sure other thread gets a lock
647
648 m_sva3 = sva3;
649 }
650
651 recordPI335();
652
653 /*std::cerr << m_pos1Set << " " << pos1 << " " << m_sva1 << " " << m_pos2Set << " " << pos2 << " " << m_sva2;
654 if(m_naxes == 3) std::cerr << " " << m_pos3Set << " " << pos3 << " " << m_sva3;
655 std::cerr << "\n";*/
656 }
657 else if (state() == stateCodes::OPERATING)
658 {
659 updateIfChanged<float>(m_indiP_pos1, std::vector<std::string>({"current", "target"}), {m_pos1, m_pos1Set}, INDI_BUSY);
660 updateIfChanged<float>(m_indiP_pos2, std::vector<std::string>({"current", "target"}), {m_pos2, m_pos2Set}, INDI_BUSY);
661
662 if (m_naxes == 3)
663 {
664 updateIfChanged<float>(m_indiP_pos3, std::vector<std::string>({"current", "target"}), {m_pos3, m_pos3Set}, INDI_BUSY);
665 }
666 }
667
670
671 return 0;
672}
673
682
684{
685 int rv;
686 std::string resp;
687
688 if ((rv = tty::ttyWriteRead(resp, "*IDN?\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
689 {
691 }
692
693 size_t st;
694 if ((st = resp.find("E-727.3SDA")) == std::string::npos)
695 {
696 return log<text_log, -1>("Unknown device found: " + resp, logPrio::LOG_CRITICAL);
697 }
698 m_ctrl = mx::ioutils::removeWhiteSpace(resp.substr(st));
699 log<text_log>(std::string("Connected to " + m_ctrl + " on ") + m_deviceName);
700
701 std::string resp1, resp2, resp3;
702
703 if ((rv = tty::ttyWriteRead(resp1, "CST? 1\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
704 {
706 }
707 resp1 = mx::ioutils::removeWhiteSpace(resp1);
708
709 if ((rv = tty::ttyWriteRead(resp2, "CST? 2\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
710 {
712 }
713 resp2 = mx::ioutils::removeWhiteSpace(resp2);
714
715 if ((rv = tty::ttyWriteRead(resp3, "CST? 3\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
716 {
718 }
719 resp3 = mx::ioutils::removeWhiteSpace(resp3);
720
721 updateIfChanged(m_indiP_pos1, "current", 0.0);
722 updateIfChanged(m_indiP_pos1, "target", 0.0);
723
724 updateIfChanged(m_indiP_pos2, "current", 0.0);
725 updateIfChanged(m_indiP_pos2, "target", 0.0);
726
727 if (resp1.find("1=S-335") == 0 && resp2.find("2=S-335") == 0 && resp3.find("3=0") == 0)
728 {
729 m_stage = resp1.substr(2);
730 m_naxes = 2;
731 m_actuallyATZ = true;
732 }
733 else if (resp1.find("1=S-325") == 0 && resp2.find("2=S-325") == 0 && resp3.find("3=S-325") == 0)
734 {
735 m_stage = resp1.substr(2);
736 m_naxes = 3;
737 m_actuallyATZ = false;
738 if (!m_pos_3_sent)
739 {
740 ///\todo this needs to only happen once, and then never again
741 REG_INDI_NEWPROP(m_indiP_pos3, "pos_3", pcf::IndiProperty::Number);
742 m_indiP_pos3.add(pcf::IndiElement("current"));
743 m_indiP_pos3.add(pcf::IndiElement("target"));
744 m_indiP_pos3["current"] = -99999999;
745 m_indiP_pos3["target"] = -99999999;
746 updateIfChanged(m_indiP_pos3, "current", 0.0);
747 updateIfChanged(m_indiP_pos3, "target", 0.0);
748 m_pos_3_sent = true;
749 }
750 }
751 else
752 {
753 return log<text_log, -1>("Unknown stage found: " + resp1 + " " + resp2 + " " + resp3, logPrio::LOG_CRITICAL);
754 }
755
756 log<text_log>("Found " + m_stage + " with " + std::to_string(m_naxes) + " axes");
757
758 //-------- now get axis limits
759
760 // axis 1
761
762 if ((rv = tty::ttyWriteRead(resp, "TMN? 1\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
763 {
765 }
766
767 if ((st = resp.find('=')) == std::string::npos)
768 {
769 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
770 }
771
772 m_min1 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
773 log<text_log>("axis 1 min: " + std::to_string(m_min1));
774
775 if ((rv = tty::ttyWriteRead(resp, "TMX? 1\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
776 {
778 }
779
780 if ((st = resp.find('=')) == std::string::npos)
781 {
782 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
783 }
784
785 m_max1 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
786 log<text_log>("axis 1 max: " + std::to_string(m_max1));
787
788 if ((rv = tty::ttyWriteRead(resp, "TMN? 2\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
789 {
791 }
792
793 if ((st = resp.find('=')) == std::string::npos)
794 {
795 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
796 }
797
798 m_min2 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
799 log<text_log>("axis 2 min: " + std::to_string(m_min2));
800
801 if ((rv = tty::ttyWriteRead(resp, "TMX? 2\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
802 {
804 }
805
806 if ((st = resp.find('=')) == std::string::npos)
807 {
808 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
809 }
810
811 m_max2 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
812 log<text_log>("axis 2 max: " + std::to_string(m_max2));
813
814 if (m_naxes == 3)
815 {
816 if ((rv = tty::ttyWriteRead(resp, "TMN? 3\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
817 {
819 }
820
821 if ((st = resp.find('=')) == std::string::npos)
822 {
823 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
824 }
825
826 m_min3 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
827 log<text_log>("axis 3 min: " + std::to_string(m_min3));
828
829 if ((rv = tty::ttyWriteRead(resp, "TMX? 3\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout)) < 0)
830 {
832 }
833
834 if ((st = resp.find('=')) == std::string::npos)
835 {
836 return log<software_critical, -1>({__FILE__, __LINE__, "invalid response"});
837 }
838
839 m_max3 = mx::ioutils::convertFromString<float>(resp.substr(st + 1));
840 log<text_log>("axis 3 max: " + std::to_string(m_max3));
841 }
842
843 m_flatCommand.resize(3, 1);
844 if (m_naxes == 2)
845 {
848 m_flatCommand(2, 0) = 0.0;
849 }
850 else if (m_naxes == 3)
851 {
855 }
856 m_flatLoaded = true;
857
858 return 0;
859}
860
862{
863 int rv;
864 std::string resp;
865
866 // get open-loop position of axis 1 (should be zero)
867 rv = tty::ttyWriteRead(resp, "SVA? 1\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
868
869 if (rv < 0)
870 {
872 }
873
874 // get open-loop position of axis 2 (should be zero)
875 rv = tty::ttyWriteRead(resp, "SVA? 2\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
876
877 if (rv < 0)
878 {
880 }
881
882 if (m_naxes == 3)
883 {
884 // get open-loop position of axis 2 (should be zero)
885 rv = tty::ttyWriteRead(resp, "SVA? 3\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
886
887 if (rv < 0)
888 {
890 }
891 }
892
893 // make sure axis 1 has servo off
895
896 if (rv < 0)
897 {
899 }
900
901 // make sure axis 2 has servo off
903
904 if (rv < 0)
905 {
907 }
908
909 if (m_naxes == 0)
910 {
911 // make sure axis 3 has servo off
913
914 if (rv < 0)
915 {
917 }
918 }
919
920 m_servoState = 0;
921
922 log<text_log>("servos off", logPrio::LOG_NOTICE);
923
924 return home();
925}
926
928{
929 if (m_servoState != 0)
930 {
931 log<text_log>("home requested but servos are not off", logPrio::LOG_ERROR);
932 return -1;
933 }
934
935 m_homingStart = 0;
936 m_homingState = 0;
937
939
940 return home_1();
941}
942
944{
945 if (!m_actuallyATZ)
946 return 1;
947 std::string resp;
948
949 if (getCom(resp, "ATZ?", axis) < 0)
950 {
952
953 return -1;
954 }
955
956 ///\todo this should be a separate unit-tested parser
957 size_t st = resp.find('=');
958 if (st == std::string::npos || st > resp.size() - 2)
959 {
960 log<software_error>({__FILE__, __LINE__, "error parsing response"});
961 return -1;
962 }
963 st += 1;
964
965 return mx::ioutils::convertFromString<double>(resp.substr(st));
966}
967
969{
970 int rv;
971
972 if (m_servoState != 0)
973 {
974 log<text_log>("home_1 requested but servos are not off", logPrio::LOG_ERROR);
975 return -1;
976 }
977
978 if (m_homingState != 0)
979 {
980 log<text_log>("home_1 requested but not in correct homing state", logPrio::LOG_ERROR);
981 return -1;
982 }
983
984 if (m_actuallyATZ)
985 {
986 // zero range found in axis 1 (NOTE this moves mirror full range) TAKES 1min
987 rv = tty::ttyWrite("ATZ 1 NaN\n", m_fileDescrip, m_writeTimeout);
988
989 if (rv < 0)
990 {
992 }
993 }
994
995 m_homingStart = mx::sys::get_curr_time(); ///\todo remmove m_homingStart once ATZ? works.
996 m_homingState = 0;
997 log<text_log>("commenced homing x");
998
999 return 0;
1000}
1001
1003{
1004 int rv;
1005
1006 if (m_servoState != 0)
1007 {
1008 log<text_log>("home_2 requested but servos are not off", logPrio::LOG_ERROR);
1009 return -1;
1010 }
1011
1012 if (m_homingState != 1)
1013 {
1014 log<text_log>("home_2 requested but not in correct homing state", logPrio::LOG_ERROR);
1015 return -1;
1016 }
1017
1018 if (m_actuallyATZ)
1019 {
1020 // zero range found in axis 2 (NOTE this moves mirror full range) TAKES 1min
1021 rv = tty::ttyWrite("ATZ 2 NaN\n", m_fileDescrip, m_writeTimeout);
1022
1023 if (rv < 0)
1024 {
1026 }
1027 }
1028
1029 m_homingStart = mx::sys::get_curr_time();
1030 log<text_log>("commenced homing y");
1031
1032 return 0;
1033}
1034
1036{
1037 int rv;
1038
1039 if (m_servoState != 0)
1040 {
1041 log<text_log>("home_3 requested but servos are not off", logPrio::LOG_ERROR);
1042 return -1;
1043 }
1044
1045 if (m_homingState != 2)
1046 {
1047 log<text_log>("home_3 requested but not in correct homing state", logPrio::LOG_ERROR);
1048 return -1;
1049 }
1050
1051 if (m_actuallyATZ)
1052 {
1053 // zero range found in axis 3 (NOTE this moves mirror full range) TAKES 1min
1054 rv = tty::ttyWrite("ATZ 3 NaN\n", m_fileDescrip, m_writeTimeout);
1055
1056 if (rv < 0)
1057 {
1059 }
1060 }
1061
1062 m_homingStart = mx::sys::get_curr_time();
1063 log<text_log>("commenced homing z");
1064
1065 return 0;
1066}
1067
1069{
1070 int rv;
1071 std::string resp;
1072
1073 if (m_servoState != 0)
1074 {
1075 log<text_log>("finishInit requested but servos are not off", logPrio::LOG_ERROR);
1076 return -1;
1077 }
1078
1079 if (m_naxes == 2 && m_homingState != 2)
1080 {
1081 log<text_log>("finishInit requested but not in correct homing state", logPrio::LOG_ERROR);
1082 return -1;
1083 }
1084 if (m_naxes == 3 && m_homingState != 3)
1085 {
1086 log<text_log>("finishInit requested but not in correct homing state", logPrio::LOG_ERROR);
1087 return -1;
1088 }
1089
1090 // goto openloop pos zero (0 V) axis 1
1091 rv = tty::ttyWrite("SVA 1 0.0\n", m_fileDescrip, m_writeTimeout);
1092
1093 if (rv < 0)
1094 {
1096 }
1097
1098 mx::sys::milliSleep(2000);
1099
1100 // goto openloop pos zero (0 V) axis 2
1101 rv = tty::ttyWrite("SVA 2 0.0\n", m_fileDescrip, m_writeTimeout);
1102
1103 if (rv < 0)
1104 {
1106 }
1107
1108 mx::sys::milliSleep(2000);
1109
1110 if (m_naxes == 3)
1111 {
1112 // goto openloop pos zero (0 V) axis 3
1113 rv = tty::ttyWrite("SVA 3 0.0\n", m_fileDescrip, m_writeTimeout);
1114
1115 if (rv < 0)
1116 {
1118 }
1119
1120 mx::sys::milliSleep(2000);
1121 }
1122
1123 // Get the real position of axis 1 (should be 0mrad st start)
1124 rv = tty::ttyWriteRead(resp, "SVA? 1\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
1125
1126 if (rv < 0)
1127 {
1129 }
1130
1131 // Get the real position of axis 2 (should be 0mrad st start)
1132 rv = tty::ttyWriteRead(resp, "SVA? 2\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
1133
1134 if (rv < 0)
1135 {
1137 }
1138
1139 if (m_naxes == 3)
1140 {
1141 // Get the real position of axis 3 (should be 0mrad st start)
1142 rv = tty::ttyWriteRead(resp, "SVA? 3\n", "\n", false, m_fileDescrip, m_writeTimeout, m_readTimeout);
1143
1144 if (rv < 0)
1145 {
1147 }
1148 }
1149
1150 // now safe to engage servos
1151 //(IMPORTANT: NEVER EVER enable servos on axis 3 -- will damage S-335)
1152 //(CAVEAT: for S-325 you CAN enable servors on axis 3)
1153
1154 // turn on servo to axis 1 (green servo LED goes on 727)
1156
1157 if (rv < 0)
1158 {
1160 }
1161
1162 mx::sys::milliSleep(250);
1163
1164 // turn on servo to axis 2 (green servo LED goes on 727)
1166
1167 if (rv < 0)
1168 {
1170 }
1171
1172 if (m_naxes == 3)
1173 {
1174 mx::sys::milliSleep(250);
1175
1176 // turn on servo to axis 3 (green servo LED goes on 727)
1178
1179 if (rv < 0)
1180 {
1182 }
1183 }
1184
1185 m_servoState = 1;
1186 log<text_log>("servos engaged", logPrio::LOG_NOTICE);
1187
1188 mx::sys::milliSleep(1000);
1189
1190 // now safe for closed loop moves
1191 // center axis 1 (to configured home position)
1192
1193 std::string com = "MOV 1 " + std::to_string(m_homePos1) + "\n";
1195
1196 if (rv < 0)
1197 {
1199 }
1200
1203
1204 // center axis 2 (to configured home position)
1205 com = "MOV 2 " + std::to_string(m_homePos2) + "\n";
1207
1208 if (rv < 0)
1209 {
1211 }
1212
1215
1216 if (m_naxes == 3)
1217 {
1218 // center axis 3 (to configured home position)
1219 com = "MOV 3 " + std::to_string(m_homePos3) + "\n";
1221
1222 if (rv < 0)
1223 {
1225 }
1226
1229 }
1230
1232
1233 return 0;
1234}
1235
1237{
1238 move_1(0.0);
1239 move_2(0.0);
1240 if (m_naxes == 3)
1241 move_3(0.0);
1242
1243 log<text_log>("DM zeroed");
1244 return 0;
1245}
1246
1247int pi335Ctrl::commandDM(void *curr_src)
1248{
1250 return 0;
1251 float pos1 = ((float *)curr_src)[0];
1252 float pos2 = ((float *)curr_src)[1];
1253
1254 float pos3 = 0;
1255 if (m_naxes == 3)
1256 pos3 = ((float *)curr_src)[2];
1257
1258 std::unique_lock<std::mutex> lock(m_indiMutex);
1259
1260 int rv;
1261 if ((rv = move_1(pos1)) < 0)
1262 return rv;
1263
1264 if ((rv = move_2(pos2)) < 0)
1265 return rv;
1266
1267 if (m_naxes == 3)
1268 if ((rv = move_3(pos3)) < 0)
1269 return rv;
1270
1271 return 0;
1272}
1273
1275{
1276 int rv;
1277
1278 if (m_servoState != 0)
1279 {
1280 if ((rv = tty::ttyWrite("SVO 1 0\n", m_fileDescrip, m_writeTimeout)) < 0)
1281 {
1283 }
1284
1285 if ((rv = tty::ttyWrite("SVO 2 0\n", m_fileDescrip, m_writeTimeout)) < 0)
1286 {
1288 }
1289
1290 m_servoState = 0;
1291
1292 log<text_log>("servos off", logPrio::LOG_NOTICE);
1293 }
1294
1295 if ((rv = tty::ttyWrite("SVA 1 0\n", m_fileDescrip, m_writeTimeout)) < 0)
1296 {
1298 }
1299
1300 if ((rv = tty::ttyWrite("SVA 2 0\n", m_fileDescrip, m_writeTimeout)) < 0)
1301 {
1303 }
1304
1305 if (m_naxes == 3)
1306 {
1307 if ((rv = tty::ttyWrite("SVA 2 0\n", m_fileDescrip, m_writeTimeout)) < 0)
1308 {
1310 }
1311 }
1312
1313 m_flatSet = false;
1315
1316 return 0;
1317}
1318
1319int pi335Ctrl::getCom(std::string &resp,
1320 const std::string &com,
1321 int axis)
1322{
1323 std::string sendcom = com;
1324 if (axis == 1 || axis == 2)
1325 {
1326 sendcom += " ";
1327 sendcom += std::to_string(axis);
1328 }
1329
1330 sendcom += "\n";
1331
1333 if (rv < 0)
1334 {
1336 return -1;
1337 }
1338
1339 return 0;
1340}
1341
1342int pi335Ctrl::getPos(float &pos,
1343 int n)
1344{
1345 std::string resp;
1346 if (getCom(resp, "POS?", n) < 0)
1347 {
1349 }
1350
1351 ///\todo this should be a separate unit-tested parser
1352 size_t st = resp.find('=');
1353 if (st == std::string::npos || st > resp.size() - 2)
1354 {
1355 log<software_error>({__FILE__, __LINE__, "error parsing response"});
1356 return -1;
1357 }
1358 st += 1;
1359 pos = mx::ioutils::convertFromString<double>(resp.substr(st));
1360
1361 return 0;
1362}
1363
1364int pi335Ctrl::getSva(float &sva,
1365 int n)
1366{
1367 std::string resp;
1368 if (getCom(resp, "SVA?", n) < 0)
1369 {
1371 }
1372
1373 ///\todo this should be a separate unit-tested parser
1374 size_t st = resp.find('=');
1375 if (st == std::string::npos || st > resp.size() - 2)
1376 {
1377 log<software_error>({__FILE__, __LINE__, "error parsing response"});
1378 return -1;
1379 }
1380 st += 1;
1381 sva = mx::ioutils::convertFromString<double>(resp.substr(st));
1382
1383 return 0;
1384}
1385
1386int pi335Ctrl::updateFlat(float absPos1,
1387 float absPos2,
1388 float absPos3)
1389{
1390 m_flatCommand(0, 0) = absPos1;
1391 m_flatCommand(1, 0) = absPos2;
1392 m_flatCommand(2, 0) = absPos3;
1393
1395 {
1396 return setFlat(true);
1397 }
1398 else
1399 {
1400 return 0;
1401 }
1402}
1403
1404int pi335Ctrl::move_1(float absPos)
1405{
1406 int rv;
1407
1409 {
1410 log<text_log>("request move on azis 1 out of range", logPrio::LOG_ERROR);
1411 return -1;
1412 }
1413
1414 m_pos1Set = absPos;
1415
1416 std::string com = "MOV 1 " + std::to_string(absPos) + "\n";
1417
1419
1420 if (rv < 0)
1421 {
1423 }
1424
1425 return 0;
1426}
1427
1428int pi335Ctrl::move_2(float absPos)
1429{
1430 int rv;
1431
1433 {
1434 log<text_log>("request move on azis 2 out of range", logPrio::LOG_ERROR);
1435 return -1;
1436 }
1437
1438 m_pos2Set = absPos;
1439 std::string com = "MOV 2 " + std::to_string(absPos) + "\n";
1440
1442
1443 if (rv < 0)
1444 {
1446 }
1447
1448 return 0;
1449}
1450
1451int pi335Ctrl::move_3(float absPos)
1452{
1453 if (m_naxes < 3)
1454 {
1455 return log<software_error, -1>({__FILE__, __LINE__, "tried to move axis 3 but we don't have that"});
1456 }
1457
1458 int rv;
1459
1461 {
1462 log<text_log>("request move on azis 3 out of range", logPrio::LOG_ERROR);
1463 return -1;
1464 }
1465
1466 m_pos3Set = absPos;
1467 std::string com = "MOV 3 " + std::to_string(absPos) + "\n";
1468
1470
1471 if (rv < 0)
1472 {
1474 }
1475
1476 return 0;
1477}
1478
1479INDI_NEWCALLBACK_DEFN(pi335Ctrl, m_indiP_pos1)
1480(const pcf::IndiProperty &ipRecv)
1481{
1482 if (ipRecv.createUniqueKey() == m_indiP_pos1.createUniqueKey())
1483 {
1484 float current = -999999, target = -999999;
1485
1486 if (ipRecv.find("current"))
1487 {
1488 current = ipRecv["current"].get<float>();
1489 }
1490
1491 if (ipRecv.find("target"))
1492 {
1493 target = ipRecv["target"].get<float>();
1494 }
1495
1496 if (target == -999999)
1497 target = current;
1498
1499 if (target == -999999)
1500 return 0;
1501
1502 if (state() == stateCodes::READY)
1503 {
1504 // Lock the mutex, waiting if necessary
1505 std::unique_lock<std::mutex> lock(m_indiMutex);
1506
1507 updateIfChanged(m_indiP_pos1, "target", target);
1508
1509 updateFlat(target, m_pos2Set, m_pos3Set); // This just changes the values, but doesn't move
1510
1511 return move_1(target);
1512 }
1513 else if (state() == stateCodes::OPERATING)
1514 {
1515 return updateFlat(target, m_pos2Set, m_pos3Set);
1516 }
1517 }
1518 return -1;
1519}
1520
1521INDI_NEWCALLBACK_DEFN(pi335Ctrl, m_indiP_pos2)
1522(const pcf::IndiProperty &ipRecv)
1523{
1524 if (ipRecv.createUniqueKey() == m_indiP_pos2.createUniqueKey())
1525 {
1526 float current = -999999, target = -999999;
1527
1528 if (ipRecv.find("current"))
1529 {
1530 current = ipRecv["current"].get<float>();
1531 }
1532
1533 if (ipRecv.find("target"))
1534 {
1535 target = ipRecv["target"].get<float>();
1536 }
1537
1538 if (target == -999999)
1539 target = current;
1540
1541 if (target == -999999)
1542 return 0;
1543
1544 if (state() == stateCodes::READY)
1545 {
1546 // Lock the mutex, waiting if necessary
1547 std::unique_lock<std::mutex> lock(m_indiMutex);
1548
1549 updateIfChanged(m_indiP_pos2, "target", target);
1550 updateFlat(m_pos1Set, target, m_pos3Set); // This just changes the values, but doesn't move
1551 return move_2(target);
1552 }
1553 else if (state() == stateCodes::OPERATING)
1554 {
1555 return updateFlat(m_pos1Set, target, m_pos3Set);
1556 }
1557 }
1558 return -1;
1559}
1560
1561INDI_NEWCALLBACK_DEFN(pi335Ctrl, m_indiP_pos3)
1562(const pcf::IndiProperty &ipRecv)
1563{
1564
1565 if (ipRecv.getName() == m_indiP_pos3.getName())
1566 {
1567 float current = -999999, target = -999999;
1568
1569 if (ipRecv.find("current"))
1570 {
1571 current = ipRecv["current"].get<float>();
1572 }
1573
1574 if (ipRecv.find("target"))
1575 {
1576 target = ipRecv["target"].get<float>();
1577 }
1578
1579 if (target == -999999)
1580 target = current;
1581
1582 if (target == -999999)
1583 return 0;
1584
1585 if (state() == stateCodes::READY)
1586 {
1587 // Lock the mutex, waiting if necessary
1588 std::unique_lock<std::mutex> lock(m_indiMutex);
1589
1590 updateIfChanged(m_indiP_pos3, "target", target);
1591
1592 updateFlat(m_pos1Set, m_pos2Set, target); // This just changes the values, but doesn't move
1593 return move_3(target);
1594 }
1595 else if (state() == stateCodes::OPERATING)
1596 {
1597 return updateFlat(m_pos1Set, m_pos2Set, target);
1598 }
1599 }
1600 return -1;
1601}
1602
1607
1609{
1610 return recordPI335(true);
1611}
1612
1614{
1615 static float pos1Set = std::numeric_limits<float>::max();
1616 static float pos1 = std::numeric_limits<float>::max();
1617 static float sva1 = std::numeric_limits<float>::max();
1618 static float pos2Set = std::numeric_limits<float>::max();
1619 static float pos2 = std::numeric_limits<float>::max();
1620 static float sva2 = std::numeric_limits<float>::max();
1621 static float pos3Set = std::numeric_limits<float>::max();
1622 static float pos3 = std::numeric_limits<float>::max();
1623 static float sva3 = std::numeric_limits<float>::max();
1624
1625 if (force || m_pos1Set != pos1Set || m_pos1 != pos1 || m_sva1 != sva1 ||
1626 m_pos2Set != pos2Set || m_pos2 != pos2 || m_sva2 != sva2 ||
1627 m_pos3Set != pos3Set || m_pos3 != pos3 || m_sva3 != sva3)
1628 {
1630
1631 pos1Set = m_pos1Set;
1632 pos1 = m_pos1;
1633 sva1 = m_sva1;
1634 pos2Set = m_pos2Set;
1635 pos2 = m_pos2;
1636 sva2 = m_sva2;
1637 pos3Set = m_pos3Set;
1638 pos3 = m_pos3;
1639 sva3 = m_sva3;
1640 }
1641
1642 return 0;
1643}
1644
1645} // namespace app
1646} // namespace MagAOX
1647
1648#endif // pi335Ctrl_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
stateCodes::stateCodeT state()
Get the current state code.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
bool powerOnWaitElapsed()
This method tests whether the power on wait time has elapsed.
std::mutex m_indiMutex
Mutex for locking INDI communications.
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
Definition dm.hpp:107
bool m_flatSet
Flag indicating whether the flat command has been set.
Definition dm.hpp:118
bool m_flatLoaded
Flag indicating whether a flat is loaded in memory.
Definition dm.hpp:115
int setFlat(bool update=false)
Send the current flat command to the DM.
Definition dm.hpp:1285
mx::improc::eigenImage< float > m_flatCommand
Data storage for the flat command.
Definition dm.hpp:114
The MagAO-X PI 335 Controller Interface.
Definition pi335Ctrl.hpp:36
virtual int appShutdown()
Shutdown the app.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos2)
dev::shmimMonitor< pi335Ctrl > shmimMonitorT
Definition pi335Ctrl.hpp:47
int testConnection()
Test the connection to the device.
virtual void loadConfig()
int commandDM(void *curr_src)
Send a command to the DM.
int home()
Start the homing procedure.
int m_naxes
The number of axes, default is 2. Max is 3.
Definition pi335Ctrl.hpp:69
int setCom(const std::string &com)
float m_max1
The maximum value for axis 1.
Definition pi335Ctrl.hpp:77
float m_posTol
The tolerance for reporting a raw position rather than the setpoint.
Definition pi335Ctrl.hpp:58
pcf::IndiProperty m_indiP_pos3
int getSva(float &sva, int n)
Get the open loop control value.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos1)
int getPos(float &pos, int n)
int recordTelem(const telem_pi335 *)
float m_homePos1
Home position of axis 1. Default is 17.5.
Definition pi335Ctrl.hpp:60
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos3)
~pi335Ctrl() noexcept
D'tor, declared and defined for noexcept.
friend class pi335Ctrl_test
Definition pi335Ctrl.hpp:39
int home_1()
Begin homing (ATZ) axis 1.
int move_3(float absPos)
Send command to device to move axis 3.
std::string m_stage
The stage connected.
Definition pi335Ctrl.hpp:68
int getCom(std::string &resp, const std::string &com, int axis)
virtual void setupConfig()
float m_max3
The maximum value for axis 3.
Definition pi335Ctrl.hpp:83
int recordPI335(bool force=false)
int setCom(const std::string &com, int axis, const std::string &arg)
int homeState(int axis)
Get the status of homing on an axiz.
int releaseDM()
Release the DM, making it safe to turn off power.
int home_3()
Begin homing (ATZ) axis 3.
int updateFlat(float absPos1, float absPos2, float absPos3)
Update the flat command and propagate.
float m_min2
The minimum value for axis 2.
Definition pi335Ctrl.hpp:79
float m_homePos2
Home position of axis 2. Default is 17.5.
Definition pi335Ctrl.hpp:61
dev::telemeter< pi335Ctrl > telemeterT
Definition pi335Ctrl.hpp:51
float m_min1
The minimum value for axis 1.
Definition pi335Ctrl.hpp:76
std::string m_ctrl
The controller connected.
Definition pi335Ctrl.hpp:67
int home_2()
Begin homing (ATZ) axis 2.
pi335Ctrl()
Default c'tor.
int move_1(float absPos)
Send command to device to move axis 1.
float m_min3
The minimum value for axis 3.
Definition pi335Ctrl.hpp:82
float m_homePos3
Home position of axis 2. Default is 17.5.
Definition pi335Ctrl.hpp:62
virtual int appLogic()
Implementation of the FSM for pi335Ctrl.
int zeroDM()
Zero all commands on the DM.
float m_max2
The maximum value for axis 2.
Definition pi335Ctrl.hpp:80
virtual int appStartup()
Startup function.
pcf::IndiProperty m_indiP_pos2
int setCom(const std::string &com, int axis)
dev::dm< pi335Ctrl, float > dmT
Definition pi335Ctrl.hpp:43
pcf::IndiProperty m_indiP_pos1
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int move_2(float absPos)
Send command to device to move axis 2.
#define DM_SETUP_CONFIG(cfig)
Call dmT::setupConfig with error checking for dm.
Definition dm.hpp:2325
#define DM_APP_SHUTDOWN
Call dmT::appShutdown with error checking for dm.
Definition dm.hpp:2365
#define DM_LOAD_CONFIG(cfig)
Call dmT::loadConfig with error checking for dm.
Definition dm.hpp:2337
#define DM_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for dm.
Definition dm.hpp:2344
#define DM_APP_LOGIC
Call dmT::appLogic with error checking for dm.
Definition dm.hpp:2351
#define DM_UPDATE_INDI
Call dmT::updateINDI with error checking for dm.
Definition dm.hpp:2358
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ NOTHOMED
The device has not been homed.
@ HOMING
The device is homing.
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ UNINITIALIZED
The application is unitialized, the default.
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
int ttyWriteRead(std::string &strRead, const std::string &strWrite, const std::string &eot, bool swallowEcho, int fd, int timeoutWrite, int timeoutRead)
Write to a tty on an open file descriptor, then get the result.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition ttyErrors.cpp:15
int ttyWrite(const std::string &buffWrite, int fd, int timeoutWrite)
Write to the tty console indicated by a file descriptor.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_BUSY
Definition indiUtils.hpp:30
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
#define SHMIMMONITOR_APP_SHUTDOWN
Call shmimMonitorT::appShutdown with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_LOGIC
Call shmimMonitorT::appLogic with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for shmimMonitor.
#define SHMIMMONITOR_UPDATE_INDI
Call shmimMonitorT::updateINDI with error checking for shmimMonitor.
An input/output capable device.
Definition ioDevice.hpp:27
unsigned m_writeTimeout
The write timeout [msec].
Definition ioDevice.hpp:29
int loadConfig(mx::app::appConfigurator &config)
Load the device section from an application configurator.
Definition ioDevice.cpp:28
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the device section.
Definition ioDevice.cpp:20
unsigned m_readTimeout
The read timeout [msec].
Definition ioDevice.hpp:28
A device base class which saves telemetry.
Definition telemeter.hpp:69
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording the build-time git state.
A simple text log, a string-type log.
Definition text_log.hpp:24
A USB device as a TTY device.
Definition usbDevice.hpp:33
std::string m_deviceName
The device path name, e.g. /dev/ttyUSB0.
Definition usbDevice.hpp:40
int m_fileDescrip
The file descriptor.
Definition usbDevice.hpp:42
int connect()
Connect to the device.
int getDeviceName()
Get the device name from udev using the vendor, product, and serial number.
std::string m_idProduct
The product id 4-digit code.
Definition usbDevice.hpp:35
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the USB section.
Definition usbDevice.cpp:24
std::string m_serial
The serial number.
Definition usbDevice.hpp:36
int loadConfig(mx::app::appConfigurator &config)
Load the USB section from an application configurator.
Definition usbDevice.cpp:34
speed_t m_baudRate
The baud rate specification.
Definition usbDevice.hpp:38
std::string m_idVendor
The vendor id 4-digit code.
Definition usbDevice.hpp:34
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.
#define TTY_E_NODEVNAMES
Definition ttyErrors.hpp:28
#define TTY_E_DEVNOTFOUND
Definition ttyErrors.hpp:30