forked from hjd1964/OnStep
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Command.ino
2383 lines (2267 loc) · 117 KB
/
Command.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// -----------------------------------------------------------------------------------
// Command processing
// last RA/Dec time
unsigned long _coord_t=0;
// help with commands
enum Command {COMMAND_NONE, COMMAND_SERIAL_A, COMMAND_SERIAL_B, COMMAND_SERIAL_C, COMMAND_SERIAL_D, COMMAND_SERIAL_E, COMMAND_SERIAL_ST4, COMMAND_SERIAL_X};
cb cmdA; // the first Serial is always enabled
#ifdef HAL_SERIAL_B_ENABLED
cb cmdB;
#endif
#ifdef HAL_SERIAL_C_ENABLED
cb cmdC;
#endif
#ifdef HAL_SERIAL_D_ENABLED
cb cmdD;
#endif
#ifdef HAL_SERIAL_E_ENABLED
cb cmdE;
#endif
#if ST4_HAND_CONTROL == ON && ST4_INTERFACE != OFF
cb cmdST4;
#endif
char _replyX[50]=""; cb cmdX; // virtual command channel for internal use
// process commands
void processCommands() {
// scratch-pad variables
double f,f1;
int i,i1,i2;
byte b;
// last RA/Dec
static double _dec,_ra;
// command processing
static char reply[50];
static char command[3];
static char parameter[45];
static bool boolReply = true;
bool supress_frame = false;
char *conv_end;
#if FOCUSER1 == ON
static char primaryFocuser = 'F';
static char secondaryFocuser = 'f';
#endif
// accumulate the command
if (SerialA.available() > 0 && !cmdA.ready()) cmdA.add(SerialA.read());
#ifdef HAL_SERIAL_B_ENABLED
if (SerialB.available() > 0 && !cmdB.ready()) cmdB.add(SerialB.read());
#endif
#ifdef HAL_SERIAL_C_ENABLED
if (SerialC.available() > 0 && !cmdC.ready()) cmdC.add(SerialC.read());
#endif
#ifdef HAL_SERIAL_D_ENABLED
if (SerialD.available() > 0 && !cmdD.ready()) cmdD.add(SerialD.read());
#endif
#ifdef HAL_SERIAL_E_ENABLED
if (SerialE.available() > 0 && !cmdE.ready()) cmdE.add(SerialE.read());
#endif
#if ST4_HAND_CONTROL == ON && ST4_INTERFACE != OFF
if (SerialST4.available() > 0 && !cmdST4.ready()) cmdST4.add(SerialST4.read());
#endif
// send any reply
#ifdef HAL_SERIAL_TRANSMIT
if (SerialA.transmit()) return;
#ifdef HAL_SERIAL_B_ENABLED
if (SerialB.transmit()) return;
#endif
#ifdef HAL_SERIAL_C_ENABLED
if (SerialC.transmit()) return;
#endif
#ifdef HAL_SERIAL_D_ENABLED
if (SerialD.transmit()) return;
#endif
#endif
// if a command is ready, process it
Command process_command = COMMAND_NONE;
if (cmdA.ready()) { strcpy(command,cmdA.getCmd()); strcpy(parameter,cmdA.getParameter()); cmdA.flush(); process_command=COMMAND_SERIAL_A; }
#ifdef HAL_SERIAL_B_ENABLED
else if (cmdB.ready()) { strcpy(command,cmdB.getCmd()); strcpy(parameter,cmdB.getParameter()); cmdB.flush(); process_command=COMMAND_SERIAL_B; }
#endif
#ifdef HAL_SERIAL_C_ENABLED
else if (cmdC.ready()) { strcpy(command,cmdC.getCmd()); strcpy(parameter,cmdC.getParameter()); cmdC.flush(); process_command=COMMAND_SERIAL_C; }
#endif
#ifdef HAL_SERIAL_D_ENABLED
else if (cmdD.ready()) { strcpy(command,cmdD.getCmd()); strcpy(parameter,cmdD.getParameter()); cmdD.flush(); process_command=COMMAND_SERIAL_D; }
#endif
#ifdef HAL_SERIAL_E_ENABLED
else if (cmdE.ready()) { strcpy(command,cmdE.getCmd()); strcpy(parameter,cmdE.getParameter()); cmdE.flush(); process_command=COMMAND_SERIAL_E; }
#endif
#if ST4_HAND_CONTROL == ON && ST4_INTERFACE != OFF
else if (cmdST4.ready()) { strcpy(command,cmdST4.getCmd()); strcpy(parameter,cmdST4.getParameter()); cmdST4.flush(); process_command=COMMAND_SERIAL_ST4; }
#endif
else if (cmdX.ready()) { strcpy(command,cmdX.getCmd()); strcpy(parameter,cmdX.getParameter()); cmdX.flush(); process_command=COMMAND_SERIAL_X; }
else return;
if (process_command) {
// Command is two chars followed by an optional parameter...
commandError=CE_NONE;
// Handles empty and one char replies
reply[0]=0; reply[1]=0;
// (char)6 - Special
if (command[0] == (char)6) {
if (command[1] == '0') {
reply[0]=command[1]; strcpy(reply,"CK_FAIL"); // last cmd checksum failed
} else {
reply[0]=command[1]; reply[1]=0; // Equatorial or Horizon mode, A or P
supress_frame=true;
}
boolReply=false;
} else
// A - Alignment Commands
if (command[0] == 'A') {
// :AW# Align Write to EEPROM
// Returns: 1 on success
if (command[1] == 'W' && parameter[0] == 0) {
saveAlignModel();
} else
// :A?# Align status
// Returns: mno#
// where m is the maximum number of alignment stars
// n is the current alignment star (0 otherwise)
// o is the last required alignment star when an alignment is in progress (0 otherwise)
if (command[1] == '?' && parameter[0] == 0) {
reply[0]=MAX_NUM_ALIGN_STARS;
reply[1]='0'+alignThisStar;
reply[2]='0'+alignNumStars;
reply[3]=0;
boolReply=false;
} else
// :A[n]# Start Telescope Manual Alignment Sequence
// This is to initiate a n-star alignment for 1..MAX_NUM_ALIGN_STARS:
// 1) Before calling this function, the telescope should be in the polar-home position
// 2) Call this function with the # of align stars you'd like to use
// 3) Set the target location (RA/Dec) to a bright star, etc. (not too near the NCP/SCP)
// 4) Issue a goto command
// 5) Center the star/object using the guide commands (as needed)
// 6) Call :A+# command to accept the correction
// ( for two+ star alignment )
// 7) Back to #3 above until done, except where possible choose at least one star on both meridian sides
// Return: 0 on failure
// 1 on success
if (command[1] >= '1' && command[1] <= MAX_NUM_ALIGN_STARS && parameter[0] == 0) {
// set current time and date before calling this routine
// telescope should be set in the polar home (CWD) for a starting point
// this command sets indexAxis1, indexAxis2, azmCor=0; altCor=0;
setHome();
// start tracking
trackingState=TrackingSidereal;
enableStepperDrivers();
// start align...
alignNumStars=command[1]-'0';
alignThisStar=1;
} else
// :A+# Align accept target location
// Return: 0 on failure
// 1 on success
if (command[1] == '+' && parameter[0] == 0) {
if (alignActive()) {
CommandErrors e=alignStar();
if (e != CE_NONE) { alignNumStars=0; alignThisStar=0; commandError=e; }
} else commandError=CE_ALIGN_NOT_ACTIVE;
} else commandError=CE_CMD_UNKNOWN;
}
else
// $ - Set parameter
// :$BD[n]# Set Dec/Alt backlash in arc-seconds
// Return: 0 on failure
// 1 on success
// :$BR[n]# Set RA/Azm backlash in arc-seconds
// Return: 0 on failure
// 1 on success
// Set the Backlash values. Units are arc-seconds
if (command[0] == '$' && command[1] == 'B') {
if (atoi2((char*)¶meter[1],&i)) {
if (i >= 0 && i <= 3600) {
if (parameter[0] == 'D') {
reactivateBacklashComp();
cli(); backlashAxis2=(int)round(((double)i*axis2Settings.stepsPerMeasure)/3600.0); sei();
nv.writeInt(EE_backlashAxis2,backlashAxis2);
} else
if (parameter[0] == 'R') {
reactivateBacklashComp();
cli(); backlashAxis1 =(int)round(((double)i*axis1Settings.stepsPerMeasure)/3600.0); sei();
nv.writeInt(EE_backlashAxis1,backlashAxis1);
} else commandError=CE_CMD_UNKNOWN;
} else commandError=CE_PARAM_RANGE;
} else commandError=CE_PARAM_FORM;
} else
// % - Return parameter
// :%BD# Get Dec/Alt Antibacklash value in arc-seconds
// Return: n#
// :%BR# Get RA/Azm Antibacklash value in arc-seconds
// Return: n#
if (command[0] == '%' && command[1] == 'B') {
if (parameter[0] == 'D' && parameter[1] == 0) {
reactivateBacklashComp();
i=(int)round(((double)backlashAxis2*3600.0)/axis2Settings.stepsPerMeasure);
if (i < 0) i=0; if (i > 3600) i=3600;
sprintf(reply,"%d",i);
boolReply=false;
} else
if (parameter[0] == 'R' && parameter[1] == 0) {
reactivateBacklashComp();
i=(int)round(((double)backlashAxis1*3600.0)/axis1Settings.stepsPerMeasure);
if (i < 0) i=0; if (i > 3600) i=3600;
sprintf(reply,"%d",i);
boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// B - Reticule/Accessory Control
// :B+# Increase reticule Brightness
// Returns: Nothing
// :B-# Decrease Reticule Brightness
// Returns: Nothing
if (command[0] == 'B' && (command[1] == '+' || command[1] == '-') && parameter[0] == 0) {
#if LED_RETICLE >= 0
int scale;
if (reticuleBrightness > 255-8) scale=1; else
if (reticuleBrightness > 255-32) scale=4; else
if (reticuleBrightness > 255-64) scale=12; else
if (reticuleBrightness > 255-128) scale=32; else scale=64;
if (command[1] == '-') reticuleBrightness+=scale; if (reticuleBrightness > 255) reticuleBrightness=255;
if (command[1] == '+') reticuleBrightness-=scale; if (reticuleBrightness < 0) reticuleBrightness=0;
analogWrite(ReticlePin,reticuleBrightness);
#endif
boolReply=false;
} else
// C - Sync Control
// :CS# Synchonize the telescope with the current right ascension and declination coordinates
// Returns: Nothing (Sync's fail silently)
// :CM# Synchonize the telescope with the current database object (as above)
// Returns: "N/A#" on success, "En#" on failure where n is the error code per the :MS# command
if (command[0] == 'C' && (command[1] == 'S' || command[1] == 'M') && parameter[0] == 0) {
if (parkStatus == NotParked && trackingState != TrackingMoveTo) {
newTargetRA=origTargetRA; newTargetDec=origTargetDec;
#if TELESCOPE_COORDINATES == TOPOCENTRIC
topocentricToObservedPlace(&newTargetRA,&newTargetDec);
#endif
CommandErrors e;
if (alignActive()) {
e=alignStar();
if (e != CE_NONE) { alignNumStars=0; alignThisStar=0; commandError=e; }
} else {
e=syncEqu(newTargetRA,newTargetDec);
}
if (command[1] == 'M') {
if (e >= CE_GOTO_ERR_BELOW_HORIZON && e <= CE_GOTO_ERR_UNSPECIFIED) { reply[0]='E'; reply[1]=(char)(e-CE_GOTO_ERR_BELOW_HORIZON)+'1'; reply[2]=0; }
if (e == CE_NONE) strcpy(reply,"N/A");
}
boolReply=false;
}
} else
// D - Distance Bars
// :D# Return: "\0x7f#" if the mount is moving, otherwise "#".
if (command[0] == 'D' && command[1] == 0) { if (trackingState == TrackingMoveTo) { reply[0]=(char)127; reply[1]=0; } else { reply[0]='#'; reply[1]=0; supress_frame=true; } boolReply=false; } else
// E - Enter special mode
if (command[0] == 'E') {
// :EC[s]# Echo string [c] on DebugSer.
// Return: Nothing
if (command[1] == 'C') {
// spaces are encoded as '_'
for (unsigned int i=0; i < strlen(parameter); i++) if (parameter[i]=='_') parameter[i]=' ';
// a newline is encoded as '&' in the last char of message
int l=strlen(parameter);
if (l > 0 && parameter[l-1] == '&') { parameter[l-1]=0; DL(parameter); } else D(parameter);
boolReply=false;
} else
// :ENVRESET# Wipe flash. OnStep must be at home and tracking turned off for this command to work.
if (command[1] == 'N' && parameter[0] == 'V' && parameter[1] == 'R' && parameter[2] == 'E' && parameter[3] == 'S' && parameter[4] == 'E' && parameter[5] == 'T' && parameter[6] == 0) {
if (atHome || parkStatus == Parked) {
nv.writeLong(EE_autoInitKey,0);
strcpy(reply,"NV will be wiped on next boot.");
boolReply=false;
} else commandError=CE_NOT_PARKED_OR_AT_HOME; } else
#if SERIAL_B_ESP_FLASHING == ON
// :ESPFLASH# ESP8266 device flash mode. OnStep must be at home and tracking turned off for this command to work.
// Return: 1 on completion (after up to one minute from start of command.)
if (command[1] == 'S' && parameter[0] == 'P' && parameter[1] == 'F' && parameter[2] == 'L' && parameter[3] == 'A' && parameter[4] == 'S' && parameter[5] == 'H' && parameter[6] == 0) {
if (atHome || parkStatus == Parked) {
SerialA.println("The ESP8266 will now be placed in flash upload mode (at 115200 Baud.)");
SerialA.println("Arduino's 'Tools -> Upload Speed' should be set to 115200 Baud.");
SerialA.println("Waiting for data, you have one minute to start the upload.");
delay(1000);
fa.go(false); // flash the addon
SerialA.println("ESP8266 reset and in run mode, resuming OnStep operation...");
delay(1000);
} else commandError=CE_NOT_PARKED_OR_AT_HOME;
} else
#endif
commandError=CE_CMD_UNKNOWN;
} else
// :FA# Active?
// Return: 0 on failure
// 1 on success
if (command[0] == 'F' && command[1] == 'A' && parameter[0] == 0) {
#if FOCUSER1 != ON
commandError=CE_0;
#endif
} else
// :fA# Active?
// Return: 0 on failure
// 1 on success
if (command[0] == 'f' && command[1] == 'A' && parameter[0] == 0) {
#if FOCUSER2 != ON
commandError=CE_0;
#endif
} else
// F,f - Focuser1 and Focuser2 Commands
#if FOCUSER1 == ON
if (command[0] == 'F' || command[0]=='f') {
focuser *foc = NULL;
if (command[0] == primaryFocuser) foc = &foc1;
#if FOCUSER2 == ON
else if (command[0] == secondaryFocuser) foc = &foc2;
#endif
// check that we have a focuser selected and for commands that shouldn't have a parameter
if (foc != NULL && !(strchr("TpIMtuQF1234+-GZHh",command[1]) && parameter[0] != 0)) {
// get ready for commands that convert to microns or steps (these commands are upper-case for microns OR lower-case for steps)
double spm = foc->getStepsPerMicro(); if (strchr("bdgimrs",command[1])) spm = 1.0;
// :FA[n]# Select primary focuser where [n] = 1 or 2
// Return: 0 on failure
// 1 on success
if (command[1] == 'A') {
if (parameter[0] == '1' && parameter[1] == 0) { primaryFocuser=toupper(secondaryFocuser); secondaryFocuser=tolower(primaryFocuser); }
#if FOCUSER2 == ON
else if (parameter[0] == '2' && parameter[1] == 0) { primaryFocuser=tolower(secondaryFocuser); secondaryFocuser=toupper(primaryFocuser); }
#endif
else commandError=CE_PARAM_RANGE;
} else
// :Fa# Get primary focuser
// Returns: 1 if primary focuser is focuser 1, 0 otherwise
if (command[1] == 'a') { if (primaryFocuser != 'F') commandError=CE_0; } else
// :FT# Get status
// Returns: M# (for moving) or S# (for stopped)
if (command[1] == 'T') { if (foc->moving()) strcpy(reply,"M"); else strcpy(reply,"S"); boolReply=false; } else
// :Fp# Get mode
// Return: 0 for absolute
// 1 for pseudo absolute
if (command[1] == 'p') { if (!foc->isDcFocuser()) commandError=CE_0; } else
// :FI# Get full in position (in microns or steps)
// Returns: n#
if (toupper(command[1]) == 'I') { sprintf(reply,"%ld",(long)round(foc->getMin()/spm)); boolReply=false; } else
// :FM# Get max position (in microns or steps)
// Returns: n#
if (toupper(command[1]) == 'M') { sprintf(reply,"%ld",(long)round(foc->getMax()/spm)); boolReply=false; } else
// :Fe# Get focuser temperature differential
// Returns: n# temperature in deg. C
if (command[1] == 'e') { if (foc->getTcfEnable()) dtostrf(ambient.getTelescopeTemperature()-foc->getTcfT0(),3,1,reply); else dtostrf(0.0,3,1,reply); boolReply=false; } else
// :Ft# Get focuser temperature
// Returns: n# temperature in deg. C
if (command[1] == 't') { dtostrf(ambient.getTelescopeTemperature(),3,1,reply); boolReply=false; } else
// :Fu# Get focuser microns per step
// Returns: n.n#
if (command[1] == 'u') { dtostrf(1.0/foc->getStepsPerMicro(),7,5,reply); boolReply=false; } else
// :FB# Get focuser backlash amount (in steps or microns)
// Return: n#
if (toupper(command[1]) == 'B' && parameter[0] == 0) { sprintf(reply,"%ld",(long)round(foc->getBacklash()/spm)); boolReply=false; } else
// :FB[n]# Set focuser backlash amount (in steps or microns)
// Return: 0 on failure
// 1 on success
if (toupper(command[1]) == 'B') { long l = atol(parameter)*spm; if (!foc->setBacklash(l)) commandError=CE_PARAM_RANGE; } else
// :FC# Get focuser temperature compensation coefficient
// Return: n.n#
if (command[1] == 'C' && parameter[0] == 0) { dtostrf(foc->getTcfCoef(),7,5,reply); boolReply=false; } else
// :FC[sn.n]# Set focuser temperature compensation coefficient in um per deg. C (+ moves out as temperature falls)
// Return: 0 on failure
// 1 on success
if (command[1] == 'C') { f = atof(parameter); if (!foc->setTcfCoef(f)) commandError=CE_PARAM_RANGE; } else
// :Fc# Get focuser temperature compensation enable status
// Return: 0 if disabled
// 1 if enabled
if (command[1] == 'c' && parameter[0] == 0) { if (!foc->getTcfEnable()) commandError=CE_0; } else
// :Fc[n]# Enable/disable focuser temperature compensation where [n] = 0 or 1
// Return: 0 on failure
// 1 on success
if (command[1] == 'c' && parameter[1] == 0) { foc->setTcfEnable(parameter[0] != '0'); } else
// :FD# Get focuser temperature compensation deadband amount (in steps or microns)
// Return: n#
if (toupper(command[1]) == 'D' && parameter[0] == 0) { sprintf(reply,"%ld",(long)round(foc->getTcfDeadband()/spm)); boolReply=false; } else
// :FD[n]# Set focuser temperature compensation deadband amount (in steps or microns)
// Return: 0 on failure
// 1 on success
if (toupper(command[1]) == 'D') { long l = atol(parameter)*spm; if (!foc->setTcfDeadband(l)) commandError=CE_PARAM_RANGE; } else
// :FP# Get focuser DC Motor Power Level (in %)
// Returns: n#
// :FP[n]# Set focuser DC Motor Power Level (in %)
// Return: 0 on failure
// 1 on success
if (command[1] == 'P') {
if (foc->isDcFocuser()) {
if (parameter[0] == 0) {
sprintf(reply,"%d",(int)foc->getDcPower()); boolReply=false;
} else {
i=atol(parameter);
if (!foc->setDcPower(i)) commandError=CE_PARAM_RANGE;
}
} else commandError=CE_CMD_UNKNOWN;
} else
// :FQ# Stop the focuser
// Returns: Nothing
if (command[1] == 'Q') { foc->stopMove(); boolReply=false; } else
// :FF# Set focuser for fast motion (1mm/s)
// Returns: Nothing
if (command[1] == 'F') { foc->setMoveRate(1000); boolReply=false; } else
// :FS# Set focuser for slow motion (0.01mm/s)
// Returns: Nothing
if (command[1] == 'S' && parameter[0] == 0) { foc->setMoveRate(10); boolReply=false; } else
// :F[n]# Set focuser move rate, where n = 1 for finest, 2 for 0.01mm/second, 3 for 0.1mm/second, 4 for 1mm/second
// Returns: Nothing
if (command[1] >= '1' && command[1] <= '4') { int p[] = {1,10,100,1000}; foc->setMoveRate(p[command[1] - '1']); boolReply=false; } else
// :F+# Move focuser in (toward objective)
// Returns: Nothing
if (command[1] == '+') { foc->startMoveIn(); boolReply=false; } else
// :F-# Move focuser out (away from objective)
// Returns: Nothing
if (command[1] == '-') { foc->startMoveOut(); boolReply=false; } else
// :FG# Get focuser current position (in microns or steps)
// Returns: sn#
if (toupper(command[1]) == 'G') { sprintf(reply,"%ld",(long)round(foc->getPosition()/spm)); boolReply=false; } else
// :FR[sn]# Set focuser target position relative (in microns or steps)
// Returns: Nothing
if (toupper(command[1]) == 'R') { foc->relativeTarget((double)atol(parameter)*spm); boolReply=false; } else
// :FS[n]# Set focuser target position (in microns or steps)
// Return: 0 on failure
// 1 on success
if (toupper(command[1]) == 'S') { if (!foc->setTarget((double)atol(parameter)*spm)) commandError=CE_SLEW_ERR_IN_STANDBY; } else
// :FZ# Set focuser position as zero
// Returns: Nothing
if (command[1] == 'Z') { foc->setPosition(0); boolReply=false; } else
// :FH# Set focuser position as half-travel
// Returns: Nothing
if (command[1] == 'H') { foc->setPosition((foc->getMax()+foc->getMin())/2.0); boolReply=false; } else
// :Fh# Set focuser target position at half-travel
// Returns: Nothing
if (command[1] == 'h') { foc->setTarget((foc->getMax()+foc->getMin())/2.0); boolReply=false; } else commandError=CE_CMD_UNKNOWN;
} else commandError=CE_CMD_UNKNOWN;
} else
#endif
// G - Get Telescope Information
if (command[0] == 'G') {
// :GA# Get Telescope Altitude
// Returns: sDD*MM# or sDD*MM'SS# (based on precision setting)
// The current scope altitude
if (command[1] == 'A' && parameter[0] == 0) { getHor(&f,&f1); doubleToDms(reply,&f,false,true,precision); boolReply=false; } else
// :GB# Get Fastest Recommended Baud rate
// Returns: n
// The baud rate code
if (command[1] == 'B' && parameter[0] == 0) {
#ifdef HAL_SLOW_PROCESSOR
strcpy(reply,"4");
#else
strcpy(reply,"0");
#endif
boolReply=false;
supress_frame=true;
} else
// :Ga# Get Local Time in 12 hour format
// Returns: HH:MM:SS#
if (command[1] == 'a' && parameter[0] == 0) { LMT=timeRange(UT1-timeZone); if (LMT > 12.0) LMT-=12.0; doubleToHms(reply,&LMT,PM_HIGH); boolReply=false; } else
// :GC# Get the current local calendar date
// Returns: MM/DD/YY#
if (command[1] == 'C' && parameter[0] == 0) {
LMT=UT1-timeZone;
// correct for day moving forward/backward... this works for multipule days of up-time
double J=JD;
int y,m,d;
while (LMT >= 24.0) { LMT=LMT-24.0; J=J-1.0; }
if (LMT<0.0) { LMT=LMT+24.0; J=J+1.0; }
greg(J,&y,&m,&d); y-=2000; if (y >= 100) y-=100;
sprintf(reply,"%02d/%02d/%02d",m,d,y);
boolReply=false;
} else
// :Gc# Get the current local time format
// Returns: 24#
if (command[1] == 'c' && parameter[0] == 0) {
strcpy(reply,"24");
boolReply=false;
} else
// :GD# Get Telescope Declination
// Returns: sDD*MM# or sDD*MM:SS# (based on precision setting)
// :GDH# Get Telescope Declination
// Returns: sDD*MM:SS.SSSS# (high precision)
if (command[1] == 'D') {
#ifdef HAL_SLOW_PROCESSOR
if ((long)(millis()-_coord_t) > 500)
#else
if ((long)(millis()-_coord_t) > 50)
#endif
{
getEqu(&f,&f1,false);
#if TELESCOPE_COORDINATES == TOPOCENTRIC
observedPlaceToTopocentric(&f,&f1);
#endif
_ra=f/15.0; _dec=f1; _coord_t=millis();
}
if (parameter[0] == 0) {
doubleToDms(reply,&_dec,false,true,precision); boolReply=false;
} else
if ((parameter[0] == 'e' || parameter[0] == 'H') && parameter[1] == 0) {
doubleToDms(reply,&_dec,false,true,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :Gd# Get Currently Selected Target Declination
// Returns: sDD*MM# or sDD*MM:SS# (based on precision setting)
// :GdH# Get Currently Selected Target Declination
// Returns: sDD*MM:SS.SSS# (high precision)
if (command[1] == 'd') {
if (parameter[0] == 0) {
doubleToDms(reply,&origTargetDec,false,true,precision); boolReply=false;
} else
if ((parameter[0] == 'e' || parameter[0] == 'H') && parameter[1] == 0) {
doubleToDms(reply,&origTargetDec,false,true,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :GE# Get last command error numeric code
// Returns: CC#
if (command[1] == 'E' && parameter[0] == 0) {
CommandErrors e=CE_REPLY_UNKNOWN;
if (process_command == COMMAND_SERIAL_A) e=cmdA.lastError; else
#ifdef HAL_SERIAL_B_ENABLED
if (process_command == COMMAND_SERIAL_B) e=cmdB.lastError; else
#endif
#ifdef HAL_SERIAL_C_ENABLED
if (process_command == COMMAND_SERIAL_C) e=cmdC.lastError; else
#endif
#ifdef HAL_SERIAL_D_ENABLED
if (process_command == COMMAND_SERIAL_D) e=cmdD.lastError; else
#endif
#ifdef HAL_SERIAL_E_ENABLED
if (process_command == COMMAND_SERIAL_E) e=cmdE.lastError; else
#endif
#if ST4_HAND_CONTROL == ON && ST4_INTERFACE != OFF
if (process_command == COMMAND_SERIAL_ST4) e=cmdST4.lastError; else
#endif
if (process_command == COMMAND_SERIAL_X) e=cmdX.lastError;
sprintf(reply,"%02d",e);
commandError=CE_NULL;
boolReply=false;
} else
// :GG# Get UTC offset time, the number of decimal hours to add to local time to convert to UTC
// Returns: sHH#
if (command[1] == 'G' && parameter[0] == 0) {
timeZoneToHM(reply,timeZone);
boolReply=false;
} else
// :Gg# Get Current Site Longitude, east is negative
// Returns: sDDD*MM#
// :GgH# Get current site Longitude
// Returns: sDD*MM:SS.SSS# (high precision)
if (command[1] == 'g') {
if (parameter[0] == 0) {
doubleToDms(reply,&longitude,true,true,PM_LOW); boolReply=false;
} else
if (parameter[0] == 'H' && parameter[1] == 0) {
doubleToDms(reply,&longitude,true,true,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :Gh# Get Horizon Limit, the minimum elevation of the mount relative to the horizon
// Returns: sDD*#
if (command[1] == 'h' && parameter[0] == 0) { sprintf(reply,"%+02d*",minAlt); boolReply=false; } else
// :GL# Get Local Time in 24 hour format
// Returns: HH:MM:SS#
// :GLH# Get Local Time in 24 hour format
// Returns: HH:MM:SS.SSSS# (high precision)
// On devices with single precision fp several days up-time will cause loss of precision as additional mantissa digits are needed to represent hours
// Devices with double precision fp are limitated by sidereal clock overflow which takes 249 days
if (command[1] == 'L') {
LMT=timeRange(UT1-timeZone);
if ( parameter[0] == 0) {
doubleToHms(reply,&LMT,PM_HIGH); boolReply=false;
} else
if ((parameter[0] == 'a' || parameter[0] == 'H') && parameter[1] == 0) {
doubleToHms(reply,&LMT,PM_HIGHEST); boolReply=false;
}
}
else
// :GM# Get site 1 name
// :GN# Get site 2 name
// :GO# Get site 3 name
// :GP# Get site 4 name
// Returns: s#
if ((command[1] == 'M' || command[1] == 'N' || command[1] == 'O' || command[1] == 'P') && parameter[0] == 0) {
i=command[1]-'M';
nv.readString(EE_sites+i*25+9,reply);
if (reply[0] == 0) { strcat(reply,"None"); }
boolReply=false;
} else
// :Gm# Gets the meridian pier-side
// Returns: E#, W#, N# (none/parked)
if (command[1] == 'm' && parameter[0] == 0) {
reply[0]='?'; reply[1]=0;
if (getInstrPierSide() == PierSideNone) reply[0]='N';
if (getInstrPierSide() == PierSideEast) reply[0]='E';
if (getInstrPierSide() == PierSideWest) reply[0]='W';
boolReply=false; } else
// :Go# Get Overhead Limit
// Returns: DD*#
// The highest elevation above the horizon that the telescope will goto
if (command[1] == 'o' && parameter[0] == 0) { sprintf(reply,"%02d*",maxAlt); boolReply=false; } else
// :GR# Get Telescope RA
// Returns: HH:MM.T# or HH:MM:SS# (based on precision setting)
// :GRH# Get Telescope RA High Precision
// Returns: HH:MM:SS.SSSS#
if (command[1] == 'R') {
#ifdef HAL_SLOW_PROCESSOR
if ((long)(millis()-_coord_t) > 500)
#else
if ((long)(millis()-_coord_t) > 50)
#endif
{
getEqu(&f,&f1,false);
#if TELESCOPE_COORDINATES == TOPOCENTRIC
observedPlaceToTopocentric(&f,&f1);
#endif
_ra=f/15.0; _dec=f1; _coord_t=millis();
}
if (parameter[0] == 0) {
doubleToHms(reply,&_ra,precision); boolReply=false;
} else
if ((parameter[0] == 'a' || parameter[0] == 'H') && parameter[1] == 0) {
doubleToHms(reply,&_ra,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :Gr# Get current/target object RA
// Returns: HH:MM.T# or HH:MM:SS (based on precision setting)
// :GrH# Get Telescope RA
// Returns: HH:MM:SS.SSSS# (high precision)
if (command[1] == 'r') {
f=origTargetRA; f/=15.0;
if (parameter[0] == 0) {
doubleToHms(reply,&f,precision); boolReply=false;
} else
if ((parameter[0] == 'a' || parameter[0] == 'H') && parameter[1] == 0) {
doubleToHms(reply,&f,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :GS# Get the Sidereal Time as sexagesimal value in 24 hour format
// Returns: HH:MM:SS#
// :GSa# Get the Sidereal Time as sexagesimal value in 24 hour format, with high precision
// Returns HH:MM:SS.ss#
if (command[1] == 'S') {
f = LST();
if (parameter[0] == 0) {
doubleToHms(reply,&f,PM_HIGH); boolReply=false;
} else
if (parameter[0] == 'a' && parameter[1] == 0) {
doubleToHms(reply,&f,PM_HIGHEST); boolReply=false;
}
} else
// :GT# Get tracking rate, 0.0 unless TrackingSidereal
// Returns: n.n# (OnStep returns more decimal places than LX200 standard)
if (command[1] == 'T' && parameter[0] == 0) {
char temp[10];
f=getTrackingRate60Hz();
dtostrf(f,0,5,temp);
strcpy(reply,temp);
boolReply=false;
} else
// :Gt# Get current site Latitude, positive for North latitudes
// Returns: sDD*MM#
// :GtH# Get current site Latitude, positive for North latitudes
// Returns: sDD*MM:SS.SSS# (high precision)
if (command[1] == 't') {
if (parameter[0] == 0) {
doubleToDms(reply,&latitude,false,true,PM_LOW); boolReply=false;
} else
if (parameter[0] == 'H' && parameter[1] == 0) {
doubleToDms(reply,&latitude,false,true,PM_HIGHEST); boolReply=false;
} else commandError=CE_CMD_UNKNOWN;
} else
// :GU# Get telescope Status
// Returns: s#
if (command[1] == 'U' && parameter[0] == 0) {
i=0;
if (trackingState != TrackingSidereal &&
!(trackingState == TrackingMoveTo && lastTrackingState == TrackingSidereal)) reply[i++]='n'; // [n]ot tracking
if (trackingState != TrackingMoveTo && !trackingSyncInProgress()) reply[i++]='N'; // [N]o goto
const char *parkStatusCh = "pIPF"; reply[i++]=parkStatusCh[parkStatus]; // not [p]arked, parking [I]n-progress, [P]arked, Park [F]ailed
if (pecRecorded) reply[i++]='R'; // PEC data has been [R]ecorded
if (syncToEncodersOnly) reply[i++]='e'; // sync to [e]ncoders only
if (atHome) reply[i++]='H'; // at [H]ome
if (ppsSynced) reply[i++]='S'; // PPS [S]ync
if (isPulseGuiding()) reply[i++]='G'; // pulse [G]uide active
if ((guideDirAxis1 || guideDirAxis2) && !isPulseGuiding())
reply[i++]='g'; // [g]uide active
#if MOUNT_TYPE != ALTAZM
if (rateCompensation == RC_REFR_RA) { reply[i++]='r'; reply[i++]='s'; } // [r]efr enabled [s]ingle axis
if (rateCompensation == RC_REFR_BOTH) { reply[i++]='r'; } // [r]efr enabled
if (rateCompensation == RC_FULL_RA) { reply[i++]='t'; reply[i++]='s'; } // on[t]rack enabled [s]ingle axis
if (rateCompensation == RC_FULL_BOTH) { reply[i++]='t'; } // on[t]rack enabled
#endif
if (waitingHome) reply[i++]='w'; // [w]aiting at home
if (pauseHome) reply[i++]='u'; // pa[u]se at home enabled?
if (soundEnabled) reply[i++]='z'; // bu[z]zer enabled?
#if MOUNT_TYPE == GEM
if (autoMeridianFlip) reply[i++]='a'; // [a]uto meridian flip
#endif
#if AXIS1_PEC == ON
const char *pch = PECStatusStringAlt; reply[i++]=pch[pecStatus]; // PEC Status one of "/,~;^" (/)gnore, ready to (,)lay, (~)laying, ready to (;)ecord, (^)ecording
#endif
// provide mount type
#if MOUNT_TYPE == GEM
reply[i++]='E';
#elif MOUNT_TYPE == FORK
reply[i++]='K';
#elif MOUNT_TYPE == ALTAZM
reply[i++]='A';
#endif
// provide pier side info.
if (getInstrPierSide() == PierSideNone) reply[i++]='o'; else // pier side n[o]ne
if (getInstrPierSide() == PierSideEast) reply[i++]='T'; else // pier side eas[T]
if (getInstrPierSide() == PierSideWest) reply[i++]='W'; // pier side [W]est
// provide pulse-guide rate
reply[i++]='0'+getPulseGuideRate();
// provide guide rate
if (currentGuideRate == -1) reply[i++]='9'; else reply[i++]='0'+currentGuideRate;
// provide general error
reply[i++]='0'+generalError;
reply[i++]=0;
boolReply=false;
} else
// :Gu# Get bit packed telescope status
// Returns: s#
if (command[1] == 'u' && parameter[0] == 0) {
memset(reply,(char)0b10000000,9);
if (trackingState != TrackingSidereal &&
!(trackingState == TrackingMoveTo && lastTrackingState == TrackingSidereal)) reply[0]|=0b10000001; // Not tracking
if (trackingState != TrackingMoveTo && !trackingSyncInProgress()) reply[0]|=0b10000010; // No goto
if (ppsSynced) reply[0]|=0b10000100; // PPS sync
if (isPulseGuiding()) reply[0]|=0b10001000; // pulse guide active
#if MOUNT_TYPE != ALTAZM
if (rateCompensation == RC_REFR_RA) reply[0]|=0b11010000; // Refr enabled Single axis
if (rateCompensation == RC_REFR_BOTH) reply[0]|=0b10010000; // Refr enabled
if (rateCompensation == RC_FULL_RA) reply[0]|=0b11100000; // OnTrack enabled Single axis
if (rateCompensation == RC_FULL_BOTH) reply[0]|=0b10100000; // OnTrack enabled
#endif
if (rateCompensation == RC_NONE) {
double tr=getTrackingRate60Hz();
if (fabs(tr-57.900)<0.001) reply[1]|=0b10000001; else // Lunar rate selected
if (fabs(tr-60.000)<0.001) reply[1]|=0b10000010; else // Solar rate selected
if (fabs(tr-60.136)<0.001) reply[1]|=0b10000011; // King rate selected
}
if (syncToEncodersOnly) reply[1]|=0b10000100; // sync to encoders only
if ((guideDirAxis1 || guideDirAxis2) && !isPulseGuiding())
reply[1]|=0b10001000; // guide active
if (atHome) reply[2]|=0b10000001; // At home
if (waitingHome) reply[2]|=0b10000010; // Waiting at home
if (pauseHome) reply[2]|=0b10000100; // Pause at home enabled?
if (soundEnabled) reply[2]|=0b10001000; // Buzzer enabled?
#if MOUNT_TYPE == GEM
if (autoMeridianFlip) reply[2]|=0b10010000; // Auto meridian flip
#endif
if (pecRecorded) reply[2]|=0b10100000; // PEC data has been recorded
// provide mount type
#if MOUNT_TYPE == GEM
reply[3]|=0b10000001; // GEM
#elif MOUNT_TYPE == FORK
reply[3]|=0b10000010; // FORK
#elif MOUNT_TYPE == ALTAZM
reply[3]|=0b10001000; // ALTAZM
#endif
// provide pier side info.
if (getInstrPierSide() == PierSideNone) reply[3]|=0b10010000; else // Pier side none
if (getInstrPierSide() == PierSideEast) reply[3]|=0b10100000; else // Pier side east
if (getInstrPierSide() == PierSideWest) reply[3]|=0b11000000; // Pier side west
#if AXIS1_PEC == ON
reply[4]=pecStatus|0b10000000; // PEC status: 0 ignore, 1 ready play, 2 playing, 3 ready record, 4 recording
#endif
reply[5]=parkStatus|0b10000000; // Park status: 0 not parked, 1 parking in-progress, 2 parked, 3 park failed
reply[6]=getPulseGuideRate()|0b10000000; // Pulse-guide rate
if (currentGuideRate == -1) reply[7]=9|0b10000000; else reply[7]=currentGuideRate|0b10000000; // Guide rate
reply[8]=generalError|0b10000000; // General error
reply[9]=0;
boolReply=false;
} else
// :GVD# Get Telescope Firmware Date
// Returns: MTH DD YYYY#
// :GVM# General Message
// Returns: s# (where s is a string up to 16 chars)
// :GVN# Get Telescope Firmware Number
// Returns: M.mp#
// :GVP# Get Telescope Product Name
// Returns: s#
// :GVT# Get Telescope Firmware Time
// Returns: HH:MM:SS#
if (command[1] == 'V') {
if (parameter[1] == 0) {
if (parameter[0] == 'D') strcpy(reply,FirmwareDate); else
if (parameter[0] == 'M') sprintf(reply,"OnStep %i.%i%s",FirmwareVersionMajor,FirmwareVersionMinor,FirmwareVersionPatch); else
if (parameter[0] == 'N') sprintf(reply,"%i.%i%s",FirmwareVersionMajor,FirmwareVersionMinor,FirmwareVersionPatch); else
if (parameter[0] == 'P') strcpy(reply,FirmwareName); else
if (parameter[0] == 'T') strcpy(reply,FirmwareTime); else commandError=CE_CMD_UNKNOWN;
} else commandError=CE_CMD_UNKNOWN;
boolReply=false;
} else
// :GW# Get alignment status
// Returns: [mount][tracking][alignment]#
// Where mount: A-AltAzm, P-Fork, G-GEM
// tracking: T-tracking, N-not tracking
// alignment: 0-needs alignment, 1-one star aligned, 2-two star aligned, >= 3-three star aligned
if (command[1] == 'W' && parameter[0] == 0) {
// mount type
#if MOUNT_TYPE == GEM
reply[0]='G';
#elif MOUNT_TYPE == FORK
reply[0]='P';
#elif MOUNT_TYPE == ALTAZM
reply[0]='A';
#endif
// tracking
if (trackingState != TrackingSidereal || trackingSyncInProgress()) reply[1]='N'; else reply[1]='T';
// align status
i=alignThisStar-1; if (i<0) i=0; if (i > 3) i=3; reply[2]='0'+i;
reply[3]=0;
boolReply=false;
} else
// :GX[II]# Get OnStep value where II is the numeric index
// Returns: n (numeric value, possibly floating point)
if (command[1] == 'X') {
if (parameter[2] == (char)0) {
if (parameter[0] == '0') { // 0n: Align Model
static int star=0;
switch (parameter[1]) {
case '0': sprintf(reply,"%ld",(long)(Align.ax1Cor*3600.0)); boolReply=false; break; // ax1Cor
case '1': sprintf(reply,"%ld",(long)(Align.ax2Cor*3600.0)); boolReply=false; break; // ax2Cor
case '2': sprintf(reply,"%ld",(long)(Align.altCor*3600.0)); boolReply=false; break; // altCor
case '3': sprintf(reply,"%ld",(long)(Align.azmCor*3600.0)); boolReply=false; break; // azmCor
case '4': sprintf(reply,"%ld",(long)(Align.doCor*3600.0)); boolReply=false; break; // doCor
case '5': sprintf(reply,"%ld",(long)(Align.pdCor*3600.0)); boolReply=false; break; // pdCor
#if MOUNT_TYPE == FORK || MOUNT_TYPE == ALTAZM
case '6': sprintf(reply,"%ld",(long)(Align.dfCor*3600.0)); boolReply=false; break; // ffCor
case '7': sprintf(reply,"%ld",(long)(0)); boolReply=false; break; // dfCor
#else
case '6': sprintf(reply,"%ld",(long)(0)); boolReply=false; break; // ffCor
case '7': sprintf(reply,"%ld",(long)(Align.dfCor*3600.0)); boolReply=false; break; // dfCor
#endif
case '8': sprintf(reply,"%ld",(long)(Align.tfCor*3600.0)); boolReply=false; break; // tfCor
// Number of stars, reset to first star
case '9': { int n=0; if (alignThisStar > alignNumStars) n=alignNumStars; sprintf(reply,"%ld",(long)(n)); star=0; boolReply=false; } break;
case 'A': { double f=(Align.actual[star].ha*Rad)/15.0; doubleToHms(reply,&f,PM_HIGH); boolReply=false; } break; // Star #n HA
case 'B': { double f=(Align.actual[star].dec*Rad); doubleToDms(reply,&f,false,true,precision); boolReply=false; } break; // Star #n Dec
case 'C': { double f=(Align.mount[star].ha*Rad)/15.0; doubleToHms(reply,&f,PM_HIGH); boolReply=false; } break; // Mount #n HA
case 'D': { double f=(Align.mount[star].dec*Rad); doubleToDms(reply,&f,false,true,precision); boolReply=false; } break; // Mount #n Dec
case 'E': sprintf(reply,"%ld",(long)(Align.mount[star].side)); star++; boolReply=false; break; // Mount PierSide (and increment n)
default: commandError=CE_CMD_UNKNOWN;
}
} else
if (parameter[0] == '4') { // 4n: Encoder
switch (parameter[1]) {
case '0': getEnc(&f,&f1); doubleToDms(reply,&f,true,true,precision); boolReply=false; break; // Get formatted absolute Axis1 angle
case '1': getEnc(&f,&f1); doubleToDms(reply,&f1,true,true,precision); boolReply=false; break; // Get formatted absolute Axis2 angle
case '2': getEnc(&f,&f1); dtostrf(f,0,6,reply); boolReply=false; break; // Get absolute Axis1 angle in degrees
case '3': getEnc(&f,&f1); dtostrf(f1,0,6,reply); boolReply=false; break; // Get absolute Axis2 angle in degrees
case '9': cli(); dtostrf(trackingTimerRateAxis1,1,8,reply); sei(); boolReply=false; break; // Get current tracking rate
default: commandError=CE_CMD_UNKNOWN;
}
} else
if (parameter[0] == '8') { // 8n: Date/Time
switch (parameter[1]) {
case '0': f=timeRange(UT1); doubleToHms(reply,&f,PM_HIGH); boolReply=false; break; // UTC time
case '1': f1=JD; f=UT1; while (f >= 24.0) { f-=24.0; f1+=1; } while (f < 0.0) { f+=24.0; f1-=1; } greg(f1,&i2,&i,&i1); i2=(i2/99.99999-floor(i2/99.99999))*100; sprintf(reply,"%02d/%02d/%02d",i,i1,i2); boolReply=false; break; // UTC date
case '9': if (dateWasSet && timeWasSet) commandError=CE_0; break; // Get Date/Time status, returns 0=known or 1=unknown
default: commandError=CE_CMD_UNKNOWN;
}
} else
if (parameter[0] == '9') { // 9n: Misc.
switch (parameter[1]) {
case '0': dtostrf(guideRates[currentPulseGuideRate]/15.0,2,2,reply); boolReply=false; break;// pulse-guide rate
case '1': sprintf(reply,"%i",pecValue); boolReply=false; break; // pec analog value
case '2': dtostrf(maxRate/16.0,3,3,reply); boolReply=false; break; // MaxRate (current)
case '3': dtostrf((double)maxRateBaseActual,3,3,reply); boolReply=false; break; // maxRateBaseActual (default)
case '4': if (meridianFlip == MeridianFlipNever) { sprintf(reply,"%d N",getInstrPierSide()); } else { sprintf(reply,"%d",getInstrPierSide()); } boolReply=false; break; // pierSide (N if never)
case '5': sprintf(reply,"%i",(int)autoMeridianFlip); boolReply=false; break; // autoMeridianFlip
case '6': // preferred pier side
if (preferredPierSide == EAST) strcpy(reply,"E"); else
if (preferredPierSide == WEST) strcpy(reply,"W"); else strcpy(reply,"B");
boolReply=false; break;
case '7': dtostrf(slewSpeed,3,1,reply); boolReply=false; break; // slew speed
case '8':
#if ROTATOR == ON
#if MOUNT_TYPE == ALTAZM
strcpy(reply,"D");
#else
strcpy(reply,"R");
#endif
#else
strcpy(reply,"N");
#endif
boolReply=false; break; // rotator availablity 2=rotate/derotate, 1=rotate, 0=off
case '9': dtostrf(maxRateLowerLimit()/16.0,3,3,reply); boolReply=false; break; // MaxRate (fastest/lowest)
case 'A': dtostrf(ambient.getTemperature(),3,1,reply); boolReply=false; break; // temperature in deg. C
case 'B': dtostrf(ambient.getPressure(),3,1,reply); boolReply=false; break; // pressure in mb
case 'C': dtostrf(ambient.getHumidity(),3,1,reply); boolReply=false; break; // relative humidity in %
case 'D': dtostrf(ambient.getAltitude(),3,1,reply); boolReply=false; break; // altitude in meters
case 'E': dtostrf(ambient.getDewPoint(),3,1,reply); boolReply=false; break; // dew point in deg. C
case 'F': { float t=HAL_MCU_Temperature(); if (t > -999) { dtostrf(t,1,0,reply); boolReply=false; } else commandError=CE_0; } break; // internal MCU temperature in deg. C
default: commandError=CE_CMD_UNKNOWN;
}
} else
if (parameter[0] == 'A') { // :GXAn: Get axis settings
int p=parameter[1]-'1';
if (p >= 0 && p <= 5) {
uint8_t state=nv.read(EE_settingsRuntime);
// check for all axes set to revert
if (state&1) {
// check for this axis set to revert
if (!(state&(1<<(p+1)))) {
if (p == 0 || p == 1 || (p == 2 && ROTATOR == ON) || (p == 3 && FOCUSER1 == ON) || (p == 4 && FOCUSER2 == ON)) {
axisSettings axis;
nv.readBytes(EE_settingsAxis1+(p*17),(byte*)&axis,sizeof(axis));
sprintf(reply,"%ld.%03ld,%d,%d,%d,%d,%d",(long)axis.stepsPerMeasure,(long)(axis.stepsPerMeasure*1000)%1000,axis.microsteps,axis.IRUN,axis.reverse,axis.min,axis.max);
boolReply=false;
} else commandError=CE_0;
} else commandError=CE_0;
} else commandError=CE_0;
} else commandError=CE_CMD_UNKNOWN;
} else
if (parameter[0] == 'U') { // Un: Get stepper driver statUs
switch (parameter[1]) {
case '1':
#if (AXIS1_DRIVER_STATUS == TMC_SPI)
tmcAxis1.refresh_DRVSTATUS();
strcat(reply,tmcAxis1.get_DRVSTATUS_STST() ? "ST," : ","); // Standstill
strcat(reply,tmcAxis1.get_DRVSTATUS_OLa() ? "OA," : ","); // Open Load A
strcat(reply,tmcAxis1.get_DRVSTATUS_OLb() ? "OB," : ","); // Open Load B
strcat(reply,tmcAxis1.get_DRVSTATUS_S2Ga() ? "GA," : ","); // Short to Ground A
strcat(reply,tmcAxis1.get_DRVSTATUS_S2Gb() ? "GB," : ","); // Short to Ground B
strcat(reply,tmcAxis1.get_DRVSTATUS_OT() ? "OT," : ","); // Overtemp Shutdown 150C
strcat(reply,tmcAxis1.get_DRVSTATUS_OTPW() ? "PW" : ""); // Overtemp Pre-warning 120C
boolReply=false;
#else
commandError=CE_0;
#endif
break;
case '2':
#if (AXIS2_DRIVER_STATUS == TMC_SPI)
tmcAxis2.refresh_DRVSTATUS();
strcat(reply,tmcAxis2.get_DRVSTATUS_STST() ? "ST," : ","); // Standstill
strcat(reply,tmcAxis2.get_DRVSTATUS_OLa() ? "OA," : ","); // Open Load A
strcat(reply,tmcAxis2.get_DRVSTATUS_OLb() ? "OB," : ","); // Open Load B
strcat(reply,tmcAxis2.get_DRVSTATUS_S2Ga() ? "GA," : ","); // Short to Ground A
strcat(reply,tmcAxis2.get_DRVSTATUS_S2Gb() ? "GB," : ","); // Short to Ground B
strcat(reply,tmcAxis2.get_DRVSTATUS_OT() ? "OT," : ","); // Overtemp Shutdown 150C
strcat(reply,tmcAxis2.get_DRVSTATUS_OTPW() ? "PW" : ""); // Overtemp Pre-warning 120C
boolReply=false;
#else
commandError=CE_0;
#endif
break;
default: commandError=CE_CMD_UNKNOWN;
}
} else
if (parameter[0] == 'E') { // En: Get settings