Instrument Neutral Distributed Interface INDI  2.0.2
teenastro.cpp
Go to the documentation of this file.
1 /*
2  TeenAstro Focuser
3  Copyright (C) 2021 Markus Noga
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 "teenastro.h"
22 #include "indicom.h"
23 #include "indicontroller.h"
24 
25 #include <unistd.h> // for sleep()
26 #include <termios.h> // for tcflush
27 
28 // Default, minimal and maximal values for focuser configuration properties
29 // In absolute units (not device units, where e.g. current is /10 and microsteps are log_2)
30 //
31 
32 #define TAF_curr_default 500
33 #define TAF_curr_min 100
34 #define TAF_curr_max 1600
35 #define TAF_micro_default (1<<4)
36 #define TAF_micro_min (1<<2)
37 #define TAF_micro_max (1<<7)
38 #define TAF_steprot_default 200
39 #define TAF_steprot_min 10
40 #define TAF_steprot_max 800
41 #define TAF_pos_default 0
42 #define TAF_pos_min 0
43 #define TAF_pos_max 2000000000UL
44 #define TAF_speed_default 20
45 #define TAF_speed_min 1
46 #define TAF_speed_max 999
47 #define TAF_acc_default 30
48 #define TAF_acc_min 1
49 #define TAF_acc_max 99
50 #define TAF_res_default 16
51 #define TAF_res_min 1
52 #define TAF_res_max 512
53 
54 #define TAF_UI_STEPS 100.0
55 #define TAF_STEP(min,max) (((max)-(min))/(TAF_UI_STEPS))
56 
57 
58 #define TAF_FOCUSER_TIMEOUT 2
59 #define TAF_FOCUSER_BUFSIZE 128
60 
61 // Focuser singleton
62 std::unique_ptr<TeenAstroFocuser> teenAstroFocuser(new TeenAstroFocuser());
63 
64 // Public methods
65 //
66 
68 {
71 }
72 
74 {
75 }
76 
78 {
79  return "TeenAstroFocuser";
80 }
81 
83 {
84  char resp[TAF_FOCUSER_BUFSIZE];
85 
86  // Issue handshake challenge for TeenAstro focuser
87  if(!sendAndReceive(":FV#", resp, TAF_FOCUSER_BUFSIZE))
88  return false;
89  if (strncmp(resp, "$ TeenAstro Focuser ", 20))
90  {
91  DEBUGF(INDI::Logger::DBG_ERROR, "Handshake response: %s", resp);
92  return false;
93  }
94 
95  // TeenAstro mounts internally forward focuser commands via a
96  // serial connection. When mount & focuser are both on USB,
97  // and scanning for devices, a race condition can occur. The
98  // focuser device driver may probe the USB connection of the
99  // mount first, and receive a correct response to the focuser
100  // handshake challenge. Then the focuser driver would block
101  // the USB port of the mount. And the scan performed by
102  // mount driver would fail. To avoid this race condition,
103  // we issue the handshake challenge for a LX200 mount and
104  // abort if it is answered.
105  if(!sendAndExpectTimeout(":GR#", resp, TAF_FOCUSER_BUFSIZE))
106  {
107  DEBUGF(INDI::Logger::DBG_DEBUG, "Device responded to focuser and mount handshake (%s), skipping.", resp);
108  return false;
109  }
110 
111  DEBUGF(INDI::Logger::DBG_DEBUG, "TeenAstroFocuser %s found", &resp[20]);
112  return true;
113 }
114 
116 {
118 
119  strcpy(FocusSyncN[0].label, "Ticks"); // Rename unit of measure to ticks, to avoid confusion with motor steps,
120  strcpy(FocusMaxPosN[0].label, "Ticks"); // motor microsteps and the effect of the resolution setting.
121  strcpy(FocusRelPosN[0].label, "Ticks"); // Ticks are resolution units.
122  strcpy(FocusAbsPosN[0].label, "Ticks");
123 
124  strcpy(FocusReverseSP.group, FOCUS_TAB);
125 
126  strcpy(FocusSpeedNP.label, "Go-to speed");
127  strcpy(FocusSpeedNP.group, FOCUS_TAB);
128  strcpy(FocusSpeedN[0].label, "Steps/s");
129  FocusSpeedN[0].min = TAF_speed_min;
130  FocusSpeedN[0].max = TAF_speed_max;
132 
133  // Main control tab
134  //
135 
136  IUFillNumber(&CfgParkPosN[0], "VAL", "Ticks", "%.f", 0, 100000, 1000, 0);
137  IUFillNumberVector(&CfgParkPosNP, CfgParkPosN, 1, getDeviceName(), "PARK_POS", "Park position", MAIN_CONTROL_TAB, IP_RW, 60,
138  IPS_IDLE );
139 
140  IUFillSwitch(&GoToParkS[0], "VAL", "Park", ISS_OFF);
141  IUFillSwitchVector(&GoToParkSP, GoToParkS, 1, getDeviceName(), "GOTO_PARK", "Go-to park", MAIN_CONTROL_TAB, IP_RW,
142  ISR_ATMOST1, 60, IPS_IDLE );
143 
146  IUFillNumberVector(&CurSpeedNP, CurSpeedN, 1, getDeviceName(), "CUR_SPEED", "Current Speed", MAIN_CONTROL_TAB, IP_RO, 0,
147  IPS_IDLE );
148 
149  IUFillNumber(&TempN[0], "VAL", "Celsius", "%+.1f°", -50., 50., 0, 0);
150  IUFillNumberVector(&TempNP, TempN, 1, getDeviceName(), "TEMP", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE );
151 
152  // Focuser tab
153  //
154 
155  IUFillText(&DeviceVersionT[0], "VAL", "Version", "unknown");
156  IUFillTextVector(&DeviceVersionTP, DeviceVersionT, 1, getDeviceName(), "DEVICE_VERSION", "Device version", FOCUS_TAB, IP_RO,
157  60, IPS_IDLE);
158 
159  // Focuser tab: Motor configuration
160  //
161 
165  "Steps/rev.", FOCUS_TAB, IP_RW, 60, IPS_IDLE );
166 
175 
176  IUFillNumber(&CfgMotorResolutionN[0], "VAL", "Microsteps/tick", "%.f", TAF_res_min, TAF_res_max, TAF_STEP(TAF_res_min,
179  IP_RW, 60, IPS_IDLE );
180 
184  60, IPS_IDLE );
185 
186  // Focuser tab: Motion configuration
187  //
188 
189  IUFillNumber(&CfgGoToAccN[0], "VAL", "Steps/s^2", "%.f", TAF_acc_min, TAF_acc_max, TAF_STEP(TAF_acc_min, TAF_acc_max),
191  IUFillNumberVector(&CfgGoToAccNP, CfgGoToAccN, 1, getDeviceName(), "GOTO_ACCEL", "Go-to accel.", FOCUS_TAB, IP_RW, 60,
192  IPS_IDLE );
193 
196  IUFillNumberVector(&CfgManualSpeedNP, CfgManualSpeedN, 1, getDeviceName(), "MAN_SPEED", "Manual speed", FOCUS_TAB, IP_RW,
197  60, IPS_IDLE );
198 
201  IUFillNumberVector(&CfgManualAccNP, CfgManualAccN, 1, getDeviceName(), "MAN_ACCEL", "Manual accel.", FOCUS_TAB, IP_RW, 60,
202  IPS_IDLE );
203 
206  IUFillNumberVector(&CfgManualDecNP, CfgManualDecN, 1, getDeviceName(), "MAN_DECEL", "Manual decel.", FOCUS_TAB, IP_RW, 60,
207  IPS_IDLE );
208 
209  // Focuser tab: Device actions
210  //
211 
212  IUFillSwitch(&RebootDeviceS[0], "VAL", "Reboot", ISS_OFF);
213  IUFillSwitchVector(&RebootDeviceSP, RebootDeviceS, 1, getDeviceName(), "REBOOT_DEVICE", "Reboot device", FOCUS_TAB, IP_RW,
214  ISR_ATMOST1, 60, IPS_IDLE );
215 
216  IUFillSwitch(&EraseEEPROMS[0], "VAL", "Erase", ISS_OFF);
217  IUFillSwitchVector(&EraseEEPROMSP, EraseEEPROMS, 1, getDeviceName(), "ERASE_EEPROM", "Erase EEPROM", FOCUS_TAB, IP_RW,
218  ISR_ATMOST1, 60, IPS_IDLE );
219 
220  addDebugControl();
221 
222  return true;
223 }
224 
226 {
227  FocusAbsPosN[0].max = FocusRelPosN[0].max = FocusSyncN[0].max = CfgParkPosN[0].max = maxPos;
228  FocusAbsPosN[0].step = FocusRelPosN[0].step = FocusSyncN[0].step = CfgParkPosN[0].step = maxPos / TAF_UI_STEPS;
229 }
230 
232 {
234  return false;
235 
236  if (isConnected())
237  {
238  // Update values from device before defining UI controls.
239  // This minimizes flicker as changes to FocuserMaxPosNP
240  // must redraw all positional controls to update their range.
242  return false;
243 
246 
247  DEBUG(INDI::Logger::DBG_DEBUG, "TeenAstroFocuser ready for use.");
248  }
249  else
250  {
253  }
254 
255  return true;
256 }
257 
259 {
260  deleteProperty(FocusSyncNP.name); // remove superclass controls to improve ordering of UI elements
265 
275 }
276 
278 {
283 }
284 
286 {
287  deleteProperty(FocusReverseSP.name); // Place this on the focuser tab to avoid clutter
289 
291 
297 
303 
306 }
307 
309 {
311 
316 
321 
324 }
325 
326 bool TeenAstroFocuser::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
327 {
328  if(dev == NULL || strcmp(dev, getDeviceName()))
329  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
330 
331  if(!strcmp(name, GoToParkSP.name))
332  {
334  IDSetSwitch(&GoToParkSP, NULL);
335  bool res = goToPark();
336  GoToParkS[0].s = ISS_OFF;
337  GoToParkSP.s = res ? IPS_OK : IPS_ALERT;
338  IDSetSwitch(&GoToParkSP, NULL);
339  return res;
340  }
341  else if(!strcmp(name, CfgMotorMicrostepsSP.name))
342  {
343  // parse selected number of usteps from states and labels. Labels are "Vxxx" where xxx is a number
344  uint32_t usteps = 0;
345  for(int i = 0; i < n; i++)
346  if(states[i] == ISS_ON)
347  usteps = atoi(names[i]);
348 
349  bool res = setMotorMicrosteps(usteps);
350  if(res)
351  IUUpdateSwitch(&CfgMotorMicrostepsSP, states, names, n);
354  return res;
355  }
356  else if(!strcmp(name, RebootDeviceSP.name))
357  {
359  IDSetSwitch(&RebootDeviceSP, NULL);
360  bool res = rebootDevice();
361  RebootDeviceS[0].s = ISS_OFF;
362  RebootDeviceSP.s = res ? IPS_OK : IPS_ALERT;
363  IDSetSwitch(&RebootDeviceSP, NULL);
364  return res;
365  }
366  else if(!strcmp(name, EraseEEPROMSP.name))
367  {
369  IDSetSwitch(&EraseEEPROMSP, NULL);
370  bool res = eraseDeviceEEPROM();
371  EraseEEPROMS[0].s = ISS_OFF;
372  EraseEEPROMSP.s = res ? IPS_OK : IPS_ALERT;
373  IDSetSwitch(&EraseEEPROMSP, NULL);
374  return res;
375  }
376  else
377  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
378 }
379 
380 bool TeenAstroFocuser::ISNewNumberHelper(INumberVectorProperty *NP, double values[], char *names[], int n, bool res)
381 {
382  if(res)
383  IUUpdateNumber(NP, values, names, n);
384  NP->s = res ? IPS_OK : IPS_ALERT;
385  IDSetNumber(NP, NULL);
386  return res;
387 }
388 
389 bool TeenAstroFocuser::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
390 {
391  if(dev == NULL || strcmp(dev, getDeviceName()))
392  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
393 
394  if(!strcmp(name, FocusSyncNP.name))
395  {
396  bool res = SyncFocuser((uint32_t) rint(values[0]));
397  return ISNewNumberHelper(&FocusSyncNP, values, names, n, res);
398  }
399  else if(!strcmp(name, CfgParkPosNP.name))
400  {
401  bool res = setParkPos((uint32_t) rint(values[0]));
402  return ISNewNumberHelper(&CfgParkPosNP, values, names, n, res);
403  }
404  else if(!strcmp(name, FocusMaxPosNP.name))
405  {
406  uint32_t val = (uint32_t) rint(values[0]);
407  bool res = SetFocuserMaxPosition(val);
408  if(res && FocusMaxPosN[0].value != val)
409  {
411  deleteMainControlProperties(); // Force redraw of UI controls as IUUpdateMinMax
412  defineMainControlProperties(); // does not reliably update the step size.
413  }
414  return ISNewNumberHelper(&FocusMaxPosNP, values, names, n, res);
415  }
416  else if(!strcmp(name, CfgManualSpeedNP.name))
417  {
418  bool res = setManualSpeed((uint32_t) rint(values[0]));
419  return ISNewNumberHelper(&CfgManualSpeedNP, values, names, n, res);
420  }
421  else if(!strcmp(name, FocusSpeedNP.name))
422  {
423  bool res = SetFocuserSpeed(rint(values[0]));
424  return ISNewNumberHelper(&FocusSpeedNP, values, names, n, res);
425  }
426  else if(!strcmp(name, CfgGoToAccNP.name))
427  {
428  bool res = setGoToAcc((uint32_t) rint(values[0]));
429  return ISNewNumberHelper(&CfgGoToAccNP, values, names, n, res);
430  }
431  else if(!strcmp(name, CfgManualAccNP.name))
432  {
433  bool res = setManualAcc((uint32_t) rint(values[0]));
434  return ISNewNumberHelper(&CfgManualAccNP, values, names, n, res);
435  }
436  else if(!strcmp(name, CfgManualDecNP.name))
437  {
438  bool res = setManualDec((uint32_t) rint(values[0]));
439  return ISNewNumberHelper(&CfgManualDecNP, values, names, n, res);
440  }
441  else if(!strcmp(name, CfgMotorStepsPerRevolutionNP.name))
442  {
443  bool res = setMotorStepsPerRevolution((uint32_t) rint(values[0]));
444  return ISNewNumberHelper(&CfgMotorStepsPerRevolutionNP, values, names, n, res);
445  }
446  else if(!strcmp(name, CfgMotorResolutionNP.name))
447  {
448  bool res = setMotorResolution((uint32_t) rint(values[0]));
449  return ISNewNumberHelper(&CfgMotorResolutionNP, values, names, n, res);
450  }
451  else if(!strcmp(name, CfgMotorCurrentNP.name))
452  {
453  bool res = setMotorCurrent((uint32_t) rint(values[0]));
454  return ISNewNumberHelper(&CfgMotorCurrentNP, values, names, n, res);
455  }
456  else
457  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
458 }
459 
460 
462 {
464  IDSetNumber(&FocusAbsPosNP, NULL);
466  IDSetNumber(&FocusRelPosNP, NULL);
467 
468  if(!goTo(pos))
469  {
471  IDSetNumber(&FocusAbsPosNP, NULL);
473  IDSetNumber(&FocusRelPosNP, NULL);
474 
475  return IPS_ALERT;
476  }
477  return IPS_BUSY;
478 }
479 
481 {
482  FocusRelPosN[0].value = ticks;
483 
484  uint32_t pos = uint32_t(FocusAbsPosN[0].value);
485  if (dir == FOCUS_INWARD)
486  pos -= ticks;
487  else
488  pos += ticks;
489 
490  return MoveAbsFocuser(pos);
491 }
492 
494 {
495  if(!isConnected())
496  return;
497 
498  updateState();
500 }
501 
503 {
505  IDSetSwitch(&FocusAbortSP, NULL);
506 
507  if(!stop())
508  {
510  IDSetSwitch(&FocusAbortSP, NULL);
511  return false;
512  }
514  IDSetSwitch(&FocusAbortSP, NULL);
515 
516  return updateState();
517 }
518 
519 
520 // Protected methods
521 //
522 
523 bool TeenAstroFocuser::send(const char *const msg)
524 {
525  DEBUGF(INDI::Logger::DBG_DEBUG, "send(\"%s\")", msg);
526 
527  tcflush(PortFD, TCIOFLUSH);
528 
529  int nbytes_written = 0, rc = -1;
530  if ( (rc = tty_write(PortFD, msg, strlen(msg), &nbytes_written)) != TTY_OK)
531  {
532  char errstr[MAXRBUF];
533  tty_error_msg(rc, errstr, MAXRBUF);
534  DEBUGF(INDI::Logger::DBG_ERROR, "send(\"%s\"): %s.", msg, errstr);
535  return false;
536  }
537  return true;
538 }
539 
540 
541 bool TeenAstroFocuser::sendAndReceive(const char *const msg, char *resp, int bufsize)
542 {
543  if(!send(msg))
544  return false;
545 
546  int nbytes_read = 0;
547  int rc = tty_nread_section(PortFD, resp, bufsize, '#', TAF_FOCUSER_TIMEOUT, &nbytes_read);
548  resp[nbytes_read] = '\0';
549  if(rc != TTY_OK || nbytes_read == 0 || resp[nbytes_read - 1] != '#')
550  {
551  char errstr[MAXRBUF];
552  tty_error_msg(rc, errstr, MAXRBUF);
553  DEBUGF(INDI::Logger::DBG_ERROR, "sendAndReceive(\"%s\") received \"%s\": %s.", msg, resp, errstr);
554  return false;
555  }
556  DEBUGF(INDI::Logger::DBG_DEBUG, "sendAndReceive(\"%s\") received \"%s\".", msg, resp);
557  return true;
558 }
559 
560 bool TeenAstroFocuser::sendAndReceiveBool(const char *const msg)
561 {
562  if(!send(msg))
563  return false;
564 
565  char resp[2];
566  int nbytes_read = 0;
567  int rc = tty_read(PortFD, resp, 1, TAF_FOCUSER_TIMEOUT, &nbytes_read);
568  resp[nbytes_read] = '\0';
569  if(rc != TTY_OK || resp[0] != '1')
570  {
571  char errstr[MAXRBUF];
572  tty_error_msg(rc, errstr, MAXRBUF);
573  DEBUGF(INDI::Logger::DBG_ERROR, "sendAndReceiveBool(\"%s\") received \"%s\": %s.", msg, resp, errstr);
574  return false;
575  }
576  DEBUGF(INDI::Logger::DBG_DEBUG, "sendAndReceiveBool(\"%s\") received \"%s\".", msg, resp);
577  return resp[0] == '1';
578 }
579 
580 
581 bool TeenAstroFocuser::sendAndExpectTimeout(const char *const msg, char *resp, int bufsize)
582 {
583  if(!send(msg))
584  return false;
585 
586  int nbytes_read = 0;
587  int rc = tty_nread_section(PortFD, resp, bufsize, '#', TAF_FOCUSER_TIMEOUT, &nbytes_read);
588  resp[nbytes_read] = '\0';
589  if(rc != TTY_TIME_OUT || nbytes_read != 0)
590  {
591  char errstr[MAXRBUF];
592  tty_error_msg(rc, errstr, MAXRBUF);
593  DEBUGF(INDI::Logger::DBG_ERROR, "sendAndExpectTimeout(\"%s\") received \"%s\".", msg, resp);
594  return false;
595  }
596  DEBUGF(INDI::Logger::DBG_DEBUG, "sendAndExpectTimeout(\"%s\") got timeout.", msg, resp);
597  return true;
598 }
599 
600 
602 {
603  char resp[TAF_FOCUSER_BUFSIZE];
604  if(!sendAndReceive(":FV#", resp, TAF_FOCUSER_BUFSIZE))
605  return false;
606  int len = strlen(resp);
607  resp[len - 1] = 0;
608  IUSaveText(&DeviceVersionT[0], resp + 2);
610  IDSetText(&DeviceVersionTP, NULL);
611  return true;
612 }
613 
615 {
616  char resp[TAF_FOCUSER_BUFSIZE];
617  int pos = -1, speed = -1;
618  float temp = -1;
619 
620  if(!sendAndReceive(":F?#", resp, TAF_FOCUSER_BUFSIZE))
621  return false;
622 
623  if(sscanf(resp, "?%d %d %f#", &pos, &speed, &temp) <= 0)
624  {
625  DEBUGF(INDI::Logger::DBG_ERROR, "Invalid format: focuser state (%s)", resp);
626  return false;
627  }
628 
629  if(FocusAbsPosNP.s == IPS_BUSY && speed == 0)
630  DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached target position.");
631 
632  FocusAbsPosN[0].value = pos;
633  FocusAbsPosNP.s = speed > 0 ? IPS_BUSY : IPS_OK;
634  IDSetNumber(&FocusAbsPosNP, NULL);
635 
636  FocusRelPosNP.s = speed > 0 ? IPS_BUSY : IPS_OK;
637  IDSetNumber(&FocusRelPosNP, NULL);
638 
639  CurSpeedN[0].value = speed;
640  CurSpeedNP.s = speed > 0 ? IPS_BUSY : IPS_OK;
641  IDSetNumber(&CurSpeedNP, NULL);
642 
643  TempN[0].value = temp;
644  TempNP.s = (temp == -99) ? IPS_ALERT : IPS_OK;
645  IDSetNumber(&TempNP, NULL);
646 
647  return true;
648 }
649 
651 {
652  if(!updateState())
653  return false;
654  return CurSpeedN[0].value > 0;
655 }
656 
657 
659 {
660  char resp[TAF_FOCUSER_BUFSIZE];
661  int parkPos = -1, maxPos = -1, manualSpeed = -1, goToSpeed = -1, gotoAcc = -1, manAcc = -1, manDec = -1;
662 
663  if(!sendAndReceive(":F~#", resp, TAF_FOCUSER_BUFSIZE))
664  return false;
665 
666  if(sscanf(resp, "~%d %d %d %d %d %d %d#", &parkPos, &maxPos, &manualSpeed, &goToSpeed, &gotoAcc, &manAcc, &manDec) <= 0)
667  {
668  DEBUGF(INDI::Logger::DBG_ERROR, "Invalid format: focuser motion config (%s)", resp);
669  return false;
670  }
671 
672  if(maxPos != FocusMaxPosN[0].value)
674 
675  CfgParkPosN[0].value = parkPos;
677  IDSetNumber(&CfgParkPosNP, NULL);
678  FocusMaxPosN[0].value = maxPos;
680  IDSetNumber(&FocusMaxPosNP, NULL);
681  CfgManualSpeedN[0].value = manualSpeed;
684  FocusSpeedN[0].value = goToSpeed;
686  IDSetNumber(&FocusSpeedNP, NULL);
687  CfgGoToAccN[0].value = gotoAcc;
689  IDSetNumber(&CfgGoToAccNP, NULL);
690  CfgManualAccN[0].value = manAcc;
692  IDSetNumber(&CfgManualAccNP, NULL);
693  CfgManualDecN[0].value = manDec;
695  IDSetNumber(&CfgManualDecNP, NULL);
696 
697  return true;
698 }
699 
700 bool TeenAstroFocuser::setConfigItem(char item, uint32_t deviceValue)
701 {
702  char cmd[64];
703  snprintf(cmd, 64, ":F%c,%d#", item, deviceValue);
704  return sendAndReceiveBool(cmd);
705 }
706 
707 bool TeenAstroFocuser::setParkPos(uint32_t value)
708 {
709  return setConfigItem('0', value);
710 }
711 
713 {
714  return setConfigItem('1', value);
715 }
716 
718 {
719  return setConfigItem('2', value);
720 }
721 
723 {
724  return setConfigItem('3', (uint32_t) value);
725 }
726 
727 bool TeenAstroFocuser::setGoToAcc(uint32_t value)
728 {
729  return setConfigItem('4', value);
730 }
731 
732 bool TeenAstroFocuser::setManualAcc(uint32_t value)
733 {
734  return setConfigItem('5', value);
735 }
736 
737 bool TeenAstroFocuser::setManualDec(uint32_t value)
738 {
739  return setConfigItem('6', value);
740 }
741 
742 
744 {
745  char resp[TAF_FOCUSER_BUFSIZE];
746  int reverse = -1, log2_micro = -1, resolution = -1, curr_10ma = -1, steprot = -1;
747 
748  if(!sendAndReceive(":FM#", resp, TAF_FOCUSER_BUFSIZE))
749  return false;
750 
751  if(sscanf(resp, "M%d %d %d %d %d#", &reverse, &log2_micro, &resolution, &curr_10ma, &steprot) <= 0)
752  {
753  DEBUGF(INDI::Logger::DBG_ERROR, "Invalid format: focuser motor config (%s)", resp);
754  return false;
755  }
756 
757  FocusReverseS[0].s = (reverse == 0) ? ISS_OFF : ISS_ON;
758  FocusReverseS[1].s = (reverse == 0) ? ISS_ON : ISS_OFF;
760  IDSetSwitch(&FocusReverseSP, NULL);
761 
762  uint32_t micro = (1 << log2_micro); // TeenAstro device returns and expects log_2(microsteps)
763  bool microFound = false;
764  for(int i = 0; i < TAF_MICROS_N; i++)
765  {
766  uint32_t thisMicro = (uint32_t) atoi(CfgMotorMicrostepsS[i].name);
767  CfgMotorMicrostepsS[i].s = (micro == thisMicro) ? ISS_ON : ISS_OFF;
768  if(micro == thisMicro)
769  microFound = true;
770  }
771  CfgMotorMicrostepsSP.s = microFound ? IPS_OK : IPS_ALERT;
773 
774  CfgMotorResolutionN[0].value = resolution;
777  CfgMotorCurrentN[0].value = curr_10ma * 10; // TeenAstro device returns and expects units of 10 mA
780  CfgMotorStepsPerRevolutionN[0].value = steprot;
783 
784  return true;
785 }
786 
788 {
789  return setConfigItem('7', enable ? 1 : 0);
790 }
791 
793 {
794  uint32_t bitPos = 0;
795  value >>= 1;
796  for(; value != 0; bitPos++)
797  value >>= 1;
798  return setConfigItem('m', bitPos); // TeenAstro device returns and expects log_2(microsteps)
799 }
800 
802 {
803  return setConfigItem('8', value);
804 }
805 
807 {
808  return setConfigItem('c', value / 10); // TeenAstro device returns and expects units of 10 mA
809 }
810 
812 {
813  return setConfigItem('r', value);
814 }
815 
816 bool TeenAstroFocuser::SyncFocuser(uint32_t value)
817 {
818  char cmd[64];
819  snprintf(cmd, 64, ":FS,%d#", value);
820  return send(cmd); // no confirmation via "0" or "1"
821 }
822 
823 
824 bool TeenAstroFocuser::goTo(uint32_t position)
825 {
826  char cmd[64];
827  snprintf(cmd, 64, ":FG,%d#", position);
828  return send(cmd);
829 }
830 
832 {
833  return send(":FP#");
834 }
835 
837 {
838  return send(":FQ#");
839 }
840 
842 {
843  if(!send(":F!#"))
844  return false;
845  sleep(3);
847 }
848 
850 {
851  if(!send(":F$#"))
852  return false;
853  sleep(1);
855 }
856 
858 {
859  // This is a verbatim copy of Focuser::saveConfigItems except one override
860  //
861 
862  DefaultDevice::saveConfigItems(fp);
863 
864  // Do not save focuser configuration items on INDI host, as they are stored on the focuser device.
865  // FI::saveConfigItems(fp);
866 
868  this->controller->saveConfigItems(fp);
869 
870  return true;
871 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool saveConfigItems(FILE *fp)
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INumberVectorProperty FocusSpeedNP
INumberVectorProperty FocusSyncNP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumberVectorProperty FocusMaxPosNP
ISwitchVectorProperty FocusAbortSP
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
INumberVectorProperty PresetNP
Definition: indifocuser.h:108
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Controller * controller
Definition: indifocuser.h:114
ISwitchVectorProperty RebootDeviceSP
Definition: teenastro.h:203
bool setManualSpeed(uint32_t value)
Definition: teenastro.cpp:717
void deleteOtherProperties()
Definition: teenastro.cpp:308
ISwitchVectorProperty CfgMotorMicrostepsSP
Definition: teenastro.h:187
INumberVectorProperty CfgMotorResolutionNP
Definition: teenastro.h:191
bool setMotorCurrent(uint32_t value)
Definition: teenastro.cpp:806
bool setManualAcc(uint32_t value)
Definition: teenastro.cpp:732
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
Definition: teenastro.cpp:326
bool sendAndReceiveBool(const char *const msg)
Definition: teenastro.cpp:560
bool setConfigItem(char item, uint32_t deviceValue)
Definition: teenastro.cpp:700
void deleteMainControlProperties()
Definition: teenastro.cpp:277
void defineOtherProperties()
Definition: teenastro.cpp:285
virtual bool AbortFocuser()
AbortFocuser all focus motion.
Definition: teenastro.cpp:502
INumber CfgManualAccN[1]
Definition: teenastro.h:168
virtual void TimerHit()
Callback function to be called once SetTimer duration elapses.
Definition: teenastro.cpp:493
bool saveConfigItems(FILE *fp)
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: teenastro.cpp:857
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
Definition: teenastro.cpp:389
bool setMotorStepsPerRevolution(uint32_t value)
Definition: teenastro.cpp:811
bool send(const char *const msg)
Definition: teenastro.cpp:523
INumberVectorProperty TempNP
Definition: teenastro.h:145
void initPositionPropertiesRanges(uint32_t maxPos)
Definition: teenastro.cpp:225
bool ReverseFocuser(bool enable)
ReverseFocuser Reverse focuser motion direction.
Definition: teenastro.cpp:787
virtual bool SyncFocuser(uint32_t value)
SyncFocuser Set current position to ticks without moving the focuser.
Definition: teenastro.cpp:816
void defineMainControlProperties()
Definition: teenastro.cpp:258
INumberVectorProperty CfgManualSpeedNP
Definition: teenastro.h:161
bool updateMotorConfig()
Definition: teenastro.cpp:743
INumber TempN[1]
Definition: teenastro.h:144
bool eraseDeviceEEPROM()
Definition: teenastro.cpp:849
bool setMotorMicrosteps(uint32_t value)
Definition: teenastro.cpp:792
INumberVectorProperty CfgGoToAccNP
Definition: teenastro.h:165
bool setMotorResolution(uint32_t value)
Definition: teenastro.cpp:801
ITextVectorProperty DeviceVersionTP
Definition: teenastro.h:155
ISwitchVectorProperty GoToParkSP
Definition: teenastro.h:134
ISwitch RebootDeviceS[1]
Definition: teenastro.h:202
const char * getDefaultName()
Definition: teenastro.cpp:77
bool SetFocuserMaxPosition(uint32_t value)
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
Definition: teenastro.cpp:712
INumber CurSpeedN[1]
Definition: teenastro.h:140
bool sendAndReceive(const char *const msg, char *resp, int bufsize)
Definition: teenastro.cpp:541
ISwitchVectorProperty EraseEEPROMSP
Definition: teenastro.h:207
bool updateDeviceVersion()
Definition: teenastro.cpp:601
ISwitch GoToParkS[1]
Definition: teenastro.h:133
bool sendAndExpectTimeout(const char *const msg, char *resp, int bufsize)
Definition: teenastro.cpp:581
INumberVectorProperty CfgMotorStepsPerRevolutionNP
Definition: teenastro.h:199
INumber CfgMotorStepsPerRevolutionN[1]
Definition: teenastro.h:198
INumber CfgMotorCurrentN[1]
Definition: teenastro.h:194
ISwitch CfgMotorMicrostepsS[TAF_MICROS_N]
Definition: teenastro.h:186
IText DeviceVersionT[1]
Definition: teenastro.h:154
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks)
MoveFocuser the focuser to an relative position.
Definition: teenastro.cpp:480
bool ISNewNumberHelper(INumberVectorProperty *NP, double values[], char *names[], int n, bool res)
Definition: teenastro.cpp:380
INumber CfgParkPosN[1]
Definition: teenastro.h:129
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: teenastro.cpp:231
INumberVectorProperty CfgManualDecNP
Definition: teenastro.h:173
bool SetFocuserSpeed(int value)
SetFocuserSpeed Set Focuser speed.
Definition: teenastro.cpp:722
bool setParkPos(uint32_t value)
Definition: teenastro.cpp:707
INumberVectorProperty CfgParkPosNP
Definition: teenastro.h:130
ISwitch EraseEEPROMS[1]
Definition: teenastro.h:206
bool setManualDec(uint32_t value)
Definition: teenastro.cpp:737
INumber CfgMotorResolutionN[1]
Definition: teenastro.h:190
INumberVectorProperty CurSpeedNP
Definition: teenastro.h:141
virtual IPState MoveAbsFocuser(uint32_t ticks)
MoveFocuser the focuser to an absolute position.
Definition: teenastro.cpp:461
INumber CfgGoToAccN[1]
Definition: teenastro.h:164
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
Definition: teenastro.cpp:115
virtual bool Handshake()
perform handshake with device to check communication
Definition: teenastro.cpp:82
INumber CfgManualSpeedN[1]
Definition: teenastro.h:160
bool updateMotionConfig()
Definition: teenastro.cpp:658
INumberVectorProperty CfgMotorCurrentNP
Definition: teenastro.h:195
INumberVectorProperty CfgManualAccNP
Definition: teenastro.h:169
INumber CfgManualDecN[1]
Definition: teenastro.h:172
bool goTo(uint32_t position)
Definition: teenastro.cpp:824
bool setGoToAcc(uint32_t value)
Definition: teenastro.cpp:727
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
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_ATMOST1
Definition: indiapi.h:174
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
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
@ TTY_TIME_OUT
Definition: indicom.h:154
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
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
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
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
#define MAXRBUF
Definition: indiserver.cpp:102
__u8 cmd[4]
Definition: pwc-ioctl.h:2
Number vector property descriptor.
Definition: indiapi.h:319
char group[MAXINDIGROUP]
Definition: indiapi.h:327
char name[MAXINDINAME]
Definition: indiapi.h:323
char label[MAXINDILABEL]
Definition: indiapi.h:325
char name[MAXINDINAME]
Definition: indiapi.h:371
char group[MAXINDIGROUP]
Definition: indiapi.h:375
char name[MAXINDINAME]
Definition: indiapi.h:250
#define TAF_acc_min
Definition: teenastro.cpp:48
#define TAF_res_max
Definition: teenastro.cpp:52
#define TAF_steprot_default
Definition: teenastro.cpp:38
#define TAF_speed_min
Definition: teenastro.cpp:45
#define TAF_steprot_max
Definition: teenastro.cpp:40
std::unique_ptr< TeenAstroFocuser > teenAstroFocuser(new TeenAstroFocuser())
#define TAF_speed_max
Definition: teenastro.cpp:46
#define TAF_speed_default
Definition: teenastro.cpp:44
#define TAF_FOCUSER_TIMEOUT
Definition: teenastro.cpp:58
#define TAF_res_min
Definition: teenastro.cpp:51
#define TAF_curr_min
Definition: teenastro.cpp:33
#define TAF_acc_max
Definition: teenastro.cpp:49
#define TAF_acc_default
Definition: teenastro.cpp:47
#define TAF_curr_max
Definition: teenastro.cpp:34
#define TAF_steprot_min
Definition: teenastro.cpp:39
#define TAF_res_default
Definition: teenastro.cpp:50
#define TAF_UI_STEPS
Definition: teenastro.cpp:54
#define TAF_FOCUSER_BUFSIZE
Definition: teenastro.cpp:59
#define TAF_curr_default
Definition: teenastro.cpp:32
#define TAF_STEP(min, max)
Definition: teenastro.cpp:55