Instrument Neutral Distributed Interface INDI 2.2.5
deepskydad_af3.cpp
Go to the documentation of this file.
1/*
2 Deep Sky Dad AF3 focuser
3
4 Copyright (C) 2019 Pavle Gartner
5
6 Based on Moonlite driver.
7 Copyright (C) 2013-2019 Jasem Mutlaq ([email protected])
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23*/
24
25#include "deepskydad_af3.h"
26
27#include "indicom.h"
28
29#include <cmath>
30#include <cstring>
31#include <memory>
32
33#include <termios.h>
34#include <unistd.h>
35
36static std::unique_ptr<DeepSkyDadAF3> deepSkyDadAf3(new DeepSkyDadAF3());
37
43
45{
47
48 // Step Mode
49 StepModeSP[S256].fill("S256", "1/256 Step", ISS_OFF);
50 StepModeSP[S128].fill("S128", "1/128 Step", ISS_OFF);
51 StepModeSP[S64].fill("S64", "1/64 Step", ISS_OFF);
52 StepModeSP[S32].fill("S32", "1/32 Step", ISS_OFF);
53 StepModeSP[S16].fill("S16", "1/16 Step", ISS_OFF);
54 StepModeSP[S8].fill("S8", "1/8 Step", ISS_OFF);
55 StepModeSP[S4].fill("S4", "1/4 Step", ISS_OFF);
56 StepModeSP[S2].fill("S2", "1/2 Step", ISS_OFF);
57 StepModeSP[S1].fill("S1", "Full Step", ISS_OFF);
58 StepModeSP.fill(getDeviceName(), "Step Mode", "", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0,
59 IPS_IDLE);
60
61 // Speed Mode
62 SpeedModeSP[VERY_SLOW].fill("VERY_SLOW", "Very slow", ISS_OFF);
63 SpeedModeSP[SLOW].fill("SLOW", "Slow", ISS_OFF);
64 SpeedModeSP[MEDIUM].fill("MEDIUM", "Medium", ISS_OFF);
65 SpeedModeSP[FAST].fill("FAST", "Fast", ISS_OFF);
66 SpeedModeSP[VERY_FAST].fill("VERY_FAST", "Very fast", ISS_OFF);
67 SpeedModeSP.fill(getDeviceName(), "Speed Mode", "", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0,
68 IPS_IDLE);
69
70 /* Relative and absolute movement */
71 FocusRelPosNP[0].setMin(0.);
72 FocusRelPosNP[0].setMax(50000.);
73 FocusRelPosNP[0].setValue(0.);
74 FocusRelPosNP[0].setStep(10.);
75
76 FocusAbsPosNP[0].setMin(0.);
77 FocusAbsPosNP[0].setMax(1000000.);
78 FocusAbsPosNP[0].setValue(50000.);
79 FocusAbsPosNP[0].setStep(5000.);
80
81 FocusMaxPosNP[0].setMin(0.);
82 FocusMaxPosNP[0].setMax(1000000.);
83 FocusMaxPosNP[0].setValue(1000000.);
84 FocusMaxPosNP[0].setStep(5000.);
85
86 FocusSyncNP[0].setMin(0.);
87 FocusSyncNP[0].setMax(1000000.);
88 FocusSyncNP[0].setValue(50000.);
89 FocusSyncNP[0].setStep(5000.);
90
91 FocusBacklashNP[0].setMin(-1000);
92 FocusBacklashNP[0].setMax(1000);
93 FocusBacklashNP[0].setStep(1);
94 FocusBacklashNP[0].setValue(0);
95
96 // Settle buffer
97 SettleBufferNP[0].fill("SETTLE_BUFFER", "Period (ms)", "%5.0f", 0, 99999, 100, 0);
98 SettleBufferNP.fill(getDeviceName(), "FOCUS_SETTLE_BUFFER", "Settle buffer",
100
101 // Motor move multiplier
102 MoveCurrentMultiplierNP[0].fill("MOTOR_MOVE_MULTIPLIER", "%", "%3.0f", 1, 100, 1, 90);
103 MoveCurrentMultiplierNP.fill(getDeviceName(), "FOCUS_MMM",
104 "Move current multiplier",
106
107 // Motor hold multiplier
108 HoldCurrentMultiplierNP[0].fill("MOTOR_HOLD_MULTIPLIER", "%", "%3.0f", 1, 100, 1, 40);
109 HoldCurrentMultiplierNP.fill(getDeviceName(), "FOCUS_MHM",
110 "Hold current multiplier",
112
113 // Focuser temperature
114 TemperatureNP[0].fill("TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
115 TemperatureNP.fill(getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
117
120
121 return true;
122}
123
125{
127
128 if (isConnected())
129 {
130 defineProperty(StepModeSP);
131 defineProperty(SpeedModeSP);
132 defineProperty(SettleBufferNP);
133 defineProperty(MoveCurrentMultiplierNP);
134 defineProperty(HoldCurrentMultiplierNP);
135 defineProperty(TemperatureNP);
136
137 GetFocusParams();
138
139 LOG_INFO("deepSkyDadAf3 parameters updated, focuser ready for use.");
140 }
141 else
142 {
143 deleteProperty(StepModeSP);
144 deleteProperty(SpeedModeSP);
145 deleteProperty(SettleBufferNP);
146 deleteProperty(MoveCurrentMultiplierNP);
147 deleteProperty(HoldCurrentMultiplierNP);
148 deleteProperty(TemperatureNP);
149 }
150
151 return true;
152}
153
155{
156 if (Ack())
157 {
158 LOG_INFO("deepSkyDadAf3 is online. Getting focus parameters...");
159 return true;
160 }
161
162 LOG_INFO(
163 "Error retrieving data from deepSkyDadAf3, please ensure deepSkyDadAf3 controller is powered and the port is correct.");
164 return false;
165}
166
168{
169 return "Deep Sky Dad AF3";
170}
171
172bool DeepSkyDadAF3::Ack()
173{
174 sleep(2);
175
176 char res[DSD_RES] = {0};
177 if (!sendCommand("[GPOS]", res) && !sendCommand("[GPOS]", res)) //try twice
178 {
179 LOG_ERROR("ACK - getPosition failed");
180 return false;
181 }
182
183 int32_t pos;
184 int rc = sscanf(res, "(%d)", &pos);
185
186 if (rc <= 0)
187 {
188 LOG_ERROR("ACK - getPosition failed");
189 return false;
190 }
191
192 return true;
193}
194
195bool DeepSkyDadAF3::readStepMode()
196{
197 char res[DSD_RES] = {0};
198
199 if (sendCommand("[GSTP]", res) == false)
200 return false;
201
202 if (strcmp(res, "(1)") == 0)
203 StepModeSP[S1].setState(ISS_ON);
204 else if (strcmp(res, "(2)") == 0)
205 StepModeSP[S2].setState(ISS_ON);
206 else if (strcmp(res, "(4)") == 0)
207 StepModeSP[S4].setState(ISS_ON);
208 else if (strcmp(res, "(8)") == 0)
209 StepModeSP[S8].setState(ISS_ON);
210 else if (strcmp(res, "(16)") == 0)
211 StepModeSP[S16].setState(ISS_ON);
212 else if (strcmp(res, "(32)") == 0)
213 StepModeSP[S32].setState(ISS_ON);
214 else if (strcmp(res, "(64)") == 0)
215 StepModeSP[S64].setState(ISS_ON);
216 else if (strcmp(res, "(128)") == 0)
217 StepModeSP[S128].setState(ISS_ON);
218 else if (strcmp(res, "(256)") == 0)
219 StepModeSP[S256].setState(ISS_ON);
220 else
221 {
222 LOGF_ERROR("Unknown error: focuser step value (%s)", res);
223 return false;
224 }
225
226 StepModeSP.setState(IPS_OK);
227 return true;
228}
229
230bool DeepSkyDadAF3::readSpeedMode()
231{
232 char res[DSD_RES] = {0};
233
234 if (sendCommand("[GSPD]", res) == false)
235 return false;
236
237 if (strcmp(res, "(1)") == 0)
238 SpeedModeSP[VERY_SLOW].setState(ISS_ON);
239 else if (strcmp(res, "(2)") == 0)
240 SpeedModeSP[SLOW].setState(ISS_ON);
241 else if (strcmp(res, "(3)") == 0)
242 SpeedModeSP[MEDIUM].setState(ISS_ON);
243 else if (strcmp(res, "(4)") == 0)
244 SpeedModeSP[FAST].setState(ISS_ON);
245 else if (strcmp(res, "(5)") == 0)
246 SpeedModeSP[VERY_FAST].setState(ISS_ON);
247 else
248 {
249 LOGF_ERROR("Unknown error: focuser speed value (%s)", res);
250 return false;
251 }
252
253 SpeedModeSP.setState(IPS_OK);
254 return true;
255}
256
257bool DeepSkyDadAF3::readPosition()
258{
259 char res[DSD_RES] = {0};
260
261 if (sendCommand("[GPOS]", res) == false)
262 return false;
263
264 int32_t pos;
265 int rc = sscanf(res, "(%d)", &pos);
266
267 if (rc > 0)
268 FocusAbsPosNP[0].setValue(pos);
269 else
270 {
271 LOGF_ERROR("Unknown error: focuser position value (%s)", res);
272 return false;
273 }
274
275 return true;
276}
277
278bool DeepSkyDadAF3::readMaxMovement()
279{
280 char res[DSD_RES] = {0};
281
282 if (sendCommand("[GMXM]", res) == false)
283 return false;
284
285 uint32_t steps = 0;
286 int rc = sscanf(res, "(%d)", &steps);
287 if (rc > 0)
288 {
289 FocusMaxPosNP[0].setValue(steps);
291 }
292 else
293 {
294 LOGF_ERROR("Unknown error: maximum movement value (%s)", res);
295 return false;
296 }
297
298 return true;
299}
300
301bool DeepSkyDadAF3::readMaxPosition()
302{
303 char res[DSD_RES] = {0};
304
305 if (sendCommand("[GMXP]", res) == false)
306 return false;
307
308 uint32_t steps = 0;
309 int rc = sscanf(res, "(%d)", &steps);
310 if (rc > 0)
311 {
312 FocusMaxPosNP[0].setValue(steps);
314 }
315 else
316 {
317 LOGF_ERROR("Unknown error: maximum position value (%s)", res);
318 return false;
319 }
320
321 return true;
322}
323
324bool DeepSkyDadAF3::readSettleBuffer()
325{
326 char res[DSD_RES] = {0};
327
328 if (sendCommand("[GBUF]", res) == false)
329 return false;
330
331 uint32_t settleBuffer = 0;
332 int rc = sscanf(res, "(%d)", &settleBuffer);
333 if (rc > 0)
334 {
335 SettleBufferNP[0].setValue(settleBuffer);
336 SettleBufferNP.setState(settleBuffer > 0 ? IPS_OK : IPS_IDLE);
337 }
338 else
339 {
340 LOGF_ERROR("Unknown error: settle buffer value (%s)", res);
341 return false;
342 }
343
344 return true;
345}
346
347bool DeepSkyDadAF3::readMoveCurrentMultiplier()
348{
349 char res[DSD_RES] = {0};
350
351 if (sendCommand("[GMMM]", res) == false)
352 return false;
353
354 uint32_t mcm = 0;
355 int rc = sscanf(res, "(%d)", &mcm);
356 if (rc > 0)
357 {
358 MoveCurrentMultiplierNP[0].setValue(mcm);
359 MoveCurrentMultiplierNP.setState(IPS_OK);
360 }
361 else
362 {
363 LOGF_ERROR("Unknown error: move current multiplier value (%s)", res);
364 return false;
365 }
366
367 return true;
368}
369
370bool DeepSkyDadAF3::readHoldCurrentMultiplier()
371{
372 char res[DSD_RES] = {0};
373
374 if (sendCommand("[GMHM]", res) == false)
375 return false;
376
377 uint32_t hcm = 0;
378 int rc = sscanf(res, "(%d)", &hcm);
379 if (rc > 0)
380 {
381 HoldCurrentMultiplierNP[0].setValue(hcm);
382 HoldCurrentMultiplierNP.setState(IPS_OK);
383 }
384 else
385 {
386 LOGF_ERROR("Unknown error: hold current multiplier value (%s)", res);
387 return false;
388 }
389
390 return true;
391}
392
393bool DeepSkyDadAF3::readTemperature()
394{
395 char res[DSD_RES] = {0};
396
397 if (sendCommand("[GTMC]", res) == false)
398 return false;
399
400 double temp = 0;
401 int rc = sscanf(res, "(%lf)", &temp);
402 if (rc > 0)
403 {
404 TemperatureNP[0].setValue(temp);
405 }
406 else
407 {
408 LOGF_ERROR("Unknown error: focuser temperature value (%s)", res);
409 return false;
410 }
411
412 return true;
413}
414
415bool DeepSkyDadAF3::isMoving()
416{
417 char res[DSD_RES] = {0};
418
419 if (sendCommand("[GMOV]", res) == false)
420 return false;
421
422 if (strcmp(res, "(1)") == 0)
423 return true;
424 else if (strcmp(res, "(0)") == 0)
425 return false;
426
427 LOGF_ERROR("Unknown error: isMoving value (%s)", res);
428 return false;
429}
430
431bool DeepSkyDadAF3::SyncFocuser(uint32_t ticks)
432{
433 char cmd[DSD_RES] = {0};
434 snprintf(cmd, DSD_RES, "[SPOS%07d]", ticks);
435 char res[DSD_RES] = {0};
436 return sendCommand(cmd, res);
437}
438
440{
441 char cmd[DSD_RES] = {0};
442 snprintf(cmd, DSD_RES, "[SREV%01d]", enabled ? 1 : 0);
443 char res[DSD_RES] = {0};
444 return sendCommand(cmd, res);
445}
446
447bool DeepSkyDadAF3::MoveFocuser(uint32_t position)
448{
449 char cmd[DSD_RES] = {0};
450 char res[DSD_RES] = {0};
451 snprintf(cmd, DSD_RES, "[STRG%06d]", position);
452 // Set Position First
453 if (sendCommand(cmd, res) == false)
454 return false;
455
456 if(strcmp(res, "!101)") == 0)
457 {
458 LOG_ERROR("MoveFocuserFailed - requested movement too big. You can increase the limit by changing the value of Max. movement.");
459 return false;
460 }
461
462 // Now start motion toward position
463 if (sendCommand("[SMOV]", res) == false)
464 return false;
465
466 return true;
467}
468
469bool DeepSkyDadAF3::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
470{
471 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
472 {
473 // Focus Step Mode
474 if (StepModeSP.isNameMatch(name))
475 {
476 int current_mode = StepModeSP.findOnSwitchIndex();
477
478 StepModeSP.update(states, names, n);
479
480 int target_mode = StepModeSP.findOnSwitchIndex();
481
482 if (current_mode == target_mode)
483 {
484 StepModeSP.setState(IPS_OK);
485 StepModeSP.apply();
486 return true;
487 }
488
489 char cmd[DSD_RES] = {0};
490
491 if(target_mode == 0)
492 target_mode = 1;
493 else if(target_mode == 1)
494 target_mode = 2;
495 else if(target_mode == 2)
496 target_mode = 4;
497 else if(target_mode == 3)
498 target_mode = 8;
499 else if(target_mode == 4)
500 target_mode = 16;
501 else if(target_mode == 5)
502 target_mode = 32;
503 else if(target_mode == 6)
504 target_mode = 64;
505 else if(target_mode == 7)
506 target_mode = 128;
507 else if(target_mode == 8)
508 target_mode = 256;
509
510 snprintf(cmd, DSD_RES, "[SSTP%d]", target_mode);
511 bool rc = sendCommandSet(cmd);
512 if (!rc)
513 {
514 StepModeSP.reset();
515 StepModeSP[current_mode].setState(ISS_ON);
516 StepModeSP.setState(IPS_ALERT);
517 StepModeSP.apply();
518 return false;
519 }
520
521 StepModeSP.setState(IPS_OK);
522 StepModeSP.apply();
523 return true;
524 }
525
526 // Focus Speed Mode
527 if (SpeedModeSP.isNameMatch(name))
528 {
529 int current_mode = SpeedModeSP.findOnSwitchIndex();
530
531 SpeedModeSP.update(states, names, n);
532
533 int target_mode = SpeedModeSP.findOnSwitchIndex();
534
535 if (current_mode == target_mode)
536 {
537 SpeedModeSP.setState(IPS_OK);
538 SpeedModeSP.apply();
539 return true;
540 }
541
542 char cmd[DSD_RES] = {0};
543
544 if(target_mode == 0)
545 target_mode = 1;
546 else if(target_mode == 1)
547 target_mode = 2;
548 else if(target_mode == 2)
549 target_mode = 3;
550 else if(target_mode == 3)
551 target_mode = 4;
552 else if(target_mode == 4)
553 target_mode = 5;
554
555 snprintf(cmd, DSD_RES, "[SSPD%d]", target_mode);
556 bool rc = sendCommandSet(cmd);
557 if (!rc)
558 {
559 SpeedModeSP.reset();
560 SpeedModeSP[current_mode].setState(ISS_ON);
561 SpeedModeSP.setState(IPS_ALERT);
562 SpeedModeSP.apply();
563 return false;
564 }
565
566 SpeedModeSP.setState(IPS_OK);
567 SpeedModeSP.apply();
568 return true;
569 }
570 }
571
572 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
573}
574
575bool DeepSkyDadAF3::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
576{
577 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
578 {
579 // Settle buffer Settings
580 if (SettleBufferNP.isNameMatch(name))
581 {
582 SettleBufferNP.update(values, names, n);
583 char cmd[DSD_RES] = {0};
584 snprintf(cmd, DSD_RES, "[SBUF%06d]", static_cast<int>(SettleBufferNP[0].getValue()));
585 bool rc = sendCommandSet(cmd);
586 if (!rc)
587 {
588 SettleBufferNP.setState(IPS_ALERT);
589 return false;
590 }
591
592 SettleBufferNP.setState(IPS_OK);
593 SettleBufferNP.apply();
594 return true;
595 }
596
597 // Move current multiplier
598 if (MoveCurrentMultiplierNP.isNameMatch(name))
599 {
600 MoveCurrentMultiplierNP.update(values, names, n);
601 char cmd[DSD_RES] = {0};
602 snprintf(cmd, DSD_RES, "[SMMM%03d]", static_cast<int>(MoveCurrentMultiplierNP[0].getValue()));
603 bool rc = sendCommandSet(cmd);
604 if (!rc)
605 {
606 MoveCurrentMultiplierNP.setState(IPS_ALERT);
607 return false;
608 }
609
610 MoveCurrentMultiplierNP.setState(IPS_OK);
611 MoveCurrentMultiplierNP.apply();
612 return true;
613 }
614
615 // Hold current multiplier
616 if (HoldCurrentMultiplierNP.isNameMatch(name))
617 {
618 HoldCurrentMultiplierNP.update(values, names, n);
619 char cmd[DSD_RES] = {0};
620 snprintf(cmd, DSD_RES, "[SMHM%03d]", static_cast<int>(HoldCurrentMultiplierNP[0].getValue()));
621 bool rc = sendCommandSet(cmd);
622 if (!rc)
623 {
624 HoldCurrentMultiplierNP.setState(IPS_ALERT);
625 return false;
626 }
627
628 HoldCurrentMultiplierNP.setState(IPS_OK);
629 HoldCurrentMultiplierNP.apply();
630 return true;
631 }
632 }
633
634 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
635}
636
637void DeepSkyDadAF3::GetFocusParams()
638{
639 StepModeSP.reset();
640 SpeedModeSP.reset();
641
642 if (readPosition())
644
645 if (readStepMode())
646 StepModeSP.reset();
647
648 if (readSpeedMode())
649 SpeedModeSP.apply();
650
651 if (readSettleBuffer())
652 SettleBufferNP.apply();
653
654 if (readMoveCurrentMultiplier())
655 MoveCurrentMultiplierNP.apply();
656
657 if (readHoldCurrentMultiplier())
658 HoldCurrentMultiplierNP.apply();
659
660 if (readMaxPosition())
662
663 if (readMaxMovement())
665
666 if (readTemperature())
667 TemperatureNP.apply();
668}
669
670IPState DeepSkyDadAF3::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
671{
672 INDI_UNUSED(speed);
673 // either go all the way in or all the way out
674 // then use timer to stop
675 if (dir == FOCUS_INWARD)
676 MoveFocuser(0);
677 else
678 MoveFocuser(FocusMaxPosNP[0].getValue());
679
681 return IPS_BUSY;
682}
683
685{
686 static_cast<DeepSkyDadAF3*>(context)->timedMoveCallback();
687}
688
689void DeepSkyDadAF3::timedMoveCallback()
690{
691 AbortFocuser();
695 FocusTimerNP[0].setValue(0);
699}
700
701
703{
704 targetPos = targetTicks;
705
706 double bcValue = FocusBacklashNP[0].getValue();
707 int diff = targetTicks - FocusAbsPosNP[0].getValue();
708 if ((diff > 0 && bcValue < 0) || (diff < 0 && bcValue > 0))
709 {
710 backlashComp = bcValue;
711 targetPos -= bcValue;
712 }
713
714 if (!MoveFocuser(targetPos))
715 return IPS_ALERT;
716
717 return IPS_BUSY;
718}
719
721{
722 int32_t newPosition = 0;
723
724 if (dir == FOCUS_INWARD)
725 newPosition = FocusAbsPosNP[0].getValue() - ticks;
726 else
727 newPosition = FocusAbsPosNP[0].getValue() + ticks;
728
729 // Clamp
730 newPosition = std::max(0, std::min(static_cast<int32_t>(FocusAbsPosNP[0].getMax()), newPosition));
731 if (!MoveAbsFocuser(newPosition))
732 return IPS_ALERT;
733
734 // JM 2019-02-10: This is already set by the framework
735 //FocusRelPosNP[0].setValue(ticks);
736 //FocusRelPosNP.setState(IPS_BUSY);
737
738 return IPS_BUSY;
739}
740
742{
743 if (!isConnected())
744 {
746 return;
747 }
748
749 bool rc = readPosition();
750 if (rc)
751 {
752 if (std::abs(lastPos - FocusAbsPosNP[0].getValue()) > 5)
753 {
755 lastPos = FocusAbsPosNP[0].getValue();
756 }
757 }
758
760 {
761 if (!isMoving())
762 {
763 if( backlashComp == 0 )
764 {
767 }
770 lastPos = FocusAbsPosNP[0].getValue();
771
772 if(moveAborted)
773 {
774 LOG_INFO("Move aborted.");
775 }
776 else if(backlashComp != 0)
777 {
778 LOGF_INFO("Performing backlash compensation of %i.", (int)backlashComp);
779 targetPos += backlashComp;
780 MoveFocuser(targetPos);
781 }
782 else
783 {
784 LOG_INFO("Focuser reached requested position.");
785 }
786
787 moveAborted = false;
788 backlashComp = 0;
789 }
790 }
791
792 rc = readTemperature();
793 if (rc)
794 {
795 //more accurate update
796 if (std::abs(lastTemperature - TemperatureNP[0].getValue()) >= 0.1)
797 {
798 TemperatureNP.apply();
799 lastTemperature = TemperatureNP[0].getValue();
800 }
801 }
802
804}
805
807{
808 moveAborted = true;
809 return sendCommand("[STOP]");
810}
811
813{
814 Focuser::saveConfigItems(fp);
815
816 StepModeSP.save(fp);
817 SpeedModeSP.save(fp);
818 SettleBufferNP.save(fp);
819 MoveCurrentMultiplierNP.save(fp);
820 HoldCurrentMultiplierNP.save(fp);
821
822 return true;
823}
824
825bool DeepSkyDadAF3::sendCommand(const char * cmd, char * res)
826{
827 int nbytes_written = 0, nbytes_read = 0, rc = -1;
828
829 tcflush(PortFD, TCIOFLUSH);
830
831 LOGF_DEBUG("CMD <%s>", cmd);
832
833 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
834 {
835 char errstr[MAXRBUF] = {0};
836 tty_error_msg(rc, errstr, MAXRBUF);
837 LOGF_ERROR("Serial write error: %s.", errstr);
838 return false;
839 }
840
841 if (res == nullptr)
842 return true;
843
844 if ((rc = tty_nread_section(PortFD, res, DSD_RES, DSD_DEL, DSD_TIMEOUT, &nbytes_read)) != TTY_OK)
845 {
846 char errstr[MAXRBUF] = {0};
847 tty_error_msg(rc, errstr, MAXRBUF);
848 LOGF_ERROR("Serial read error: %s.", errstr);
849 return false;
850 }
851
852 LOGF_DEBUG("RES <%s>", res);
853
854 tcflush(PortFD, TCIOFLUSH);
855
856 return true;
857}
858
859bool DeepSkyDadAF3::sendCommandSet(const char * cmd)
860{
861 char res[DSD_RES] = {0};
862
863 if (sendCommand(cmd, res) == false)
864 return false;
865
866 return strcmp(res, "(OK)") == 0;
867}
868
870{
871 INDI_UNUSED(steps);
872 return true;
873}
874
876{
877 char cmd[DSD_RES] = {0};
878
879 snprintf(cmd, DSD_RES, "[SMXP%d]", ticks);
880
881 if (sendCommandSet(cmd))
882 {
883 SyncPresets(ticks);
884 return true;
885 }
886
887 return false;
888}
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
virtual bool saveConfigItems(FILE *fp) override
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
static void timedMoveHelper(void *context)
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser Move focuser in a specific direction and speed for period of time.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
const char * getDefaultName() override
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
bool isConnected() const
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSyncNP
INDI::PropertyNumber FocusTimerNP
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusBacklashNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
virtual void SyncPresets(uint32_t ticks)
Synchronizes the range (min, max, step) of the preset number properties (PresetNP) based on the focus...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition eventloop.c:586
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:759
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2