API
 
Loading...
Searching...
No Matches
zaberBinaryStage.hpp
Go to the documentation of this file.
1/** \file zaberBinaryStage.hpp
2 * \brief A class with details of a single binary-protocol Zaber stage.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup zaberLowLevelBinary_files
6 */
7
8#ifndef zaberBinaryStage_hpp
9#define zaberBinaryStage_hpp
10
11#include <ctime>
12#include <fstream>
13#include <limits>
14#include <string>
15
16#include "../../libMagAOX/libMagAOX.hpp" // Note this is included on command line to trigger pch
17
18#include "zb_serial.h"
19
20namespace MagAOX
21{
22namespace app
23{
24
25/// A class to manage the details of one binary-protocol stage in a Zaber system.
26/**
27 * \ingroup zaberLowLevelBinary
28 */
29template <class parentT>
31{
32 public:
33 /// Binary protocol command numbers used by the T-LSM firmware 5.xx implementation.
55
56 /// Device-mode bits used by the implementation.
57 enum modeBits : int32_t
58 {
61 modeHomeStatus = ( 1 << 7 )
62 };
63
64 /// Stored-position register used to persist the MagAO-X parked position.
65 static constexpr int32_t parkPositionRegister = 0;
66
67 protected:
68 /// Parent application used for logging and power-state checks.
69 parentT *m_parent{ nullptr };
70
71 /// Configured stage name used in INDI properties.
72 std::string m_name;
73
74 /// Configured stage serial number.
75 std::string m_serial;
76
77 /// Current binary device address.
78 int m_deviceAddress{ -1 };
79
80 /// Axis number placeholder for future multi-axis support.
81 int m_axisNumber{ 0 };
82
83 /// Whether the most recent command was accepted.
84 bool m_commandStatus{ true };
85
86 /// Current device state mapped to ASCII-app semantics.
87 char m_deviceStatus{ 'U' };
88
89 /// Whether the stage is currently homing.
90 bool m_homing{ false };
91
92 /// Time stamp of the last successful home operation.
93 timespec m_lastHomed{ 0, 0 };
94
95 /// Whether MagAO-X currently considers this stage parked.
96 bool m_parked{ false };
97
98 /// Current raw position in microsteps.
99 long m_rawPos{ 0 };
100
101 /// Last target position sent to the device in microsteps.
102 long m_tgtPos{ 0 };
103
104 /// Configured target speed command value for this stage.
105 int32_t m_targetSpeed{ 1000 };
106
107 /// Maximum position in microsteps.
108 long m_maxPos{ -1 };
109
110 /// Emulated parked position in microsteps.
111 long m_parkPos{ 0 };
112
113 /// Whether a parked position has been recovered from device non-volatile memory.
114 bool m_hasParkPos{ false };
115
116 /// Whether a parked state file has been loaded from disk.
117 bool m_hasStateFile{ false };
118
119 /// Raw position loaded from the parked state file.
121
122 /// Parked flag loaded from the parked state file.
123 bool m_stateFileParked{ false };
124
125 /// Last reported stage temperature. Firmware 5.35 does not expose this directly.
126 float m_temp{ -999.0 };
127
128 /// whether potentiometer knob is enabled
129 bool m_knobEnabled{ false };
130
131 /// Whether any warning-equivalent condition is active.
132 bool m_warn{ false };
133
134 /// Driver disabled warning flag.
135 bool m_warnFD{ false };
136
137 /// Device-specific warning flag placeholders retained for API compatibility.
138 bool m_warnFQ{ false };
139 bool m_warnFS{ false };
140 bool m_warnFT{ false };
141 bool m_warnFB{ false };
142 bool m_warnFP{ false };
143 bool m_warnFE{ false };
144 bool m_warnWH{ false };
145 bool m_warnWL{ false };
146 bool m_warnWP{ false };
147 bool m_warnWV{ false };
148 bool m_warnWT{ false };
149 bool m_warnWM{ false };
150 bool m_warnWR{ false };
151 bool m_warnNC{ false };
152 bool m_warnNI{ false };
153 bool m_warnND{ false };
154 bool m_warnNU{ false };
155 bool m_warnNJ{ false };
156 bool m_warnUNK{ false };
157
158 public:
159 /// Default constructor deleted because stages require a parent app.
161
162 /// Construct the stage helper.
163 zaberBinaryStage( parentT *parent /**< [in] the parent application */ )
164 {
165 if( parent == nullptr )
166 {
167 throw mx::exception( mx::error_t::invalidarg, "parent was null on construction of zaberBinaryStage" );
168 }
169
170 m_parent = parent;
171 }
172
173 /// Get the stage name.
174 std::string name();
175
176 /// Set the stage name.
177 int name( const std::string &n /**< [in] the new stage name */ );
178
179 /// Get the stage serial number.
180 std::string serial();
181
182 /// Set the stage serial number.
183 int serial( const std::string &s /**< [in] the new stage serial number */ );
184
185 /// Get the device address.
187
188 /// Set the device address.
189 int deviceAddress( const int &da /**< [in] the new device address */ );
190
191 /// Get the axis number.
193
194 /// Set the axis number.
195 int axisNumber( const int &an /**< [in] the new axis number */ );
196
197 /// Get the status of the last command.
199
200 /// Get the current device status.
202
203 /// Get the homing state.
204 bool homing();
205
206 /// Get the last home time.
207 time_t lastHomed();
208
209 /// Get the parked state.
210 int parked();
211
212 /// Get the knob state.
214
215 /// Get the current raw position.
216 long rawPos();
217
218 /// Get the target raw position.
219 long tgtPos();
220
221 /// Get the maximum position.
222 long maxPos();
223
224 /// Get the configured target speed.
225 int32_t targetSpeed();
226
227 /// Set the configured target speed.
228 int targetSpeed( const int32_t &speed /**< [in] the target speed command value */ );
229
230 /// Get whether any warning-equivalent flag is set.
231 bool warn();
232
233 /// Get the driver temperature.
234 float temp();
235
236 /// Get whether any warning-equivalent flag is set.
238
239 /// Get the driver-disabled warning flag.
240 bool warnFD();
241 /// Get the FQ warning flag.
242 bool warnFQ();
243 /// Get the FS warning flag.
244 bool warnFS();
245 /// Get the FT warning flag.
246 bool warnFT();
247 /// Get the FB warning flag.
248 bool warnFB();
249 /// Get the FP warning flag.
250 bool warnFP();
251 /// Get the FE warning flag.
252 bool warnFE();
253 /// Get the WH warning flag.
254 bool warnWH();
255 /// Get the WL warning flag.
256 bool warnWL();
257 /// Get the WP warning flag.
258 bool warnWP();
259 /// Get the WV warning flag.
260 bool warnWV();
261 /// Get the WT warning flag.
262 bool warnWT();
263 /// Get the WM warning flag.
264 bool warnWM();
265 /// Get the WR warning flag.
266 bool warnWR();
267 /// Get the NC warning flag.
268 bool warnNC();
269 /// Get the NI warning flag.
270 bool warnNI();
271 /// Get the ND warning flag.
272 bool warnND();
273 /// Get the NU warning flag.
274 bool warnNU();
275 /// Get the NJ warning flag.
276 bool warnNJ();
277 /// Get the unknown-warning flag.
278 bool warnUNK();
279
280 /// Send a command and wait for the corresponding binary reply.
281 int queryCommand( int32_t &response, /**< [out] decoded reply data */
282 z_port port, /**< [in] the port with which to communicate */
283 uint8_t commandNumber, /**< [in] the command number to send */
284 int32_t data, /**< [in] the command data */
285 uint8_t expectedReply /**< [in] the expected reply command number */
286 );
287
288 /// Send a command for which no reply is expected.
289 int sendCommandNoReply( z_port port, /**< [in] the port with which to communicate */
290 uint8_t commandNumber, /**< [in] the command number to send */
291 int32_t data /**< [in] the command data */
292 );
293
294 /// Return a setting value from the device.
295 int getSetting( int32_t &value, /**< [out] the setting value */
296 z_port port, /**< [in] the port with which to communicate */
297 uint8_t settingNumber /**< [in] the setting command number to query */
298 );
299
300 /// Get the maximum position from the device.
301 int getMaxPos( z_port port /**< [in] the port with which to communicate */ );
302
303 /// Get the parked state for MagAO-X compatibility.
304 int getParked( z_port port /**< [in] the port with which to communicate */ );
305
306 /// Get the knob enabled status
307 int getKnob( z_port port /**< [in] the port with which to communicate */ );
308
309 /// Update the current position and derived motion state.
310 int updatePos( z_port port /**< [in] the port with which to communicate */ );
311
312 /// Update the stage temperature, if supported.
313 int updateTemp( z_port port /**< [in] the port with which to communicate */ );
314
315 /// Disable the manual knob and asynchronous command replies.
316 int enableKnob( z_port port, bool enable /**< [in] the port with which to communicate */ );
317
318 /// Set the target speed used for absolute and relative moves.
319 int setTargetSpeed( z_port port, /**< [in] the port with which to communicate */
320 int32_t speed /**< [in] the target speed command value */
321 );
322
323 /// Set the hold current used while the stage is idle.
324 int setHoldCurrent( z_port port, /**< [in] the port with which to communicate */
325 int32_t value /**< [in] the hold current command value */
326 );
327
328 /// Stop the stage.
329 int stop( z_port port /**< [in] the port with which to communicate */ );
330
331 /// Emergency-stop the stage.
332 int estop( z_port port /**< [in] the port with which to communicate */ );
333
334 /// Home the stage.
335 int home( z_port port /**< [in] the port with which to communicate */ );
336
337 /// Mark the stage parked using MagAO-X bookkeeping semantics.
338 int park( z_port port /**< [in] the port with which to communicate */ );
339
340 /// Clear the parked bookkeeping state.
341 int unpark( z_port port /**< [in] the port with which to communicate */ );
342
343 /// Recall the MagAO-X parked position from device non-volatile memory.
344 int recallParkPosition( z_port port /**< [in] the port with which to communicate */ );
345
346 /// Restore parked state after a power cycle if device and disk state agree.
347 int restoreParkedState( z_port port /**< [in] the port with which to communicate */ );
348
349 /// Move to a new absolute position.
350 int moveAbs( z_port port, /**< [in] the port with which to communicate */
351 long rawPos /**< [in] the position to move to in microsteps */ );
352
353 /// Clear all warning flags.
355
356 /// Refresh warning-equivalent state from firmware 5.xx information.
357 int getWarnings( z_port port /**< [in] the port with which to communicate */ );
358
359 /// Refresh the stored last-home timestamp when a home completion is detected.
360 int updateLastHomed( bool wasHoming /**< [in] whether the stage was homing before the latest status refresh */ );
361
362 /// Clear transient state on power-off.
364
365 /// Write the state file used by the low-level app.
366 int writeStateFile( std::ofstream &fout /**< [in] an open output stream */ );
367
368 /// Read the state file used by the low-level app.
369 int readStateFile( std::ifstream &fin /**< [in] an open input stream */ );
370};
371
372template <class parentT>
374{
375 return m_name;
376}
377
378template <class parentT>
379int zaberBinaryStage<parentT>::name( const std::string &n )
380{
381 m_name = n;
382 return 0;
383}
384
385template <class parentT>
387{
388 return m_serial;
389}
390
391template <class parentT>
392int zaberBinaryStage<parentT>::serial( const std::string &s )
393{
394 m_serial = s;
395 return 0;
396}
397
398template <class parentT>
400{
401 return m_deviceAddress;
402}
403
404template <class parentT>
406{
407 m_deviceAddress = da;
408 return 0;
409}
410
411template <class parentT>
413{
414 return m_axisNumber;
415}
416
417template <class parentT>
419{
420 m_axisNumber = an;
421 return 0;
422}
423
424template <class parentT>
426{
427 return m_commandStatus;
428}
429
430template <class parentT>
432{
433 return m_deviceStatus;
434}
435
436template <class parentT>
438{
439 return m_homing;
440}
441
442template <class parentT>
444{
445 return m_lastHomed.tv_sec;
446}
447
448template <class parentT>
450{
451 return m_parked;
452}
453
454template <class parentT>
456{
457 return m_knobEnabled;
458}
459
460template <class parentT>
462{
463 return m_rawPos;
464}
465
466template <class parentT>
468{
469 return m_tgtPos;
470}
471
472template <class parentT>
474{
475 return m_maxPos;
476}
477
478template <class parentT>
480{
481 return m_targetSpeed;
482}
483
484template <class parentT>
485int zaberBinaryStage<parentT>::targetSpeed( const int32_t &speed )
486{
487 m_targetSpeed = speed;
488 return 0;
489}
490
491template <class parentT>
493{
494 return m_warn;
495}
496
497template <class parentT>
499{
500 return m_temp;
501}
502
503template <class parentT>
505{
506 return m_warn;
507}
508
509template <class parentT>
511{
512 return m_warnFD;
513}
514
515template <class parentT>
517{
518 return m_warnFQ;
519}
520
521template <class parentT>
523{
524 return m_warnFS;
525}
526
527template <class parentT>
529{
530 return m_warnFT;
531}
532
533template <class parentT>
535{
536 return m_warnFB;
537}
538
539template <class parentT>
541{
542 return m_warnFP;
543}
544
545template <class parentT>
547{
548 return m_warnFE;
549}
550
551template <class parentT>
553{
554 return m_warnWH;
555}
556
557template <class parentT>
559{
560 return m_warnWL;
561}
562
563template <class parentT>
565{
566 return m_warnWP;
567}
568
569template <class parentT>
571{
572 return m_warnWV;
573}
574
575template <class parentT>
577{
578 return m_warnWT;
579}
580
581template <class parentT>
583{
584 return m_warnWM;
585}
586
587template <class parentT>
589{
590 return m_warnWR;
591}
592
593template <class parentT>
595{
596 return m_warnNC;
597}
598
599template <class parentT>
601{
602 return m_warnNI;
603}
604
605template <class parentT>
607{
608 return m_warnND;
609}
610
611template <class parentT>
613{
614 return m_warnNU;
615}
616
617template <class parentT>
619{
620 return m_warnNJ;
621}
622
623template <class parentT>
625{
626 return m_warnUNK;
627}
628
629template <class parentT>
631 int32_t &response, z_port port, uint8_t commandNumber, int32_t data, uint8_t expectedReply )
632{
633 if( m_deviceAddress < 1 )
634 {
636 std::format( "stage {} with s/n {} not found in system.", m_name, m_serial ) );
637 }
638
639 if( port <= 0 )
640 {
641 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
642 {
643 return -1;
644 }
645
646 return MagAOXAppT::log<software_error, -1>( { 0, "invalid zaber binary port" } );
647 }
648
649 uint8_t command[6];
650 if( zb_encode( command, static_cast<uint8_t>( m_deviceAddress ), commandNumber, data ) != Z_SUCCESS )
651 {
652 return MagAOXAppT::log<software_error, -1>( "zb_encode failed" );
653 }
654
655 if( zb_send( port, command ) != 6 )
656 {
657 return MagAOXAppT::log<software_error, -1>( "zb_send failed" );
658 }
659
660 uint8_t reply[6];
661 int rv = zb_receive( port, reply );
662 if( rv != 6 )
663 {
664 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
665 {
666 return -1;
667 }
668
669 return MagAOXAppT::log<software_error, -1>( "zb_receive failed" );
670 }
671
672 if( reply[0] != static_cast<uint8_t>( m_deviceAddress ) )
673 {
675 std::format( "unexpected reply from device {} while querying {}", reply[0], m_name ) );
676 }
677
678 if( reply[1] == 255 )
679 {
680 int32_t errorCode;
681 zb_decode( &errorCode, reply );
683 std::format( "device {} command {} returned error {}", m_name, commandNumber, errorCode ) );
684 }
685
686 if( reply[1] != expectedReply )
687 {
689 std::format( "device {} returned reply {} while expecting {}", m_name, reply[1], expectedReply ) );
690 }
691
692 if( zb_decode( &response, reply ) != Z_SUCCESS )
693 {
694 return MagAOXAppT::log<software_error, -1>( "zb_decode failed" );
695 }
696
697 m_commandStatus = true;
698 return 0;
699}
700
701template <class parentT>
702int zaberBinaryStage<parentT>::sendCommandNoReply( z_port port, uint8_t commandNumber, int32_t data )
703{
704 if( m_deviceAddress < 1 )
705 {
707 std::format( "stage {} with s/n {} not found in system.", m_name, m_serial ) );
708 }
709
710 if( port <= 0 )
711 {
712 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
713 {
714 return -1;
715 }
716
717 return MagAOXAppT::log<software_error, -1>( { 0, "invalid zaber binary port" } );
718 }
719
720 uint8_t command[6];
721 if( zb_encode( command, static_cast<uint8_t>( m_deviceAddress ), commandNumber, data ) != Z_SUCCESS )
722 {
723 return MagAOXAppT::log<software_error, -1>( "zb_encode failed" );
724 }
725
726 if( zb_send( port, command ) != 6 )
727 {
728 return MagAOXAppT::log<software_error, -1>( "zb_send failed" );
729 }
730
731 m_commandStatus = true;
732 return 0;
733}
734
735template <class parentT>
736int zaberBinaryStage<parentT>::getSetting( int32_t &value, z_port port, uint8_t settingNumber )
737{
738 return queryCommand( value, port, cmdReturnSetting, settingNumber, settingNumber );
739}
740
741template <class parentT>
743{
744 int32_t value;
745 int rv = getSetting( value, port, cmdSetMaximumPosition );
746 if( rv < 0 )
747 {
748 return rv;
749 }
750
751 m_maxPos = value;
752 return 0;
753}
754
755template <class parentT>
757{
758 if( m_hasParkPos && m_rawPos == m_parkPos )
759 {
760 m_parked = true;
761 }
762 else
763 {
764 m_parked = false;
765 }
766
767 return 0;
768}
769
770template <class parentT>
772{
773 int32_t value;
774 int rv = getSetting( value, port, cmdSetDeviceMode );
775 if( rv < 0 )
776 {
777 return rv;
778 }
779 m_knobEnabled = !( value & modeDisablePotentiometer );
780
781 return 0;
782}
783
784template <class parentT>
786{
787 bool wasHoming = m_homing;
788
789 int32_t status;
790 int rv = queryCommand( status, port, cmdReturnStatus, 0, cmdReturnStatus );
791 if( rv < 0 )
792 {
793 return rv;
794 }
795
796 if( status == 0 )
797 {
798 m_deviceStatus = 'I';
799 }
800 else
801 {
802 m_deviceStatus = 'B';
803 }
804
805 m_homing = ( status == 1 );
806
807 int32_t pos;
808 rv = queryCommand( pos, port, cmdReturnCurrentPosition, 0, cmdReturnCurrentPosition );
809 if( rv < 0 )
810 {
811 return rv;
812 }
813
814 m_rawPos = pos;
815
816 rv = getWarnings( port );
817 if( rv < 0 )
818 {
819 return rv;
820 }
821
822 return updateLastHomed( wasHoming );
823}
824
825template <class parentT>
827{
828 m_temp = -999.0;
829 return 0;
830}
831
832template <class parentT>
833int zaberBinaryStage<parentT>::enableKnob( z_port port, bool enable )
834{
835 int32_t mode;
836 int rv = getSetting( mode, port, cmdSetDeviceMode );
837 if( rv < 0 )
838 {
839 return rv;
840 }
841
842 mode |= modeDisableAutoReply;
843 if( enable )
844 mode &= ~modeDisablePotentiometer; // clear the bit to enable
845 else
846 mode |= modeDisablePotentiometer; // set the bit to disable
847
848 rv = sendCommandNoReply( port, cmdSetDeviceMode, mode );
849 if( rv < 0 )
850 {
851 return rv;
852 }
853
854 int32_t appliedMode;
855 rv = getSetting( appliedMode, port, cmdSetDeviceMode );
856 if( rv < 0 )
857 {
858 return rv;
859 }
860
861 bool knobOk = enable ? !( appliedMode & modeDisablePotentiometer ) // bit should be 0
862 : ( appliedMode & modeDisablePotentiometer ); // bit should be 1
863
864 if( !knobOk || !( appliedMode & modeDisableAutoReply ) )
865 {
867 std::format( "device {} did not apply requested device mode {}, got {}", m_name, mode, appliedMode ) );
868 }
869
870 return 0;
871}
872
873template <class parentT>
874int zaberBinaryStage<parentT>::setTargetSpeed( z_port port, int32_t speed )
875{
876 int rv = sendCommandNoReply( port, cmdSetTargetSpeed, speed );
877 if( rv < 0 )
878 {
879 return rv;
880 }
881
882 int32_t appliedSpeed;
883 rv = getSetting( appliedSpeed, port, cmdSetTargetSpeed );
884 if( rv < 0 )
885 {
886 return rv;
887 }
888
889 if( appliedSpeed != speed )
890 {
892 std::format( "device {} reported target speed {} after requesting {}", m_name, appliedSpeed, speed ) );
893 }
894
895 return 0;
896}
897
898template <class parentT>
899int zaberBinaryStage<parentT>::setHoldCurrent( z_port port, int32_t value )
900{
901 int rv = sendCommandNoReply( port, cmdSetHoldCurrent, value );
902 if( rv < 0 )
903 {
904 return rv;
905 }
906
907 int32_t appliedValue;
908 rv = getSetting( appliedValue, port, cmdSetHoldCurrent );
909 if( rv < 0 )
910 {
911 return rv;
912 }
913
914 if( appliedValue != value )
915 {
917 std::format( "device {} reported hold current {} after requesting {}", m_name, appliedValue, value ) );
918 }
919
920 return 0;
921}
922
923template <class parentT>
925{
926 int rv = sendCommandNoReply( port, cmdStop, 0 );
927 if( rv < 0 )
928 {
929 return rv;
930 }
931
932 m_homing = false;
933 m_parked = false;
934 return 0;
935}
936
937template <class parentT>
939{
940 return stop( port );
941}
942
943template <class parentT>
945{
946 int rv = sendCommandNoReply( port, cmdHome, 0 );
947 if( rv < 0 )
948 {
949 return rv;
950 }
951
952 m_homing = true;
953 m_tgtPos = 0;
954 m_parked = false;
955 return 0;
956}
957
958template <class parentT>
960{
961 int rv = sendCommandNoReply( port, cmdStoreCurrentPosition, parkPositionRegister );
962 if( rv < 0 )
963 {
964 return rv;
965 }
966
967 rv = recallParkPosition( port );
968 if( rv < 0 )
969 {
970 return rv;
971 }
972
973 rv = setHoldCurrent( port, 0 );
974 if( rv < 0 )
975 {
976 return rv;
977 }
978
979 return 0;
980}
981
982template <class parentT>
984{
985 m_parked = false;
986 return 0;
987}
988
989template <class parentT>
991{
992 int32_t storedPosition;
993 int rv =
994 queryCommand( storedPosition, port, cmdReturnStoredPosition, parkPositionRegister, cmdReturnStoredPosition );
995 if( rv < 0 )
996 {
997 m_hasParkPos = false;
998 return -1;
999 }
1000
1001 m_parkPos = storedPosition;
1002 m_hasParkPos = true;
1003 m_parked = ( m_rawPos == m_parkPos );
1004 return 0;
1005}
1006
1007template <class parentT>
1009{
1010 if( !m_hasStateFile || !m_stateFileParked || !m_hasParkPos )
1011 {
1012 return 0;
1013 }
1014
1015 if( m_stateFileRawPos != m_parkPos )
1016 {
1018 std::format( "parked state mismatch for {}: disk {} device {}", m_name, m_stateFileRawPos, m_parkPos ) );
1019 }
1020
1021 int rv = setHoldCurrent( port, 0 );
1022 if( rv < 0 )
1023 {
1024 return rv;
1025 }
1026
1027 rv = sendCommandNoReply( port, cmdSetCurrentPosition, m_stateFileRawPos );
1028 if( rv < 0 )
1029 {
1030 return rv;
1031 }
1032
1033 int32_t restoredPos;
1034 rv = queryCommand( restoredPos, port, cmdReturnCurrentPosition, 0, cmdReturnCurrentPosition );
1035 if( rv < 0 )
1036 {
1037 return rv;
1038 }
1039
1040 if( restoredPos != m_stateFileRawPos )
1041 {
1042 return MagAOXAppT::log<software_error, -1>(
1043 std::format( "device {} restored position {} but expected {}", m_name, restoredPos, m_stateFileRawPos ) );
1044 }
1045
1046 m_rawPos = restoredPos;
1047 m_tgtPos = restoredPos;
1048 m_parked = true;
1049 return 0;
1050}
1051
1052template <class parentT>
1053int zaberBinaryStage<parentT>::moveAbs( z_port port, long rawPos )
1054{
1055 if( m_parked )
1056 {
1057 int rv = unpark( port );
1058 if( rv < 0 )
1059 {
1060 return rv;
1061 }
1062 }
1063
1064 int rv = sendCommandNoReply( port, cmdMoveAbsolute, rawPos );
1065 if( rv < 0 )
1066 {
1067 return rv;
1068 }
1069
1070 m_tgtPos = rawPos;
1071 m_homing = false;
1072 return 0;
1073}
1074
1075template <class parentT>
1077{
1078 m_warn = false;
1079 m_warnFD = false;
1080 m_warnFQ = false;
1081 m_warnFS = false;
1082 m_warnFT = false;
1083 m_warnFB = false;
1084 m_warnFP = false;
1085 m_warnFE = false;
1086 m_warnWH = false;
1087 m_warnWL = false;
1088 m_warnWP = false;
1089 m_warnWV = false;
1090 m_warnWT = false;
1091 m_warnWM = false;
1092 m_warnWR = false;
1093 m_warnNC = false;
1094 m_warnNI = false;
1095 m_warnND = false;
1096 m_warnNU = false;
1097 m_warnNJ = false;
1098 m_warnUNK = false;
1099 return 0;
1100}
1101
1102template <class parentT>
1104{
1105 unsetWarnings();
1106
1107 int32_t mode;
1108 int rv = getSetting( mode, port, cmdSetDeviceMode );
1109 if( rv < 0 )
1110 {
1111 return rv;
1112 }
1113
1114 if( ( mode & modeHomeStatus ) == 0 )
1115 {
1116 m_warn = true;
1117 m_warnWR = true;
1118 }
1119
1120 return 0;
1121}
1122
1123template <class parentT>
1125{
1126 if( !m_homing && !m_warnWR && m_tgtPos == 0 && m_rawPos == 0 && ( wasHoming || m_lastHomed.tv_sec == 0 ) )
1127 {
1128 if( clock_gettime( CLOCK_ISIO, &m_lastHomed ) < 0 )
1129 {
1130 return MagAOXAppT::log<software_error, -1>( { errno, 0, "clock_gettime for last homed" } );
1131 }
1132 }
1133
1134 return 0;
1135}
1136
1137template <class parentT>
1139{
1140 m_commandStatus = true;
1141 m_deviceStatus = 'U';
1142 m_homing = false;
1143 m_temp = -999.0;
1144 unsetWarnings();
1145 return 0;
1146}
1147
1148template <class parentT>
1150{
1151 fout << m_rawPos << '\n';
1152 if( !fout )
1153 {
1154 return MagAOXAppT::log<software_error, -1>( { "error writing raw position" } );
1155 }
1156
1157 fout << m_parked << '\n';
1158 if( !fout )
1159 {
1160 return MagAOXAppT::log<software_error, -1>( { "error writing parked state" } );
1161 }
1162
1163 fout << m_maxPos << '\n';
1164 if( !fout )
1165 {
1166 return MagAOXAppT::log<software_error, -1>( { "error writing max position" } );
1167 }
1168
1169 fout << m_lastHomed.tv_sec << '\n';
1170 if( !fout )
1171 {
1172 return MagAOXAppT::log<software_error, -1>( { "error writing last home time" } );
1173 }
1174
1175 return 0;
1176}
1177
1178template <class parentT>
1180{
1181 long rawPos;
1182 bool parked;
1183 long maxPos;
1184 time_t lastHomed;
1185
1186 fin >> rawPos;
1187 if( !fin )
1188 {
1189 return MagAOXAppT::log<software_error, -1>( { "error reading raw position" } );
1190 }
1191
1192 fin >> parked;
1193 if( !fin )
1194 {
1195 return MagAOXAppT::log<software_error, -1>( { "error reading parked state" } );
1196 }
1197
1198 fin >> maxPos;
1199 if( !fin )
1200 {
1201 return MagAOXAppT::log<software_error, -1>( { "error reading max position" } );
1202 }
1203
1204 fin >> lastHomed;
1205 if( !fin )
1206 {
1207 return MagAOXAppT::log<software_error, -1>( { "error reading last home time" } );
1208 }
1209
1210 m_rawPos = rawPos;
1211 m_tgtPos = rawPos;
1212 m_parked = parked;
1213 m_parkPos = rawPos;
1214 m_hasParkPos = parked;
1215 m_hasStateFile = true;
1216 m_stateFileRawPos = rawPos;
1217 m_stateFileParked = parked;
1218 m_maxPos = maxPos;
1219 m_lastHomed.tv_sec = lastHomed;
1220 m_lastHomed.tv_nsec = 0;
1221 return 0;
1222}
1223
1224} // namespace app
1225} // namespace MagAOX
1226
1227#endif // zaberBinaryStage_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 binary-protocol stage in a Zaber system.
static constexpr int32_t parkPositionRegister
Stored-position register used to persist the MagAO-X parked position.
bool m_commandStatus
Whether the most recent command was accepted.
int targetSpeed(const int32_t &speed)
Set the configured target speed.
int park(z_port port)
Mark the stage parked using MagAO-X bookkeeping semantics.
int getParked(z_port port)
Get the parked state for MagAO-X compatibility.
int stop(z_port port)
Stop the stage.
int updatePos(z_port port)
Update the current position and derived motion state.
bool m_warn
Whether any warning-equivalent condition is active.
int sendCommandNoReply(z_port port, uint8_t commandNumber, int32_t data)
Send a command for which no reply is expected.
bool warnWV()
Get the WV warning flag.
int updateTemp(z_port port)
Update the stage temperature, if supported.
bool warnNC()
Get the NC warning flag.
timespec m_lastHomed
Time stamp of the last successful home operation.
bool warnNJ()
Get the NJ warning flag.
bool warn()
Get whether any warning-equivalent flag is set.
long maxPos()
Get the maximum position.
bool warnWH()
Get the WH warning flag.
float m_temp
Last reported stage temperature. Firmware 5.35 does not expose this directly.
int deviceAddress()
Get the device address.
char m_deviceStatus
Current device state mapped to ASCII-app semantics.
bool warnFS()
Get the FS warning flag.
int getMaxPos(z_port port)
Get the maximum position from the device.
bool warnFE()
Get the FE warning flag.
std::string serial()
Get the stage serial number.
bool m_hasStateFile
Whether a parked state file has been loaded from disk.
bool warningState()
Get whether any warning-equivalent flag is set.
long m_maxPos
Maximum position in microsteps.
commandCodes
Binary protocol command numbers used by the T-LSM firmware 5.xx implementation.
char deviceStatus()
Get the current device status.
int m_axisNumber
Axis number placeholder for future multi-axis support.
zaberBinaryStage(parentT *parent)
Construct the stage helper.
zaberBinaryStage()=delete
Default constructor deleted because stages require a parent app.
std::string m_serial
Configured stage serial number.
bool warnFB()
Get the FB warning flag.
int getKnob(z_port port)
Get the knob enabled status.
int readStateFile(std::ifstream &fin)
Read the state file used by the low-level app.
int getSetting(int32_t &value, z_port port, uint8_t settingNumber)
Return a setting value from the device.
bool warnNU()
Get the NU warning flag.
bool warnUNK()
Get the unknown-warning flag.
bool warnND()
Get the ND warning flag.
int serial(const std::string &s)
Set the stage serial number.
long m_tgtPos
Last target position sent to the device in microsteps.
bool warnFQ()
Get the FQ warning flag.
int32_t targetSpeed()
Get the configured target speed.
int axisNumber(const int &an)
Set the axis number.
bool m_warnFD
Driver disabled warning flag.
int unpark(z_port port)
Clear the parked bookkeeping state.
float temp()
Get the driver temperature.
int restoreParkedState(z_port port)
Restore parked state after a power cycle if device and disk state agree.
int m_deviceAddress
Current binary device address.
int name(const std::string &n)
Set the stage name.
int unsetWarnings()
Clear all warning flags.
bool homing()
Get the homing state.
bool m_homing
Whether the stage is currently homing.
long m_rawPos
Current raw position in microsteps.
long rawPos()
Get the current raw position.
int getWarnings(z_port port)
Refresh warning-equivalent state from firmware 5.xx information.
bool warnFD()
Get the driver-disabled warning flag.
bool warnFP()
Get the FP warning flag.
int32_t m_targetSpeed
Configured target speed command value for this stage.
bool warnWR()
Get the WR warning flag.
parentT * m_parent
Parent application used for logging and power-state checks.
int onPowerOff()
Clear transient state on power-off.
bool warnWT()
Get the WT warning flag.
bool warnNI()
Get the NI warning flag.
int moveAbs(z_port port, long rawPos)
Move to a new absolute position.
modeBits
Device-mode bits used by the implementation.
bool m_warnFQ
Device-specific warning flag placeholders retained for API compatibility.
int deviceAddress(const int &da)
Set the device address.
bool commandStatus()
Get the status of the last command.
std::string name()
Get the stage name.
long m_stateFileRawPos
Raw position loaded from the parked state file.
int estop(z_port port)
Emergency-stop the stage.
int enableKnob(z_port port, bool enable)
Disable the manual knob and asynchronous command replies.
bool m_hasParkPos
Whether a parked position has been recovered from device non-volatile memory.
long tgtPos()
Get the target raw position.
long m_parkPos
Emulated parked position in microsteps.
int setTargetSpeed(z_port port, int32_t speed)
Set the target speed used for absolute and relative moves.
int queryCommand(int32_t &response, z_port port, uint8_t commandNumber, int32_t data, uint8_t expectedReply)
Send a command and wait for the corresponding binary reply.
bool warnWM()
Get the WM warning flag.
int writeStateFile(std::ofstream &fout)
Write the state file used by the low-level app.
int axisNumber()
Get the axis number.
bool warnWP()
Get the WP warning flag.
int updateLastHomed(bool wasHoming)
Refresh the stored last-home timestamp when a home completion is detected.
bool warnWL()
Get the WL warning flag.
int setHoldCurrent(z_port port, int32_t value)
Set the hold current used while the stage is idle.
bool m_parked
Whether MagAO-X currently considers this stage parked.
std::string m_name
Configured stage name used in INDI properties.
int recallParkPosition(z_port port)
Recall the MagAO-X parked position from device non-volatile memory.
time_t lastHomed()
Get the last home time.
int home(z_port port)
Home the stage.
int parked()
Get the parked state.
bool m_knobEnabled
whether potentiometer knob is enabled
bool warnFT()
Get the FT warning flag.
bool knobEnabled()
Get the knob state.
bool m_stateFileParked
Parked flag loaded from the parked state file.
Provides a set of functions for interacting with Zaber devices in the binary protocol.
Definition dm.hpp:19
Software ERR log entry.
int zb_decode(int32_t *destination, const uint8_t *reply)
Definition zb_serial.c:48
int zb_encode(uint8_t *destination, uint8_t device_number, uint8_t command_number, int32_t data)
Definition zb_serial.c:25
int zb_send(z_port port, const uint8_t *command)
int zb_receive(z_port port, uint8_t *destination)
@ Z_SUCCESS
Definition z_common.h:65