Instrument Neutral Distributed Interface INDI  1.9.5
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);
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 }
connectioninterface.h
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
MoonLiteDRO::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: moonlite_dro.cpp:851
MOONLITEDRO_TIMEOUT
#define MOONLITEDRO_TIMEOUT
Definition: moonlite_dro.cpp:34
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::FocuserInterface::FOCUSER_CAN_SYNC
@ FOCUSER_CAN_SYNC
Definition: indifocuserinterface.h:78
INDI::FocuserInterface::FOCUSER_CAN_REL_MOVE
@ FOCUSER_CAN_REL_MOVE
Definition: indifocuserinterface.h:75
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
Connection::TCP::getPortFD
int getPortFD() const
Definition: connectiontcp.h:120
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
IPState
IPState
Property state.
Definition: indiapi.h:158
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
INDI::DefaultDevice::setConnected
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
Definition: defaultdevice.cpp:847
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
connectiontcp.h
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
MAXINDINAME
#define MAXINDINAME
Definition: indiapi.h:190
IUFillNumber
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: indidriver.c:348
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
INDI::DefaultDevice::setDefaultPollingPeriod
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
Definition: defaultdevice.cpp:1157
MoonLiteDRO::Connect
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: moonlite_dro.cpp:140
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
MoonLiteDRO::FOCUS_FULL_STEP
@ FOCUS_FULL_STEP
Definition: moonlite_dro.h:30
INDI::Focuser::serialConnection
Connection::Serial * serialConnection
Definition: indifocuser.h:113
MoonLiteDRO::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: moonlite_dro.cpp:957
MoonLiteDRO::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: moonlite_dro.cpp:47
tty_read_section
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:557
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1455
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
max
double max(void)
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1156
MoonLiteDRO::MoonLiteDRO
MoonLiteDRO(int ID)
Definition: moonlite_dro.cpp:39
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
MoonLiteDRO::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: moonlite_dro.cpp:888
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
MoonLiteDRO::FOCUS_HALF_STEP
@ FOCUS_HALF_STEP
Definition: moonlite_dro.h:30
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::Focuser::PortFD
int PortFD
Definition: indifocuser.h:116
INDI::BaseDevice::setDeviceName
void setDeviceName(const char *dev)
Set the device name.
Definition: basedevice.cpp:793
MoonLiteDRO::Disconnect
virtual bool Disconnect() override
Disconnect from device.
Definition: moonlite_dro.cpp:156
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
INDI::DefaultDevice::Connect
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: defaultdevice.cpp:1058
INDI::FocuserInterface::FOCUS_INWARD
@ FOCUS_INWARD
Definition: indifocuserinterface.h:68
IUFillSwitchVector
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: indidriver.c:412
IUFillNumberVector
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: indidriver.c:455
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
connectionserial.h
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::Focuser::tcpConnection
Connection::TCP * tcpConnection
Definition: indifocuser.h:114
MoonLiteDRO::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: moonlite_dro.cpp:184
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
INDI::Focuser::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indifocuser.cpp:120
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
MoonLiteDRO::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: moonlite_dro.cpp:936
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::FocuserInterface::FocusRelPosNP
INumberVectorProperty FocusRelPosNP
Definition: indifocuserinterface.h:286
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
LOG_DEBUG
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
MoonLiteDRO::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: moonlite_dro.cpp:103
name
const char * name
Definition: indiserver.c:116
MoonLiteDRO::remoteDisconnect
void remoteDisconnect()
Definition: moonlite_dro.cpp:170
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
MoonLiteDRO::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: moonlite_dro.cpp:795
MoonLiteDRO
Definition: moonlite_dro.h:25
MoonLiteDRO::SyncFocuser
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition: moonlite_dro.cpp:573
MoonLiteDRO::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: moonlite_dro.cpp:867
ISState
ISState
Switch state.
Definition: indiapi.h:148
Connection::Serial::getPortFD
int getPortFD() const
Definition: connectionserial.h:136
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
MoonLiteDRO::getDefaultName
const char * getDefaultName() override
Definition: moonlite_dro.cpp:196
INDI::DefaultDevice::addDebugControl
void addDebugControl()
Add Debug control to the driver.
Definition: defaultdevice.cpp:639
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1465
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
INDI::DefaultDevice::Disconnect
virtual bool Disconnect()
Disconnect from device.
Definition: defaultdevice.cpp:1083
tty_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:465
TTY_OK
@ TTY_OK
Definition: indicom.h:94
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
MoonLiteDRO::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: moonlite_dro.cpp:730
INDI::Focuser::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indifocuser.cpp:168
INDI::FocuserInterface::FocusAbsPosN
INumber FocusAbsPosN[1]
Definition: indifocuserinterface.h:283
moonlite_dro.h
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
IUFillSwitch
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: indidriver.c:320
INDI::Focuser::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indifocuser.cpp:145
INDI::DefaultDevice::getActiveConnection
Connection::Interface * getActiveConnection()
Definition: defaultdevice.cpp:1245
INDI::FocuserInterface::FocusSpeedN
INumber FocusSpeedN[1]
Definition: indifocuserinterface.h:269
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151