Instrument Neutral Distributed Interface INDI  2.0.2
moonlite_dro.cpp
Go to the documentation of this file.
1 /*
2  Moonlite DRO Dual Focuser
3  Copyright (C) 2018 Jasem Mutlaq (mutlaqja@ikarustech.com)
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 
36 static std::unique_ptr<MoonLiteDRO> dro1(new MoonLiteDRO(1));
37 static std::unique_ptr<MoonLiteDRO> dro2(new MoonLiteDRO(2));
38 
39 MoonLiteDRO::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  FocusSpeedN[0].min = 1;
52  FocusSpeedN[0].max = 5;
53  FocusSpeedN[0].value = 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  FocusRelPosN[0].min = 0.;
88  FocusRelPosN[0].max = 50000.;
89  FocusRelPosN[0].value = 0;
90  FocusRelPosN[0].step = 1000;
91 
92  FocusAbsPosN[0].min = 0.;
93  FocusAbsPosN[0].max = 100000.;
94  FocusAbsPosN[0].value = 0;
95  FocusAbsPosN[0].step = 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();
162  return INDI::Focuser::Disconnect();
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 
201 bool 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 
276 bool 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 
333 bool 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 
384 bool 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 
433 bool 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  FocusAbsPosN[0].value = 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 
483 bool 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[3] = '\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 
528 bool 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 
551 bool 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 
573 bool 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 
597 bool 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 < FocusAbsPosN[0].min || position > FocusAbsPosN[0].max)
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 
643 bool 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 
678 bool 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 
705 bool 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 
730 bool 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 
795 bool 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 
836 void MoonLiteDRO::GetFocusParams()
837 {
838  if (updatePosition())
839  IDSetNumber(&FocusAbsPosNP, nullptr);
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 = FocusAbsPosN[0].value - ticks;
874  else
875  newPosition = FocusAbsPosN[0].value + ticks;
876 
877  rc = gotoAbsPosition(newPosition);
878 
879  if (!rc)
880  return IPS_ALERT;
881 
882  FocusRelPosN[0].value = 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 - FocusAbsPosN[0].value) > 5)
900  {
901  IDSetNumber(&FocusAbsPosNP, nullptr);
902  lastPos = FocusAbsPosN[0].value;
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  {
926  IDSetNumber(&FocusAbsPosNP, nullptr);
927  IDSetNumber(&FocusRelPosNP, nullptr);
928  lastPos = FocusAbsPosN[0].value;
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  {
949  IDSetNumber(&FocusAbsPosNP, nullptr);
950  IDSetNumber(&FocusRelPosNP, nullptr);
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
Definition: connectiontcp.h:84
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setDeviceName(const char *dev)
Set the device name.
Definition: basedevice.cpp:815
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.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
Connection::TCP * tcpConnection
Definition: indifocuser.h:117
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Connection::Serial * serialConnection
Definition: indifocuser.h:116
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
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
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
Initilize properties initial state and value. The child class must implement this function.
void remoteDisconnect()
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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
Process the client newNumber command.
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
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
double max(void)
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
#define MAXINDINAME
Definition: indiapi.h:191
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:566
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
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:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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:158
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:180
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:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#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 MAXRBUF
Definition: indiserver.cpp:102
#define MOONLITEDRO_TIMEOUT
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371