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