API
 
Loading...
Searching...
No Matches
zaberStage.hpp
Go to the documentation of this file.
1/** \file zaberStage.hpp
2 * \brief A class with details of a single zaber stage
3 *
4 * \ingroup zaberLowLevel_files
5 */
6
7#ifndef zaberStage_hpp
8#define zaberStage_hpp
9
10#include <iostream>
11
12#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
13
14#include "za_serial.h"
15
16namespace MagAOX
17{
18namespace app
19{
20
21/// A class to manage the details of one stage in a Zaber system.
22/**
23 * \ingroup zaberLowLevel
24 */
25template <class parentT>
27{
28 protected:
29 parentT *m_parent{ nullptr }; // The parent MagAOXApp
30
31 std::string m_name; ///< The stage's name.
32
33 std::string m_serial; ///< The stage's serial number.
34
35 int m_deviceAddress{ -1 }; ///< The device's address, a.k.a. its order in the chain
36
37 int m_axisNumber{ 0 }; ///< The axis number at the address (normally 0 in MagAO-X)
38
39 bool m_commandStatus{ true }; ///< The status of the last command sent. true = OK, false = RJ (rejected)
40
42 'U' }; ///< Current status. Either 'I' for IDLE or 'B' for BUSY. Intializes to 'U' for UNKOWN.
43
44 bool m_homing{ false };
45
46 timespec m_lastHomed{ 0, 0 }; ///< Time stamp of the last time the stage was homed
47
48 bool m_parked{ false };
49
50 long m_rawPos; ///< The raw position reported by the device, in microsteps.
51
52 long m_tgtPos{ 0 }; ///< The tgt position last sent to the device, in microsteps.
53
54 long m_maxPos; ///< The max position allowed for the device, set by config. Will be set to no larger m_maxPosHW.
55
56 float m_temp{ -999 }; ///< The driver temperature, in C.
57
58 bool m_knobEnabled{ false };
59
60 bool m_ledEnabled{ false };
61
62 bool m_warn{ false };
63
64 bool m_warnFD{ false };
65 bool m_warnFDreported{ false };
66 bool m_warnFQ{ false };
67 bool m_warnFQreported{ false };
68 bool m_warnFS{ false };
69 bool m_warnFSreported{ false };
70 bool m_warnFT{ false };
71 bool m_warnFTreported{ false };
72 bool m_warnFB{ false };
73 bool m_warnFBreported{ false };
74 bool m_warnFP{ false };
75 bool m_warnFPreported{ false };
76 bool m_warnFE{ false };
77 bool m_warnFEreported{ false };
78 bool m_warnWH{ false };
79 bool m_warnWHreported{ false };
80 bool m_warnWL{ false };
81 bool m_warnWLreported{ false };
82 bool m_warnWP{ false };
83 bool m_warnWPreported{ false };
84 bool m_warnWV{ false };
85 bool m_warnWVreported{ false };
86 bool m_warnWT{ false };
87 bool m_warnWTreported{ false };
88 bool m_warnWM{ false };
89 bool m_warnWMreported{ false };
90 bool m_warnWR{ false };
91 bool m_warnWRreported{ false };
92 bool m_warnNC{ false };
93 bool m_warnNCreported{ false };
94 bool m_warnNI{ false };
95 bool m_warnNIreported{ false };
96 bool m_warnND{ false };
97 bool m_warnNDreported{ false };
98 bool m_warnNU{ false };
99 bool m_warnNUreported{ false };
100 bool m_warnNJ{ false };
101 bool m_warnNJreported{ false };
102 bool m_warnUNK{ false };
103
104 public:
105 zaberStage() = delete;
106
107 zaberStage( parentT *parent )
108 {
109 if( parent == nullptr )
110 {
111 throw mx::exception( mx::error_t::invalidarg, "parent was null on construction of zaberState" );
112 }
113
114 m_parent = parent;
115 }
116
117 /// Get the device name
118 /**
119 * \returns the current value of m_name
120 */
121 std::string name();
122
123 /// Set the device name
124 /**
125 * \returns 0 on success
126 * \returns -1 on error
127 */
128 int name( const std::string &n /**< [in] the new device name*/ );
129
130 /// Get the device serial number
131 /**
132 * \returns the current value of m_serial
133 */
134 std::string serial();
135
136 /// Set the device serial
137 /**
138 * \returns 0 on success
139 * \returns -1 on error
140 */
141 int serial( const std::string &s /**< [in] the new device serial*/ );
142
143 /// Get the device address
144 /**
145 * \returns the current value of m_deviceAddress
146 */
148
149 /// Set the device address
150 /**
151 * \returns 0 on success
152 * \returns -1 on error
153 */
154 int deviceAddress( const int &da /**< [in] the new device address*/ );
155
156 /// Get the axis number
157 /**
158 * \returns the current value of m_axisNumber
159 */
161
162 /// Set the axis number
163 /**
164 * \returns 0 on success
165 * \returns -1 on error
166 */
167 int axisNumber( const int &an /**< [in] the new axis number */ );
168
169 /// Get the command status
170 /**
171 * \returns the current value of m_commandStatus
172 */
174
175 /// Get the device status
176 /**
177 * \returns the current value of m_deviceStatus
178 */
180
181 /// Get the homing status
182 /**
183 * \returns the current value of m_homing
184 */
185 bool homing();
186
187 /// Get the time of last homing
188 /**
189 * \returns the current value of m_lastHomed
190 */
191 time_t lastHomed();
192
193 /// Get the parked status
194 /**
195 * \returns the current value of m_parked
196 */
197 int parked();
198
199 /// Get the knob status
200 /**
201 * \returns the current value of m_knobEnabled
202 */
204
205 /// Get the LED status
206 /**
207 * \returns the current value of m_ledEnabled
208 */
210
211 /// Get the current raw position, in counts
212 /**
213 * \returns the current value of m_rawPos
214 */
215 long rawPos();
216
217 /// Get the current tgt position, in counts
218 /**
219 * \returns the current value of m_tgtPos
220 */
221 long tgtPos();
222
223 /// Get the max position, in counts
224 /**
225 * \returns the current value of m_maxPos
226 */
227 long maxPos();
228
229 /// Get the status of the warning flag
230 /**
231 * \returns the current value of m_warn
232 */
233 bool warn();
234
235 /// Get the temperature, in C
236 /**
237 * \returns the current value of m_temp
238 */
239 float temp();
240
241 /// Get the warning state
242 /**
243 * \returns the true if any warning flags are set.
244 */
246
247 bool warnFD();
248 bool warnFQ();
249 bool warnFS();
250 bool warnFT();
251 bool warnFB();
252 bool warnFP();
253 bool warnFE();
254 bool warnWH();
255 bool warnWL();
256 bool warnWP();
257 bool warnWV();
258 bool warnWT();
259 bool warnWM();
260 bool warnWR();
261 bool warnNC();
262 bool warnNI();
263 bool warnND();
264 bool warnNU();
265 bool warnNJ();
266 bool warnUNK();
267
268 /// Get a response from the device, after a command has been sent.
269 /** Parses the standard parts of the response in this stage's fields,
270 * and extracts the response string.
271 *
272 * \returns 0 on success.
273 * \returns -1 on error.
274 */
275 int getResponse( std::string &response, ///< [out] the text response
276 const std::string &repBuff ///< [in] the reply buffer, not decoded.
277 );
278
279 /// Get a response from the device, after a command has been sent.
280 /** Parses the standard parts of the response in this stages fields,
281 * and extracts the response string.
282 *
283 * \overload
284 *
285 * \returns 0 on success.
286 * \returns -1 on error.
287 */
288 int getResponse( std::string &response, ///< [out] the text response component
289 const za_reply &rep ///< [in] the decodedstage reply
290 );
291
292 /// Determine whether a decoded message is the awaited command reply.
293 bool isCommandReply( const za_reply &rep /**< [in] the decoded device message */ );
294
295 /// Send a command and get the response
296 int sendCommand( std::string &response, ///< [out] the response received from the stage
297 z_port port, ///< [in] the port with which to communicate
298 const std::string &command ///< [in] the command to send
299 );
300
301 /// Send a command for which no response is expected
302 int sendCommand( z_port port, /**< [in] the port with which to communicate */
303 const std::string &command /**< [in] the command to send */
304 );
305
306 /// Get a value for this device
307 /** Sends the command specified and converts the response to the specified type.
308 *
309 * The command passed should include `get` if needed.
310 *
311 * \tparam valT is the value type to convert to.
312 */
313 template <typename valT>
314 int getValue( valT &val, /**< [out] the value to update */
315 z_port port, /**< [in] the port with which to communicate */
316 const std::string command /**< [in] the command to send */
317 );
318
319 /// Get the maximum position from the stage
320 int getMaxPos( z_port port /**< [in] the port with which to communicate */ );
321
322 /// Get the parked state from the stage
323 int getParked( z_port port /**< [in] the port with which to communicate */ );
324
325 int getKnob( z_port port /**< [in] the port with which to communicate */ );
326
327 int getLED( z_port port /**< [in] the port with which to communicate */ );
328
329 /// Update the position of the stage
330 int updatePos( z_port port /**< [in] the port with which to communicate */ );
331
332 /// Update the stage temperature
333 int updateTemp( z_port port /**< [in] the port with which to communicate */ );
334
335 /// Enable/Disable the knob
336 int enableKnob( z_port port, bool enable );
337
338 // Enable/disable LED
339 int enableLED( z_port port, bool enable );
340
341 /// Stop the stage
342 int stop( z_port port );
343
344 /// Emergency stop the stage
345 int estop( z_port port );
346
347 /// Initiate homing
348 int home( z_port port /**< [in] the port with which to communicate */ );
349
350 /// Park the stage
351 int park( z_port port /**< [in] the port with which to communicate */ );
352
353 /// Unpark the stage
354 int unpark( z_port port /**< [in] the port with which to communicate */ );
355
356 /// Move to a new absolute position
357 int moveAbs( z_port port, ///< [in] the port with which to communicate
358 long rawPos ///< [in] the position to move to, in counts
359 );
360
361 /// Sets all warning flags to false
362 /** This is not the same as clearing warnings on the device, this is just used for
363 * bookkeeping.
364 *
365 * \returns 0 on success (always)
366 */
368
369 /// Process a single warning from the device, setting the appropriate flag.
370 /** Warnings are two ASCII characeters, e.g. "WR".
371 *
372 * \returns 0 if the warning is processed, including if it's not recognized.
373 * \returns -1 on an error, currently not possible.
374 */
375 int processWarning( std::string &warn /**< [in] the two-character warning flag */ );
376
377 /// Parse the warning response from the device.
378 /** Sends each warning flag to processWarning.
379 *
380 * \returns 0 on success
381 * \returns -1 on error
382 */
383 int parseWarnings( std::string &response /**< [in] the response from the warnings query*/ );
384
385 /// Get warnings from the device
386 /** Log entries will be made and flags will be set in this structure.
387 *
388 * \returns 0 on success
389 * \returns -1 on error.
390 */
391 int getWarnings( z_port port /**< [in] the port with which to communicate */ );
392
393 /// Clear all state so that when the system is powered back on we get the correct new state.
395
396 int writeStateFile( std::ofstream &fout /**< [in] an open ofstream to write to */ );
397
398 int readStateFile( std::ifstream &fin /**< [in] an open ofstream to write to */ );
399};
400
401template <class parentT>
403{
404 return m_name;
405}
406
407template <class parentT>
408int zaberStage<parentT>::name( const std::string &n )
409{
410 m_name = n;
411 return 0;
412}
413
414template <class parentT>
416{
417 return m_serial;
418}
419
420template <class parentT>
421int zaberStage<parentT>::serial( const std::string &s )
422{
423 m_serial = s;
424 return 0;
425}
426
427template <class parentT>
429{
430 return m_deviceAddress;
431}
432
433template <class parentT>
435{
436 m_deviceAddress = da;
437 return 0;
438}
439
440template <class parentT>
442{
443 return m_axisNumber;
444}
445
446template <class parentT>
448{
449 m_axisNumber = an;
450 return 0;
451}
452
453template <class parentT>
455{
456 return m_commandStatus;
457}
458
459template <class parentT>
461{
462 return m_deviceStatus;
463}
464
465template <class parentT>
467{
468 return m_homing;
469}
470
471template <class parentT>
473{
474 return m_lastHomed.tv_sec;
475}
476
477template <class parentT>
479{
480 return m_parked;
481}
482
483template <class parentT>
485{
486 return m_knobEnabled;
487}
488
489template <class parentT>
491{
492 return m_ledEnabled;
493}
494
495template <class parentT>
497{
498 return m_rawPos;
499}
500
501template <class parentT>
503{
504 return m_tgtPos;
505}
506
507template <class parentT>
509{
510 return m_maxPos;
511}
512
513template <class parentT>
515{
516 return m_warn;
517}
518
519template <class parentT>
521{
522 return m_temp;
523}
524
525template <class parentT>
527{
528 return m_warn;
529}
530
531template <class parentT>
533{
534 return m_warnFD;
535}
536
537template <class parentT>
539{
540 return m_warnFQ;
541}
542
543template <class parentT>
545{
546 return m_warnFS;
547}
548
549template <class parentT>
551{
552 return m_warnFT;
553}
554
555template <class parentT>
557{
558 return m_warnFB;
559}
560
561template <class parentT>
563{
564 return m_warnFP;
565}
566
567template <class parentT>
569{
570 return m_warnFE;
571}
572
573template <class parentT>
575{
576 return m_warnWH;
577}
578
579template <class parentT>
581{
582 return m_warnWL;
583}
584
585template <class parentT>
587{
588 return m_warnWP;
589}
590
591template <class parentT>
593{
594 return m_warnWV;
595}
596
597template <class parentT>
599{
600 return m_warnWT;
601}
602
603template <class parentT>
605{
606 return m_warnWM;
607}
608
609template <class parentT>
611{
612 return m_warnWR;
613}
614
615template <class parentT>
617{
618 return m_warnNC;
619}
620
621template <class parentT>
623{
624 return m_warnNI;
625}
626
627template <class parentT>
629{
630 return m_warnND;
631}
632
633template <class parentT>
635{
636 return m_warnNU;
637}
638
639template <class parentT>
641{
642 return m_warnNJ;
643}
644
645template <class parentT>
647{
648 return m_warnUNK;
649}
650
651template <class parentT>
652int zaberStage<parentT>::getResponse( std::string &response, const std::string &repBuff )
653{
654 za_reply rep;
655 int rv = za_decode( &rep, repBuff.c_str(), repBuff.size() );
656 if( rv != Z_SUCCESS )
657 {
658 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
659 {
660 return rv; // don't log, but propagate error
661 }
662
663 MagAOXAppT::log<software_error>( { rv, "za_decode !=Z_SUCCESS" } );
664 return rv;
665 }
666
667 return getResponse( response, rep );
668}
669
670template <class parentT>
671int zaberStage<parentT>::getResponse( std::string &response, const za_reply &rep )
672{
673 if( rep.device_address == m_deviceAddress )
674 {
675 if( rep.reply_flags[0] == 'O' )
676 {
677 m_commandStatus = true;
678 }
679 else
680 {
681 m_commandStatus = false;
682 }
683
684 m_deviceStatus = rep.device_status[0];
685
686 if( m_deviceStatus == 'I' && m_homing )
687 {
688 m_warnWR = false; // Clear preemptively
689 m_homing = false;
690 if( clock_gettime( CLOCK_ISIO, &m_lastHomed ) < 0 )
691 {
692 MagAOXAppT::log<software_error>( { errno, 0, "clock_gettime for last homed" } );
693 }
694 }
695
696 if( rep.warning_flags[0] == '-' )
697 {
698 unsetWarnings();
699 }
700 else
701 {
702 m_warn = true;
703 }
704
705 response = rep.response_data;
706
707 return 0;
708 }
709 else
710 {
711 MagAOXAppT::log<software_error>( "wrong device" );
712 return -1;
713 }
714}
715
716template <class parentT>
718{
719 return rep.message_type == '@' && rep.device_address == m_deviceAddress;
720}
721
722template <class parentT>
723int zaberStage<parentT>::sendCommand( std::string &response, z_port port, const std::string &command )
724{
725 if( port <= 0 )
726 {
727 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
728 {
729 return -1; // don't log, but propagate error
730 }
731
732 MagAOXAppT::log<software_error>( { 0, "invalid zaber port" } );
733 response = "";
734 return -1;
735 }
736
737 int rv = za_send( port, command.c_str(), command.size() );
738
739 if( rv < 0 )
740 {
741 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
742 {
743 return rv; // don't log, but propagate error
744 }
745
746 MagAOXAppT::log<software_error>( { rv, "za_send !=Z_SUCCESS" } );
747 response = "";
748 return -1;
749 }
750
751 char buff[256];
752
753 while( 1 )
754 {
755 rv = za_receive( port, buff, sizeof( buff ) );
756
757 if( rv == Z_ERROR_TIMEOUT )
758 {
759 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
760 {
761 return rv; // don't log, but propagate error
762 }
763
764 MagAOXAppT::log<software_error>( "Z_ERROR_TIMEOUT" );
765 break; // assume error and just get out.
766 }
767 else if( rv < 0 )
768 {
769 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
770 {
771 return rv; // don't log, but propagate error
772 }
773
774 MagAOXAppT::log<software_error>( { 0, "za_receive !=Z_SUCCESS" } );
775 break;
776 }
777 za_reply rep;
778
779 rv = za_decode( &rep, buff, static_cast<size_t>( rv ) );
780 if( rv != Z_SUCCESS )
781 {
782 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
783 {
784 return rv; // don't log, but propagate error
785 }
786
787 MagAOXAppT::log<software_error>( "za_decode !=Z_SUCCESS" );
788 break;
789 }
790
791 if( isCommandReply( rep ) )
792 return getResponse( response, rep );
793 }
794
795 response = "";
796
797 return -1;
798}
799
800template <class parentT>
801template <typename valT>
802int zaberStage<parentT>::getValue( valT &val, z_port port, const std::string command )
803{
804 if( m_deviceAddress < 1 )
805 {
807 { std::format( "stage {} with s/n {} not found in system.", m_name, m_serial ) } );
808 }
809
810 std::string response;
811
812 int rv = sendCommand( response, port, std::format( "/{} {}", m_deviceAddress, command ) );
813
814 if( rv == 0 )
815 {
816 if( m_commandStatus )
817 {
818 mx::error_t errc;
819
820 val = mx::ioutils::stoT<valT>( response, &errc );
821
822 if( !!errc )
823 {
825 std::format( "parsing [{}] response from {}: {}", command, m_name, mx::errorMessage( errc ) ) );
826 }
827
828 return 0;
829 }
830 else
831 {
832 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
833 {
834 return -1; // don't log, but propagate error
835 }
836
837 MagAOXAppT::log<software_error>( { rv, command + "command Rejected" } );
838 return -1;
839 }
840 }
841 else
842 {
843 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
844 {
845 return -1; // don't log, but propagate error
846 }
847
849
850 return -1;
851 }
852}
853
854template <class parentT>
856{
857 int rv = getValue( m_maxPos, port, "get limit.max" );
858
859 if( rv < 0 )
860 {
861 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
862 {
863 return -1; // don't log, but propagate error
864 }
865
866 return MagAOXAppT::log<software_error, -1>();
867 }
868
869 return 0;
870}
871
872template <class parentT>
874{
875 int rv = getValue( m_parked, port, "tools parking state" );
876
877 if( rv < 0 )
878 {
879 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
880 {
881 return -1; // don't log, but propagate error
882 }
883
884 return MagAOXAppT::log<software_error, -1>();
885 }
886
887 return 0;
888}
889
890template <class parentT>
892{
893 int rv = getValue( m_knobEnabled, port, "get knob.enable" );
894
895 if( rv < 0 )
896 {
897 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
898 {
899 return -1; // don't log, but propagate error
900 }
901
902 return MagAOXAppT::log<software_error, -1>();
903 }
904
905 return 0;
906}
907
908template <class parentT>
910{
911 int rv = getValue( m_ledEnabled, port, "get system.led.enable" );
912
913 if( rv < 0 )
914 {
915 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
916 {
917 return -1; // don't log, but propagate error
918 }
919
920 return MagAOXAppT::log<software_error, -1>();
921 }
922
923 return 0;
924}
925
926template <class parentT>
928{
929 int rv = getValue( m_rawPos, port, "get pos" );
930
931 if( rv < 0 )
932 {
933 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
934 {
935 return -1; // don't log, but propagate error
936 }
937
938 return MagAOXAppT::log<software_error, -1>();
939 }
940
941 return 0;
942}
943
944template <class parentT>
946{
947 int rv = getValue( m_temp, port, "get driver.temperature" );
948
949 if( rv < 0 )
950 {
951 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
952 {
953 return -1; // don't log, but propagate error
954 }
955
956 return MagAOXAppT::log<software_error, -1>();
957 }
958
959 return 0;
960}
961
962template <class parentT>
963int zaberStage<parentT>::sendCommand( z_port port, const std::string &command )
964{
965 if( m_deviceAddress < 1 )
966 {
968 std::format( "stage {} with s/n {} not found in system.", m_name, m_serial ) );
969 }
970
971 std::string response;
972
973 int rv = sendCommand( response, port, std::format( "/{} {}", m_deviceAddress, command ) );
974
975 if( rv == 0 )
976 {
977 if( m_commandStatus )
978 {
979 return 0;
980 }
981 else
982 {
983 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
984 {
985 return -1; // don't log, but propagate error
986 }
987
989 { rv, std::format( "{} {} commmand rejected", m_name, command ) } );
990 }
991 }
992 else
993 {
994 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
995 {
996 return -1; // don't log, but propagate error
997 }
998
1000 return -1;
1001 }
1002}
1003
1004template <class parentT>
1005int zaberStage<parentT>::enableKnob( z_port port, bool enable )
1006{
1007 std::string cmd = std::format( "set knob.enable {}", enable ? "1" : "0" );
1008
1009 int rv = sendCommand( port, cmd );
1010
1011 if( rv < 0 )
1012 {
1013 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1014 {
1015 return -1; // don't log, but propagate error
1016 }
1017
1018 return MagAOXAppT::log<software_error, -1>();
1019 }
1020
1021 return 0;
1022}
1023
1024template <class parentT>
1025int zaberStage<parentT>::enableLED( z_port port, bool enable )
1026{
1027 std::string cmd = std::format( "set system.led.enable {}", enable ? "1" : "0" );
1028
1029 int rv = sendCommand( port, cmd );
1030
1031 if( rv < 0 )
1032 {
1033 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1034 {
1035 return -1; // don't log, but propagate error
1036 }
1037
1038 return MagAOXAppT::log<software_error, -1>();
1039 }
1040
1041 return 0;
1042}
1043
1044template <class parentT>
1046{
1047 int rv = sendCommand( port, "stop" );
1048
1049 if( rv < 0 )
1050 {
1051 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1052 {
1053 return -1; // don't log, but propagate error
1054 }
1055
1056 return MagAOXAppT::log<software_error, -1>();
1057 }
1058
1059 return 0;
1060}
1061
1062template <class parentT>
1064{
1065 int rv = sendCommand( port, "estop" );
1066
1067 if( rv < 0 )
1068 {
1069 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1070 {
1071 return -1; // don't log, but propagate error
1072 }
1073
1074 return MagAOXAppT::log<software_error, -1>();
1075 }
1076
1077 return 0;
1078}
1079
1080template <class parentT>
1082{
1083 int rv = sendCommand( port, "home" );
1084
1085 if( rv < 0 )
1086 {
1087 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1088 {
1089 return -1; // don't log, but propagate error
1090 }
1091
1092 return MagAOXAppT::log<software_error, -1>();
1093 }
1094
1095 m_homing = true;
1096 m_tgtPos = 0;
1097 return 0;
1098}
1099
1100template <class parentT>
1102{
1103 int rv = sendCommand( port, "tools parking park" );
1104
1105 if( rv < 0 )
1106 {
1107 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1108 {
1109 return -1; // don't log, but propagate error
1110 }
1111
1112 return MagAOXAppT::log<software_error, -1>();
1113 }
1114
1115 m_parked = true;
1116
1117 return 0;
1118}
1119
1120template <class parentT>
1122{
1123 int rv = sendCommand( port, "tools parking unpark" );
1124
1125 if( rv < 0 )
1126 {
1127 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1128 {
1129 return -1; // don't log, but propagate error
1130 }
1131
1132 return MagAOXAppT::log<software_error, -1>();
1133 }
1134
1135 m_parked = false;
1136 return 0;
1137}
1138
1139template <class parentT>
1140int zaberStage<parentT>::moveAbs( z_port port, long rawPos )
1141{
1142 m_tgtPos = rawPos;
1143
1144 if( m_parked )
1145 {
1146 if( unpark( port ) < 0 )
1147 {
1148 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1149 {
1150 return -1; // don't log, but propagate error
1151 }
1152
1153 return MagAOXAppT::log<software_error, -1>();
1154 }
1155 }
1156
1157 int rv = sendCommand( port, std::format( "move abs {}", rawPos ) );
1158
1159 if( rv < 0 )
1160 {
1161 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1162 {
1163 return -1; // don't log, but propagate error
1164 }
1165
1166 return MagAOXAppT::log<software_error, -1>();
1167 }
1168
1169 return 0;
1170}
1171
1172template <class parentT>
1174{
1175 m_warn = false;
1176
1177 m_warnFD = false;
1178 m_warnFQ = false;
1179 m_warnFS = false;
1180 m_warnFT = false;
1181 m_warnFB = false;
1182 m_warnFP = false;
1183 m_warnFE = false;
1184 m_warnWH = false;
1185 m_warnWL = false;
1186 m_warnWP = false;
1187 m_warnWV = false;
1188 m_warnWT = false;
1189 m_warnWM = false;
1190 m_warnWR = false;
1191 m_warnNC = false;
1192 m_warnNI = false;
1193 m_warnND = false;
1194 m_warnNU = false;
1195 m_warnNJ = false;
1196 m_warnUNK = false;
1197
1198 return 0;
1199}
1200
1201template <class parentT>
1203{
1204 if( warn == "FD" )
1205 {
1206 if( !m_warnFDreported )
1207 {
1209 " Driver Disabled (FD): The driver has disabled itself due to overheating.",
1211 m_warnFDreported = true;
1212 }
1213
1214 m_warnFD = true;
1215 return 0;
1216 }
1217 else if( warn == "FQ" )
1218 {
1219 if( !m_warnFQreported )
1220 {
1221 MagAOXAppT::log<text_log>( m_name + " warning FQ: you should probably check.", logPrio::LOG_EMERGENCY );
1222 m_warnFQreported = true;
1223 }
1224
1225 m_warnFQ = true;
1226 return 0;
1227 }
1228 else if( warn == "FS" )
1229 {
1230 if( !m_warnFSreported )
1231 {
1233 m_name + " Stalled and Stopped (FS): Stalling was detected and the axis has stopped itself. ",
1235 m_warnFSreported = true;
1236 }
1237 m_warnFS = true;
1238 return 0;
1239 }
1240 else if( warn == "FT" )
1241 {
1242 if( !m_warnFTreported )
1243 {
1245 m_name + " Excessive Twist (FT): The lockstep group has exceeded allowable twist and has stopped. ",
1247 m_warnFTreported = true;
1248 }
1249
1250 m_warnFT = true;
1251 return 0;
1252 }
1253 else if( warn == "FB" )
1254 {
1255 if( !m_warnFBreported )
1256 {
1257 MagAOXAppT::log<text_log>( m_name + " Stream Bounds Error (FB): A previous streamed motion could not be "
1258 "executed because it failed a precondition",
1260 m_warnFBreported = true;
1261 }
1262
1263 m_warnFB = true;
1264 return 0;
1265 }
1266 else if( warn == "FP" )
1267 {
1268 if( !m_warnFPreported )
1269 {
1271 m_name + " Interpolated Path Deviation (FP): Streamed or sinusoidal motion was terminated because an "
1272 "axis slipped and thus the device deviated from the requested path. ",
1274 m_warnFPreported = true;
1275 }
1276
1277 m_warnFP = true;
1278 return 0;
1279 }
1280 else if( warn == "FE" )
1281 {
1282 if( !m_warnFEreported )
1283 {
1285 m_name + " Limit Error (FE): The target limit sensor cannot be reached or is faulty. ",
1287 m_warnFEreported = true;
1288 }
1289
1290 m_warnFE = true;
1291 return 0;
1292 }
1293 else if( warn == "WH" )
1294 {
1295 if( m_warnWHreported == false )
1296 {
1298 m_name + " Device not homed (WH): The device has a position reference, but has not been homed.",
1300 m_warnWHreported = true;
1301 }
1302
1303 m_warnWH = true;
1304 return 0;
1305 }
1306 else if( warn == "WL" )
1307 {
1308 if( !m_warnWLreported )
1309 {
1310 MagAOXAppT::log<text_log>( m_name + " Unexpected Limit Trigger warning (WL): A movement operation did not "
1311 "complete due to a triggered limit sensor.",
1313 m_warnWLreported = true;
1314 }
1315
1316 m_warnWL = true;
1317 return 0;
1318 }
1319 else if( warn == "WP" )
1320 {
1321 if( !m_warnWPreported )
1322 {
1324 m_name + " Invalid calibration type (WP): The saved calibration data type is unsupported",
1326 m_warnWPreported = true;
1327 }
1328
1329 m_warnWP = true;
1330 return 0;
1331 }
1332 else if( warn == "WV" )
1333 {
1334 if( !m_warnWVreported )
1335 {
1336 MagAOXAppT::log<text_log>( m_name + " Voltage Out of Range (WV): The supply voltage is outside the "
1337 "recommended operating range of the device",
1339 m_warnWVreported = true;
1340 }
1341
1342 m_warnWV = true;
1343 return 0;
1344 }
1345 else if( warn == "WT" )
1346 {
1347 if( !m_warnWTreported )
1348 {
1349 MagAOXAppT::log<text_log>( m_name + " Controller Temperature High (WT): The internal temperature of the "
1350 "controller has exceeded the recommended limit for the device.",
1352 m_warnWTreported = true;
1353 }
1354
1355 m_warnWT = true;
1356 return 0;
1357 }
1358 else if( warn == "WM" )
1359 {
1360 if( m_warnWMreported == false )
1361 {
1362 MagAOXAppT::log<text_log>( m_name + " Displaced when Stationary (WM): While not in motion, the axis has "
1363 "been forced out of its position.",
1365 m_warnWMreported = true;
1366 }
1367
1368 m_warnWM = true;
1369 return 0;
1370 }
1371 else if( warn == "WR" )
1372 {
1373 if( m_warnWRreported == false )
1374 {
1376 m_name +
1377 " No Reference Position (WR): Axis has not had a reference position established. [homing required]",
1379 m_warnWRreported = true;
1380 }
1381
1382 m_warnWR = true;
1383 return 0;
1384 }
1385 else if( warn == "NC" )
1386 {
1387 if( !m_warnNCreported )
1388 {
1390 " Manual Control (NC): Axis is busy due to manual control via the knob.",
1392 m_warnNCreported = true;
1393 }
1394
1395 m_warnNC = true;
1396 return 0;
1397 }
1398 else if( warn == "NI" )
1399 {
1400 if( m_homing == true || warnWR() )
1401 {
1402 return 0; // ignore this during homing
1403 }
1404
1405 if( !m_warnNIreported )
1406 {
1407 MagAOXAppT::log<text_log>( m_name + " Command Interrupted (NI): A movement operation "
1408 "(command or manual control) was requested "
1409 "while the axis was executing another movement command.",
1411 m_warnNIreported = true;
1412 }
1413
1414 m_warnNI = true;
1415 return 0;
1416 }
1417 else if( warn == "ND" )
1418 {
1419 if( !m_warnNDreported )
1420 {
1421 MagAOXAppT::log<text_log>( m_name + " Stream Discontinuity (ND): The device has slowed down while "
1422 "following a "
1423 "streamed motion path because it has run out of queued motions.",
1425 m_warnNDreported = true;
1426 }
1427
1428 m_warnND = true;
1429 return 0;
1430 }
1431 else if( warn == "NU" )
1432 {
1433 if( !m_warnNUreported )
1434 {
1435 MagAOXAppT::log<text_log>( m_name + " Setting Update Pending (NU): A setting is pending to be "
1436 "updated or a reset is pending.",
1438 m_warnNUreported = true;
1439 }
1440
1441 m_warnNU = true;
1442 return 0;
1443 }
1444 else if( warn == "NJ" )
1445 {
1446 if( !m_warnNJreported )
1447 {
1448 MagAOXAppT::log<text_log>( m_name + " Joystick Calibrating (NJ): Joystick calibration is "
1449 "in progress.",
1451 m_warnNJreported = true;
1452 }
1453
1454 m_warnNJ = true;
1455 return 0;
1456 }
1457 else
1458 {
1459 MagAOXAppT::log<software_warning>( std::format( "{} unknown stage warning: {}", m_name, warn ) );
1460
1461 m_warnUNK = true;
1462
1463 return 0;
1464 }
1465
1466 return -1;
1467}
1468
1469template <class parentT>
1470int zaberStage<parentT>::parseWarnings( std::string &response )
1471{
1472
1473 size_t nwarn;
1474
1475 try
1476 {
1477 nwarn = std::stoi( response.substr( 0, 2 ) );
1478 }
1479 catch( ... )
1480 {
1481 return MagAOXAppT::log<software_error, -1>( { "exception while parsing warning" } );
1482 }
1483
1484 if( nwarn > 0 )
1485 {
1486 m_warn = true;
1487 }
1488
1489 for( size_t n = 0; n < nwarn; ++n )
1490 {
1491 if( response.size() < 5 + n * 3 )
1492 {
1493 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1494 {
1495 return -1; // don't log, but propagate error
1496 }
1497
1498 return MagAOXAppT::log<software_error, -1>( { "parsing incomplete warning response" } );
1499 }
1500
1501 std::string warn = response.substr( 3 + n * 3, 2 );
1502
1503 int rv = processWarning( warn );
1504 if( rv < 0 )
1505 {
1506 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1507 {
1508 return -1; // don't log, but propagate error
1509 }
1510
1512 return -1;
1513 }
1514 }
1515
1516 if( m_warnFDreported )
1517 {
1518 if( !m_warnFD )
1519 {
1520 m_warnFDreported = false;
1521 }
1522 }
1523
1524 if( m_warnFQreported )
1525 {
1526 if( !m_warnFQ )
1527 {
1528 m_warnFQreported = false;
1529 }
1530 }
1531
1532 if( m_warnFSreported )
1533 {
1534 if( !m_warnFS )
1535 {
1536 m_warnFSreported = false;
1537 }
1538 }
1539
1540 if( m_warnFTreported )
1541 {
1542 if( !m_warnFT )
1543 {
1544 m_warnFTreported = false;
1545 }
1546 }
1547
1548 if( m_warnFBreported )
1549 {
1550 if( !m_warnFB )
1551 {
1552 m_warnFBreported = false;
1553 }
1554 }
1555
1556 if( m_warnFPreported )
1557 {
1558 if( !m_warnFP )
1559 {
1560 m_warnFPreported = false;
1561 }
1562 }
1563
1564 if( m_warnFEreported )
1565 {
1566 if( !m_warnFE )
1567 {
1568 m_warnFEreported = false;
1569 }
1570 }
1571
1572 if( m_warnWHreported )
1573 {
1574 if( !m_warnWH )
1575 {
1576 m_warnWHreported = false;
1577 }
1578 }
1579
1580 if( m_warnWLreported )
1581 {
1582 if( !m_warnWL )
1583 {
1584 m_warnWLreported = false;
1585 }
1586 }
1587
1588 if( m_warnWPreported )
1589 {
1590 if( !m_warnWP )
1591 {
1592 m_warnWPreported = false;
1593 }
1594 }
1595
1596 if( m_warnWVreported )
1597 {
1598 if( !m_warnWV )
1599 {
1600 m_warnWVreported = false;
1601 }
1602 }
1603
1604 if( m_warnWTreported )
1605 {
1606 if( !m_warnWT )
1607 {
1608 m_warnWTreported = false;
1609 }
1610 }
1611
1612 if( m_warnWMreported )
1613 {
1614 if( !m_warnWM )
1615 {
1616 m_warnWMreported = false;
1617 }
1618 }
1619
1620 if( m_warnWRreported )
1621 {
1622 if( !m_warnWR )
1623 {
1624 m_warnWRreported = false;
1625 }
1626 }
1627
1628 if( m_warnNCreported )
1629 {
1630 if( !m_warnNC )
1631 {
1632 m_warnNCreported = false;
1633 }
1634 }
1635
1636 if( m_warnNIreported )
1637 {
1638 if( !m_warnNI )
1639 {
1640 m_warnNIreported = false;
1641 }
1642 }
1643
1644 if( m_warnNDreported )
1645 {
1646 if( !m_warnND )
1647 {
1648 m_warnNDreported = false;
1649 }
1650 }
1651
1652 if( m_warnNUreported )
1653 {
1654 if( !m_warnNU )
1655 {
1656 m_warnNUreported = false;
1657 }
1658 }
1659
1660 if( m_warnNJreported )
1661 {
1662 if( !m_warnNJ )
1663 {
1664 m_warnNJreported = false;
1665 }
1666 }
1667
1668 return 0;
1669}
1670
1671template <class parentT>
1673{
1674 if( m_deviceAddress < 1 )
1675 {
1676 return MagAOXAppT::log<software_error, -1>(
1677 { "stage " + m_name + " with with s/n " + m_serial + " not found in system." } );
1678 }
1679
1680 std::string response;
1681
1682 int rv = sendCommand( response, port, std::format( "/{} warnings", m_deviceAddress ) );
1683
1684 if( rv == 0 )
1685 {
1686 if( m_commandStatus )
1687 {
1688 unsetWarnings(); // Clear all the flags before setting them to stay current.
1689 return parseWarnings( response );
1690 }
1691 else
1692 {
1693 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1694 {
1695 return -1; // don't log, but propagate error
1696 }
1697
1698 MagAOXAppT::log<software_error>( { rv, "warnings Command Rejected" } );
1699 return -1;
1700 }
1701 }
1702 else
1703 {
1704 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1705 {
1706 return -1; // don't log, but propagate error
1707 }
1708
1710 return -1;
1711 }
1712}
1713
1714template <class parentT>
1716{
1717 m_commandStatus = true; ///< The status of the last command sent. true = OK, false = RJ (rejected)
1718
1719 m_deviceStatus = 'U'; ///< Current status. Either 'I' for IDLE or 'B' for BUSY. Intializes to 'U' for UNKOWN.
1720
1721 m_homing = false;
1722
1723 // We don't 0 rawPos so it is retained
1724
1725 m_temp = -999; ///< The driver temperature, in C.
1726
1727 unsetWarnings();
1728 m_warnWRreported = false;
1729
1730 return 0;
1731}
1732
1733template <class parentT>
1734int zaberStage<parentT>::writeStateFile( std::ofstream &fout )
1735{
1736 fout << m_rawPos << '\n';
1737
1738 if( !fout )
1739 {
1740 return MagAOXAppT::log<software_error, -1>( { "error writing raw position" } );
1741 }
1742
1743 fout << m_parked << '\n';
1744
1745 if( !fout )
1746 {
1747 return MagAOXAppT::log<software_error, -1>( { "error writing parked state" } );
1748 }
1749
1750 fout << m_maxPos << '\n';
1751
1752 if( !fout )
1753 {
1754 return MagAOXAppT::log<software_error, -1>( { "error writing max position" } );
1755 }
1756
1757 fout << m_lastHomed.tv_sec << '\n';
1758
1759 if( !fout )
1760 {
1761 return MagAOXAppT::log<software_error, -1>( { "error writing last home time" } );
1762 }
1763
1764 return 0;
1765}
1766
1767template <class parentT>
1768int zaberStage<parentT>::readStateFile( std::ifstream &fin )
1769{
1770 long rawPos;
1771 bool parked;
1772 long maxPos;
1773 time_t lastHomed;
1774
1775 fin >> rawPos;
1776
1777 if( !fin )
1778 {
1779 return MagAOXAppT::log<software_error, -1>( { "error reading raw position" } );
1780 }
1781
1782 fin >> parked;
1783
1784 if( !fin )
1785 {
1786 return MagAOXAppT::log<software_error, -1>( { "error reading parked state" } );
1787 }
1788
1789 fin >> maxPos;
1790
1791 if( !fin )
1792 {
1793 return MagAOXAppT::log<software_error, -1>( { "error reading max position" } );
1794 }
1795
1796 fin >> lastHomed;
1797
1798 if( !fin )
1799 {
1800 return MagAOXAppT::log<software_error, -1>( { "error reading last home time" } );
1801 }
1802
1803 m_rawPos = rawPos;
1804 m_tgtPos = rawPos;
1805 m_parked = parked;
1806 m_maxPos = maxPos;
1807 m_lastHomed.tv_sec = lastHomed;
1808 m_lastHomed.tv_nsec = 0;
1809
1810 return 0;
1811}
1812
1813} // namespace app
1814} // namespace MagAOX
1815
1816#endif // zaberStage_hpp
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
A class to manage the details of one stage in a Zaber system.
long m_maxPos
The max position allowed for the device, set by config. Will be set to no larger m_maxPosHW.
int unpark(z_port port)
Unpark the stage.
int getMaxPos(z_port port)
Get the maximum position from the stage.
int serial(const std::string &s)
Set the device serial.
char deviceStatus()
Get the device status.
bool isCommandReply(const za_reply &rep)
Determine whether a decoded message is the awaited command reply.
int axisNumber(const int &an)
Set the axis number.
int getWarnings(z_port port)
Get warnings from the device.
float m_temp
The driver temperature, in C.
long rawPos()
Get the current raw position, in counts.
int processWarning(std::string &warn)
Process a single warning from the device, setting the appropriate flag.
int readStateFile(std::ifstream &fin)
bool warn()
Get the status of the warning flag.
std::string name()
Get the device name.
int home(z_port port)
Initiate homing.
time_t lastHomed()
Get the time of last homing.
int writeStateFile(std::ofstream &fout)
int getParked(z_port port)
Get the parked state from the stage.
int getKnob(z_port port)
int stop(z_port port)
Stop the stage.
int sendCommand(z_port port, const std::string &command)
Send a command for which no response is expected.
bool ledEnabled()
Get the LED status.
int enableKnob(z_port port, bool enable)
Enable/Disable the knob.
bool m_commandStatus
The status of the last command sent. true = OK, false = RJ (rejected)
long maxPos()
Get the max position, in counts.
bool homing()
Get the homing status.
long tgtPos()
Get the current tgt position, in counts.
int sendCommand(std::string &response, z_port port, const std::string &command)
Send a command and get the response.
int m_axisNumber
The axis number at the address (normally 0 in MagAO-X)
int deviceAddress(const int &da)
Set the device address.
int onPowerOff()
Clear all state so that when the system is powered back on we get the correct new state.
int moveAbs(z_port port, long rawPos)
Move to a new absolute position.
int axisNumber()
Get the axis number.
zaberStage(parentT *parent)
long m_rawPos
The raw position reported by the device, in microsteps.
int updatePos(z_port port)
Update the position of the stage.
timespec m_lastHomed
Time stamp of the last time the stage was homed.
int parseWarnings(std::string &response)
Parse the warning response from the device.
std::string serial()
Get the device serial number.
bool commandStatus()
Get the command status.
int parked()
Get the parked status.
long m_tgtPos
The tgt position last sent to the device, in microsteps.
int estop(z_port port)
Emergency stop the stage.
std::string m_serial
The stage's serial number.
int enableLED(z_port port, bool enable)
int updateTemp(z_port port)
Update the stage temperature.
int park(z_port port)
Park the stage.
int name(const std::string &n)
Set the device name.
int getLED(z_port port)
bool knobEnabled()
Get the knob status.
int deviceAddress()
Get the device address.
int getResponse(std::string &response, const za_reply &rep)
Get a response from the device, after a command has been sent.
int m_deviceAddress
The device's address, a.k.a. its order in the chain.
char m_deviceStatus
Current status. Either 'I' for IDLE or 'B' for BUSY. Intializes to 'U' for UNKOWN.
float temp()
Get the temperature, in C.
int getResponse(std::string &response, const std::string &repBuff)
Get a response from the device, after a command has been sent.
int getValue(valT &val, z_port port, const std::string command)
Get a value for this device.
std::string m_name
The stage's name.
bool warningState()
Get the warning state.
int unsetWarnings()
Sets all warning flags to false.
Definition dm.hpp:19
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_EMERGENCY
Normal operations of the entire system should be shut down immediately.
Software ERR log entry.
int za_receive(z_port port, char *destination, int length)
Definition za_serial.c:151
int za_decode(struct za_reply *destination, const char *reply, size_t sMaxSz)
Definition za_serial.c:539
int za_send(z_port port, const char *command, size_t sMaxSz)
Definition za_serial.c:112
Provides a set of functions for interacting with Zaber devices in the ASCII protocol.
char device_status[5]
Definition za_serial.h:44
char message_type
Definition za_serial.h:35
int device_address
Definition za_serial.h:37
char reply_flags[3]
Definition za_serial.h:42
char warning_flags[3]
Definition za_serial.h:47
char response_data[128]
Definition za_serial.h:50
@ Z_SUCCESS
Definition z_common.h:65
@ Z_ERROR_TIMEOUT
Definition z_common.h:78