Instrument Neutral Distributed Interface INDI 2.2.5
moonlite_dro.cpp
Go to the documentation of this file.
1/*
2 Moonlite DRO Dual Focuser
3 Copyright (C) 2018 Jasem Mutlaq ([email protected])
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#include "moonlite_dro.h"
25
26#include "indicom.h"
27
28#include <cmath>
29#include <cstring>
30#include <memory>
31#include <termios.h>
32#include <unistd.h>
33
34#define MOONLITEDRO_TIMEOUT 3
35
36static std::unique_ptr<MoonLiteDRO> dro1(new MoonLiteDRO(1));
37static std::unique_ptr<MoonLiteDRO> dro2(new MoonLiteDRO(2));
38
39MoonLiteDRO::MoonLiteDRO(int ID) : m_ID(ID)
40{
42 char name[MAXINDINAME] = {0};
43 snprintf(name, MAXINDINAME, "MoonLiteDRO #%d", m_ID);
44 setDeviceName(name);
45}
46
48{
50
51 FocusSpeedNP[0].setMin(1);
52 FocusSpeedNP[0].setMax(5);
53 FocusSpeedNP[0].setValue(1);
54
55 // Step Delay
56 IUFillNumber(&StepDelayN[0], "STEP_DELAY", "Delay", "%.f", 1, 5, 1., 1.);
57 IUFillNumberVector(&StepDelayNP, StepDelayN, 1, getDeviceName(), "FOCUS_STEP_DELAY", "Step",
58 SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
59
60 // Step Mode
61 IUFillSwitch(&StepModeS[FOCUS_HALF_STEP], "HALF_STEP", "Half Step", ISS_OFF);
62 IUFillSwitch(&StepModeS[FOCUS_FULL_STEP], "FULL_STEP", "Full Step", ISS_ON);
63 IUFillSwitchVector(&StepModeSP, StepModeS, 2, getDeviceName(), "FOCUS_STEP_MODE", "Step Mode", SETTINGS_TAB, IP_RW,
64 ISR_1OFMANY, 0,
65 IPS_IDLE);
66
67 // Temperature Settings
68 IUFillNumber(&TemperatureSettingN[0], "Calibration", "Calibration", "%6.2f", -20, 20, 0.5, 0);
69 IUFillNumber(&TemperatureSettingN[1], "Coefficient", "Coefficient", "%6.2f", -20, 20, 0.5, 0);
70 IUFillNumberVector(&TemperatureSettingNP, TemperatureSettingN, 2, getDeviceName(), "FOCUS_TEMPERATURE_SETTINGS",
71 "T. Settings",
72 SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
73
74 // Compensate for temperature
75 IUFillSwitch(&TemperatureCompensateS[0], "Enable", "Enable", ISS_OFF);
76 IUFillSwitch(&TemperatureCompensateS[1], "Disable", "Disable", ISS_ON);
77 IUFillSwitchVector(&TemperatureCompensateSP, TemperatureCompensateS, 2, getDeviceName(), "FOCUS_TEMPERATURE_COMPENSATION",
78 "T. Compensate", SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
79
80
81 // Focuser temperature
82 IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
83 IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
85
86 // Relative and absolute movement
87 FocusRelPosNP[0].setMin(0.);
88 FocusRelPosNP[0].setMax(50000.);
89 FocusRelPosNP[0].setValue(0);
90 FocusRelPosNP[0].setStep(1000);
91
92 FocusAbsPosNP[0].setMin(0.);
93 FocusAbsPosNP[0].setMax(100000.);
94 FocusAbsPosNP[0].setValue(0);
95 FocusAbsPosNP[0].setStep(1000);
96
99
100 return true;
101}
102
104{
106
107 if (isConnected())
108 {
109 // Only display such properties for the first focuser only
110 if (m_ID == 1)
111 {
112 defineProperty(&TemperatureNP);
113 defineProperty(&TemperatureSettingNP);
114 defineProperty(&TemperatureCompensateSP);
115 }
116
117 defineProperty(&StepDelayNP);
118 defineProperty(&StepModeSP);
119
120 GetFocusParams();
121
122 LOGF_INFO("%s parameters updated, focuser ready for use.", getDeviceName());
123 }
124 else
125 {
126 if (m_ID == 1)
127 {
128 deleteProperty(TemperatureNP.name);
129 deleteProperty(TemperatureSettingNP.name);
130 deleteProperty(TemperatureCompensateSP.name);
131 }
132
133 deleteProperty(StepDelayNP.name);
134 deleteProperty(StepModeSP.name);
135 }
136
137 return true;
138}
139
141{
142 if (m_ID == 1)
143 return INDI::Focuser::Connect();
144
145 if (dro1->isConnected() == false)
146 {
147 LOG_ERROR("You must connect DRO Focuser #1 first before connecting to DRO Focuser #2.");
148 return false;
149 }
150
151 PortFD = dro1->getPortFD();
153 return true;
154}
155
157{
158 if (m_ID == 1)
159 {
160 // Also disconnect 2nd focuser
161 dro2->remoteDisconnect();
163 }
164
165 // No need to do anything for DRO #2
166 PortFD = -1;
167 return true;
168}
169
171{
172 // If not DRO #2, then return immediately.
173 if (m_ID != 2)
174 return;
175
176 if (isConnected())
177 {
178 // Otherwise, just set PortFD = -1
179 PortFD = -1;
180 setConnected(false, IPS_IDLE);
182 }
183}
185{
186 if (Ack())
187 {
188 LOGF_INFO("%s is online. Getting focus parameters...", getDeviceName());
189 return true;
190 }
191
192 LOG_INFO("Handshake failed. please ensure MoonLite controller is powered and the port is correct.");
193 return false;
194}
195
197{
198 return "MoonLiteDRO";
199}
200
201bool MoonLiteDRO::Ack()
202{
203 // For First Focuser, try to get the serial/tcp connection port FD
204 if (m_ID == 1)
205 {
208 else
210 }
211 // For second focuser, try to get the port FD of the first focuser
212 else if (m_ID == 2)
213 {
214 // We need to get Serial Port file descriptor from first focuser
215 // Since we need to have only a SINGLE serial connection to the DRO and not two.
216 PortFD = dro1->getPortFD();
217 if (PortFD == -1)
218 {
219 LOG_WARN("You must connect DRO Focuser #1 first before connecting to DRO Focuser #2.");
220 return false;
221 }
222
223 // If we have a valid Port FD then we are good to go
224 return true;
225 }
226
227 int nbytes_written = 0, nbytes_read = 0, rc = -1;
228 char errstr[MAXRBUF];
229 char resp[5] = {0};
230 short pos = -1;
231
232 tcflush(PortFD, TCIOFLUSH);
233
234 //Try to request the position of the focuser
235 //Test for success on transmission and response
236 //If either one fails, try again, up to 3 times, waiting 1 sec each time
237 //If that fails, then return false.
238
239 int numChecks = 0;
240 bool success = false;
241 while(numChecks < 3 && !success)
242 {
243 numChecks++;
244 sleep(1); //wait 1 second between each test.
245
246 bool transmissionSuccess = (rc = tty_write(PortFD, ":GP#", 4, &nbytes_written)) == TTY_OK;
247 if(!transmissionSuccess)
248 {
249 tty_error_msg(rc, errstr, MAXRBUF);
250 LOGF_ERROR("Handshake Attempt %i, tty transmission error: %s.", numChecks, errstr);
251 }
252
253 bool responseSuccess = (rc = tty_read(PortFD, resp, 5, MOONLITEDRO_TIMEOUT, &nbytes_read)) == TTY_OK;
254 if(!responseSuccess)
255 {
256 tty_error_msg(rc, errstr, MAXRBUF);
257 LOGF_ERROR("Handshake Attempt %i, updatePosition response error: %s.", numChecks, errstr);
258 }
259
260 success = transmissionSuccess && responseSuccess;
261 }
262
263 if(!success)
264 {
265 LOG_INFO("Handshake failed after 3 attempts");
266 return false;
267 }
268
269 tcflush(PortFD, TCIOFLUSH);
270
271 rc = sscanf(resp, "%hX#", &pos);
272
273 return rc > 0;
274}
275
276bool MoonLiteDRO::updateStepDelay()
277{
278 int nbytes_written = 0, nbytes_read = 0, rc = -1;
279 char errstr[MAXRBUF];
280 char resp[3] = {0};
281 char cmd[DRO_CMD] = {0};
282 short speed;
283
284 if (m_ID == 1)
285 strncpy(cmd, ":GD#", DRO_CMD);
286 else
287 strncpy(cmd, ":2GD#", DRO_CMD);
288
289 LOGF_DEBUG("CMD <%s>", cmd);
290
291 tcflush(PortFD, TCIOFLUSH);
292
293 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
294 {
295 tty_error_msg(rc, errstr, MAXRBUF);
296 LOGF_ERROR("updateStepDelay error: %s.", errstr);
297 return false;
298 }
299
300 if ((rc = tty_read_section(PortFD, resp, '#', MOONLITEDRO_TIMEOUT, &nbytes_read)) != TTY_OK)
301 {
302 tty_error_msg(rc, errstr, MAXRBUF);
303 LOGF_ERROR("updateStepDelay error: %s.", errstr);
304 return false;
305 }
306
307 tcflush(PortFD, TCIOFLUSH);
308
309 LOGF_DEBUG("RES <%s>", resp);
310
311 rc = sscanf(resp, "%hX", &speed);
312
313 if (rc > 0)
314 {
315 int focus_speed = -1;
316 while (speed > 0)
317 {
318 speed >>= 1;
319 focus_speed++;
320 }
321
322 StepDelayN[0].value = focus_speed;
323 }
324 else
325 {
326 LOGF_ERROR("Unknown error: focuser step delay value (%s)", resp);
327 return false;
328 }
329
330 return true;
331}
332
333bool MoonLiteDRO::updateStepMode()
334{
335 int nbytes_written = 0, nbytes_read = 0, rc = -1;
336 char errstr[MAXRBUF];
337 char resp[4] = {0};
338 char cmd[DRO_CMD] = {0};
339
340 if (m_ID == 1)
341 strncpy(cmd, ":GH#", DRO_CMD);
342 else
343 strncpy(cmd, ":2GH#", DRO_CMD);
344
345 tcflush(PortFD, TCIOFLUSH);
346
347 LOGF_DEBUG("CMD <%s>", cmd);
348
349 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
350 {
351 tty_error_msg(rc, errstr, MAXRBUF);
352 LOGF_ERROR("updateStepMode error: %s.", errstr);
353 return false;
354 }
355
356 if ((rc = tty_read_section(PortFD, resp, '#', MOONLITEDRO_TIMEOUT, &nbytes_read)) != TTY_OK)
357 {
358 tty_error_msg(rc, errstr, MAXRBUF);
359 LOGF_ERROR("updateStepMode error: %s.", errstr);
360 return false;
361 }
362
363 tcflush(PortFD, TCIOFLUSH);
364
365 resp[3] = '\0';
366
367 LOGF_DEBUG("RES <%s>", resp);
368
369 IUResetSwitch(&StepModeSP);
370
371 if (strcmp(resp, "FF") == 0)
372 StepModeS[FOCUS_HALF_STEP].s = ISS_ON;
373 else if (strcmp(resp, "00") == 0)
374 StepModeS[FOCUS_FULL_STEP].s = ISS_ON;
375 else
376 {
377 LOGF_ERROR("Unknown error: focuser step value (%s)", resp);
378 return false;
379 }
380
381 return true;
382}
383
384bool MoonLiteDRO::updateTemperature()
385{
386 int nbytes_written = 0, nbytes_read = 0, rc = -1;
387 char errstr[MAXRBUF];
388 char resp[16] = {0};
389
390 tcflush(PortFD, TCIOFLUSH);
391
392 tty_write(PortFD, ":C#", 3, &nbytes_written);
393
394 LOG_DEBUG("CMD <:GT#>");
395
396 if ((rc = tty_write(PortFD, ":GT#", 4, &nbytes_written)) != TTY_OK)
397 {
398 tty_error_msg(rc, errstr, MAXRBUF);
399 LOGF_ERROR("updateTemperature error: %s.", errstr);
400 return false;
401 }
402
403 if ((rc = tty_read_section(PortFD, resp, '#', MOONLITEDRO_TIMEOUT, &nbytes_read)) != TTY_OK)
404 {
405 tty_error_msg(rc, errstr, MAXRBUF);
406 LOGF_ERROR("updateTemperature error: %s.", errstr);
407 return false;
408 }
409
410 tcflush(PortFD, TCIOFLUSH);
411
412 resp[nbytes_read - 1] = '\0';
413
414 LOGF_DEBUG("RES <%s>", resp);
415
416 uint32_t temp = 0;
417 rc = sscanf(resp, "%X", &temp);
418
419 if (rc > 0)
420 {
421 // Signed hex
422 TemperatureN[0].value = static_cast<int16_t>(temp) / 2.0;
423 }
424 else
425 {
426 LOGF_ERROR("Unknown error: focuser temperature value (%s)", resp);
427 return false;
428 }
429
430 return true;
431}
432
433bool MoonLiteDRO::updatePosition()
434{
435 int nbytes_written = 0, nbytes_read = 0, rc = -1;
436 char errstr[MAXRBUF];
437 char resp[DRO_CMD] = {0};
438 int pos = -1;
439 char cmd[DRO_CMD] = {0};
440
441 if (m_ID == 1)
442 strncpy(cmd, ":GP#", DRO_CMD);
443 else
444 strncpy(cmd, ":2GP#", DRO_CMD);
445
446 LOGF_DEBUG("CMD <%s>", cmd);
447
448 tcflush(PortFD, TCIOFLUSH);
449
450 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
451 {
452 tty_error_msg(rc, errstr, MAXRBUF);
453 LOGF_ERROR("updatePosition error: %s.", errstr);
454 return false;
455 }
456
457 if ((rc = tty_read_section(PortFD, resp, '#', MOONLITEDRO_TIMEOUT, &nbytes_read)) != TTY_OK)
458 {
459 tty_error_msg(rc, errstr, MAXRBUF);
460 LOGF_ERROR("updatePosition error: %s.", errstr);
461 return false;
462 }
463
464 tcflush(PortFD, TCIOFLUSH);
465
466 LOGF_DEBUG("RES <%s>", resp);
467
468 rc = sscanf(resp, "%X", &pos);
469
470 if (rc > 0)
471 {
472 FocusAbsPosNP[0].setValue(pos);
473 }
474 else
475 {
476 LOGF_ERROR("Unknown error: focuser position value (%s)", resp);
477 return false;
478 }
479
480 return true;
481}
482
483bool MoonLiteDRO::isMoving()
484{
485 int nbytes_written = 0, nbytes_read = 0, rc = -1;
486 char errstr[MAXRBUF];
487 char resp[DRO_CMD] = {0};
488 char cmd[DRO_CMD] = {0};
489
490 if (m_ID == 1)
491 strncpy(cmd, ":GI#", DRO_CMD);
492 else
493 strncpy(cmd, ":2GI#", DRO_CMD);
494
495 LOGF_DEBUG("CMD <%s>", cmd);
496
497 tcflush(PortFD, TCIOFLUSH);
498
499 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
500 {
501 tty_error_msg(rc, errstr, MAXRBUF);
502 LOGF_ERROR("isMoving error: %s.", errstr);
503 return false;
504 }
505
506 if ((rc = tty_read_section(PortFD, resp, '#', MOONLITEDRO_TIMEOUT, &nbytes_read)) != TTY_OK)
507 {
508 tty_error_msg(rc, errstr, MAXRBUF);
509 LOGF_ERROR("isMoving error: %s.", errstr);
510 return false;
511 }
512
513 tcflush(PortFD, TCIOFLUSH);
514
515 resp[2] = '\0';
516
517 LOGF_DEBUG("RES <%s>", resp);
518
519 if (strcmp(resp, "01") == 0)
520 return true;
521 else if (strcmp(resp, "00") == 0)
522 return false;
523
524 LOGF_ERROR("Unknown error: isMoving value (%s)", resp);
525 return false;
526}
527
528bool MoonLiteDRO::setTemperatureCalibration(double calibration)
529{
530 int nbytes_written = 0, rc = -1;
531 char cmd[DRO_CMD] = {0};
532
533 uint8_t hex = static_cast<int8_t>(calibration * 2) & 0xFF;
534 snprintf(cmd, DRO_CMD, ":PO%02X#", hex);
535
536 LOGF_DEBUG("CMD <%s>", cmd);
537
538 tcflush(PortFD, TCIOFLUSH);
539
540 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
541 {
542 char errstr[MAXRBUF];
543 tty_error_msg(rc, errstr, MAXRBUF);
544 LOGF_ERROR("setTemperatureCalibration error: %s.", errstr);
545 return false;
546 }
547
548 return true;
549}
550
551bool MoonLiteDRO::setTemperatureCoefficient(double coefficient)
552{
553 int nbytes_written = 0, rc = -1;
554 char errstr[MAXRBUF];
555 char cmd[DRO_CMD] = {0};
556 uint8_t hex = static_cast<int8_t>(coefficient * 2) & 0xFF;
557 snprintf(cmd, DRO_CMD, ":SC%02X#", hex);
558
559 LOGF_DEBUG("CMD <%s>", cmd);
560
561 tcflush(PortFD, TCIOFLUSH);
562
563 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
564 {
565 tty_error_msg(rc, errstr, MAXRBUF);
566 LOGF_ERROR("setTemperatureCoefficient error: %s.", errstr);
567 return false;
568 }
569
570 return true;
571}
572
573bool MoonLiteDRO::SyncFocuser(uint32_t ticks)
574{
575 int nbytes_written = 0, rc = -1;
576 char cmd[DRO_CMD] = {0};
577
578 if (m_ID == 1)
579 snprintf(cmd, DRO_CMD, ":SP%04X#", ticks);
580 else
581 snprintf(cmd, DRO_CMD, ":2SP%04X#", ticks);
582
583 LOGF_DEBUG("CMD <%s>", cmd);
584
585 // Set Position
586 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
587 {
588 char errstr[MAXRBUF];
589 tty_error_msg(rc, errstr, MAXRBUF);
590 LOGF_ERROR("reset error: %s.", errstr);
591 return false;
592 }
593
594 return true;
595}
596
597bool MoonLiteDRO::gotoAbsPosition(unsigned int position)
598{
599 int nbytes_written = 0, rc = -1;
600 char errstr[MAXRBUF];
601 char cmd[DRO_CMD] = {0};
602
603 if (position < FocusAbsPosNP[0].getMin() || position > FocusAbsPosNP[0].getMax())
604 {
605 LOGF_ERROR("Requested position value out of bound: %d", position);
606 return false;
607 }
608
609 if (m_ID == 1)
610 snprintf(cmd, DRO_CMD, ":SN%04X#", position);
611 else
612 snprintf(cmd, DRO_CMD, ":2SN%04X#", position);
613
614 LOGF_DEBUG("CMD <%s>", cmd);
615
616 // Set Position
617 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
618 {
619 tty_error_msg(rc, errstr, MAXRBUF);
620 LOGF_ERROR("setPosition error: %s.", errstr);
621 return false;
622 }
623
624 memset(cmd, 0, DRO_CMD);
625 if (m_ID == 1)
626 strncpy(cmd, ":FG#", DRO_CMD);
627 else
628 strncpy(cmd, ":2FG#", DRO_CMD);
629
630 LOGF_DEBUG("CMD <%s>", cmd);
631
632 // gotoAbsPosition to Position
633 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
634 {
635 tty_error_msg(rc, errstr, MAXRBUF);
636 LOGF_ERROR("gotoAbsPosition error: %s.", errstr);
637 return false;
638 }
639
640 return true;
641}
642
643bool MoonLiteDRO::setStepMode(FocusStepMode mode)
644{
645 int nbytes_written = 0, rc = -1;
646 char errstr[MAXRBUF];
647 char cmd[DRO_CMD] = {0};
648
649 tcflush(PortFD, TCIOFLUSH);
650
651 if (mode == FOCUS_HALF_STEP)
652 {
653 if (m_ID == 1)
654 strncpy(cmd, ":SH#", DRO_CMD);
655 else
656 strncpy(cmd, ":2SH#", DRO_CMD);
657 }
658 else
659 {
660 if (m_ID == 1)
661 strncpy(cmd, ":SF#", DRO_CMD);
662 else
663 strncpy(cmd, ":2SF#", DRO_CMD);
664 }
665
666 LOGF_DEBUG("CMD <%s>", cmd);
667
668 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
669 {
670 tty_error_msg(rc, errstr, MAXRBUF);
671 LOGF_ERROR("setStepMode error: %s.", errstr);
672 return false;
673 }
674
675 return true;
676}
677
678bool MoonLiteDRO::setStepDelay(uint8_t delay)
679{
680 int nbytes_written = 0, rc = -1;
681 char errstr[MAXRBUF];
682 char cmd[DRO_CMD] = {0};
683
684 int hex_value = 1;
685
686 hex_value <<= delay;
687
688 if (m_ID == 1)
689 snprintf(cmd, DRO_CMD, ":SD%02X#", hex_value);
690 else
691 snprintf(cmd, DRO_CMD, ":2SD%02X#", hex_value);
692
693 LOGF_DEBUG("CMD <%s>", cmd);
694
695 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
696 {
697 tty_error_msg(rc, errstr, MAXRBUF);
698 LOGF_ERROR("setStepelay error: %s.", errstr);
699 return false;
700 }
701
702 return true;
703}
704
705bool MoonLiteDRO::setTemperatureCompensation(bool enable)
706{
707 int nbytes_written = 0, rc = -1;
708 char errstr[MAXRBUF];
709 char cmd[DRO_CMD] = {0};
710
711 tcflush(PortFD, TCIOFLUSH);
712
713 if (enable)
714 strncpy(cmd, ":+#", DRO_CMD);
715 else
716 strncpy(cmd, ":-#", DRO_CMD);
717
718 LOGF_DEBUG("CMD <%s>", cmd);
719
720 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
721 {
722 tty_error_msg(rc, errstr, MAXRBUF);
723 LOGF_ERROR("setTemperatureCompensation error: %s.", errstr);
724 return false;
725 }
726
727 return true;
728}
729
730bool MoonLiteDRO::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
731{
732 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
733 {
734 // Focus Step Mode
735 if (strcmp(StepModeSP.name, name) == 0)
736 {
737 bool rc = false;
738 int current_mode = IUFindOnSwitchIndex(&StepModeSP);
739
740 IUUpdateSwitch(&StepModeSP, states, names, n);
741
742 int target_mode = IUFindOnSwitchIndex(&StepModeSP);
743
744 if (current_mode == target_mode)
745 {
746 StepModeSP.s = IPS_OK;
747 IDSetSwitch(&StepModeSP, nullptr);
748 }
749
750 if (target_mode == 0)
751 rc = setStepMode(FOCUS_HALF_STEP);
752 else
753 rc = setStepMode(FOCUS_FULL_STEP);
754
755 if (!rc)
756 {
757 IUResetSwitch(&StepModeSP);
758 StepModeS[current_mode].s = ISS_ON;
759 StepModeSP.s = IPS_ALERT;
760 IDSetSwitch(&StepModeSP, nullptr);
761 return false;
762 }
763
764 StepModeSP.s = IPS_OK;
765 IDSetSwitch(&StepModeSP, nullptr);
766 return true;
767 }
768
769 // Temperature Compensation
770 if (strcmp(TemperatureCompensateSP.name, name) == 0)
771 {
772 int last_index = IUFindOnSwitchIndex(&TemperatureCompensateSP);
773 IUUpdateSwitch(&TemperatureCompensateSP, states, names, n);
774
775 bool rc = setTemperatureCompensation((TemperatureCompensateS[0].s == ISS_ON));
776
777 if (!rc)
778 {
779 TemperatureCompensateSP.s = IPS_ALERT;
780 IUResetSwitch(&TemperatureCompensateSP);
781 TemperatureCompensateS[last_index].s = ISS_ON;
782 IDSetSwitch(&TemperatureCompensateSP, nullptr);
783 return false;
784 }
785
786 TemperatureCompensateSP.s = IPS_OK;
787 IDSetSwitch(&TemperatureCompensateSP, nullptr);
788 return true;
789 }
790 }
791
792 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
793}
794
795bool MoonLiteDRO::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
796{
797 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
798 {
799 // Temperature Settings
800 if (strcmp(name, TemperatureSettingNP.name) == 0)
801 {
802 IUUpdateNumber(&TemperatureSettingNP, values, names, n);
803 if (!setTemperatureCalibration(TemperatureSettingN[0].value) ||
804 !setTemperatureCoefficient(TemperatureSettingN[1].value))
805 {
806 TemperatureSettingNP.s = IPS_ALERT;
807 IDSetNumber(&TemperatureSettingNP, nullptr);
808 return false;
809 }
810
811 TemperatureSettingNP.s = IPS_OK;
812 IDSetNumber(&TemperatureSettingNP, nullptr);
813 return true;
814 }
815
816 // Step Delay
817 if (strcmp(name, StepDelayNP.name) == 0)
818 {
819 if (setStepDelay(values[0]) == false)
820 {
821 StepDelayNP.s = IPS_ALERT;
822 IDSetNumber(&StepDelayNP, nullptr);
823 return false;
824 }
825
826 IUUpdateNumber(&StepDelayNP, values, names, n);
827 StepDelayNP.s = IPS_OK;
828 IDSetNumber(&StepDelayNP, nullptr);
829 return true;
830 }
831 }
832
833 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
834}
835
836void MoonLiteDRO::GetFocusParams()
837{
838 if (updatePosition())
840
841 if (updateTemperature())
842 IDSetNumber(&TemperatureNP, nullptr);
843
844 if (updateStepDelay())
845 IDSetNumber(&StepDelayNP, nullptr);
846
847 if (updateStepMode())
848 IDSetSwitch(&StepModeSP, nullptr);
849}
850
852{
853 targetPos = targetTicks;
854
855 bool rc = false;
856
857 rc = gotoAbsPosition(targetPos);
858
859 if (!rc)
860 return IPS_ALERT;
861
863
864 return IPS_BUSY;
865}
866
868{
869 double newPosition = 0;
870 bool rc = false;
871
872 if (dir == FOCUS_INWARD)
873 newPosition = FocusAbsPosNP[0].getValue() - ticks;
874 else
875 newPosition = FocusAbsPosNP[0].getValue() + ticks;
876
877 rc = gotoAbsPosition(newPosition);
878
879 if (!rc)
880 return IPS_ALERT;
881
882 FocusRelPosNP[0].setValue(ticks);
884
885 return IPS_BUSY;
886}
887
889{
890 if (!isConnected())
891 {
893 return;
894 }
895
896 bool rc = updatePosition();
897 if (rc)
898 {
899 if (fabs(lastPos - FocusAbsPosNP[0].getValue()) > 5)
900 {
902 lastPos = FocusAbsPosNP[0].getValue();
903 }
904 }
905
906 // Only query temperature for FIRST focuser
907 if (m_ID == 1)
908 {
909 rc = updateTemperature();
910 if (rc)
911 {
912 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
913 {
914 IDSetNumber(&TemperatureNP, nullptr);
915 lastTemperature = TemperatureN[0].value;
916 }
917 }
918 }
919
921 {
922 if (!isMoving())
923 {
928 lastPos = FocusAbsPosNP[0].getValue();
929 LOG_INFO("Focuser reached requested position.");
930 }
931 }
932
934}
935
937{
938 int nbytes_written;
939 char cmd[DRO_CMD] = {0};
940
941 strncpy(cmd, (m_ID == 1) ? ":FQ#" : "#:2FQ#", DRO_CMD);
942
943 LOGF_DEBUG("CMD <%s>", cmd);
944
945 if (tty_write_string(PortFD, cmd, &nbytes_written) == TTY_OK)
946 {
951 return true;
952 }
953 else
954 return false;
955}
956
958{
959 Focuser::saveConfigItems(fp);
960
961 IUSaveConfigSwitch(fp, &StepModeSP);
962 IUSaveConfigNumber(fp, &StepDelayNP);
963
964 return true;
965}
int getPortFD() const
bool isConnected() const
void setDeviceName(const char *dev)
Set the device name.
virtual bool Disconnect()
Disconnect from device.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
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.
Connection::Interface * getActiveConnection()
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
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 FocusSpeedNP
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,...
Connection::TCP * tcpConnection
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...
Connection::Serial * serialConnection
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool saveConfigItems(FILE *fp) override
const char * getDefaultName() override
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool Disconnect() override
Disconnect from device.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
void remoteDisconnect()
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
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...
MoonLiteDRO(int ID)
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
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
MoveFocuser the focuser to an absolute position.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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
#define MAXINDINAME
Definition indiapi.h:189
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:653
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
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
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:490
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition indidevapi.c:337
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition indidevapi.c:376
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition indidevapi.c:398
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:453
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOG_WARN(txt)
Definition indilogger.h:73
#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
#define MOONLITEDRO_TIMEOUT
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369