Instrument Neutral Distributed Interface INDI  2.0.2
dmfc.cpp
Go to the documentation of this file.
1 /*
2  Pegasus DMFC Focuser
3  Copyright (C) 2017 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 "dmfc.h"
22 
23 #include "indicom.h"
25 
26 #include <cmath>
27 #include <cstring>
28 #include <memory>
29 
30 #include <termios.h>
31 #include <unistd.h>
32 
33 #define DMFC_TIMEOUT 3
34 #define FOCUS_SETTINGS_TAB "Settings"
35 #define TEMPERATURE_THRESHOLD 0.1
36 
37 static std::unique_ptr<DMFC> dmfc(new DMFC());
38 
40 {
41  setVersion(1, 1);
42 
43  // Can move in Absolute & Relative motions, can AbortFocuser motion.
50 }
51 
53 {
55 
56  // Focuser temperature
57  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
58  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
60 
61  // Max Speed
62  IUFillNumber(&MaxSpeedN[0], "Value", "", "%6.2f", 100, 1000., 100., 400.);
63  IUFillNumberVector(&MaxSpeedNP, MaxSpeedN, 1, getDeviceName(), "MaxSpeed", "", FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
64 
65  // Encoders
66  IUFillSwitch(&EncoderS[ENCODERS_ON], "On", "", ISS_ON);
67  IUFillSwitch(&EncoderS[ENCODERS_OFF], "Off", "", ISS_OFF);
68  IUFillSwitchVector(&EncoderSP, EncoderS, 2, getDeviceName(), "Encoders", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0,
69  IPS_IDLE);
70 
71  // Motor Modes
72  IUFillSwitch(&MotorTypeS[MOTOR_DC], "DC", "DC", ISS_OFF);
73  IUFillSwitch(&MotorTypeS[MOTOR_STEPPER], "Stepper", "Stepper", ISS_ON);
74  IUFillSwitchVector(&MotorTypeSP, MotorTypeS, 2, getDeviceName(), "Motor Type", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY,
75  0, IPS_IDLE);
76 
77  // LED
78  IUFillSwitch(&LEDS[LED_OFF], "Off", "", ISS_ON);
79  IUFillSwitch(&LEDS[LED_ON], "On", "", ISS_OFF);
80  IUFillSwitchVector(&LEDSP, LEDS, 2, getDeviceName(), "LED", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
81 
82  // Firmware Version
83  IUFillText(&FirmwareVersionT[0], "Version", "Version", "");
84  IUFillTextVector(&FirmwareVersionTP, FirmwareVersionT, 1, getDeviceName(), "Firmware", "Firmware", MAIN_CONTROL_TAB, IP_RO,
85  0, IPS_IDLE);
86 
87  // Relative and absolute movement
88  FocusRelPosN[0].min = 0.;
89  FocusRelPosN[0].max = 50000.;
90  FocusRelPosN[0].value = 0;
91  FocusRelPosN[0].step = 1000;
92 
93  FocusAbsPosN[0].min = 0.;
94  FocusAbsPosN[0].max = 100000;
95  FocusAbsPosN[0].value = 0;
96  FocusAbsPosN[0].step = 1000;
97 
98  // Backlash compensation
99  FocusBacklashN[0].min = 1; // 0 is off.
100  FocusBacklashN[0].max = 1000;
101  FocusBacklashN[0].value = 1;
102  FocusBacklashN[0].step = 1;
103 
104  //LED Default ON
105  LEDS[LED_ON].s = ISS_ON;
106  LEDS[LED_OFF].s = ISS_OFF;
107 
108  addDebugControl();
111 
112  return true;
113 }
114 
115 void DMFC::ISGetProperties(const char *dev)
116 {
118  int configSwitch = MOTOR_STEPPER;
119 
120  // Try to read config value for motor type
121  // If relative, then update the capability of the focuser as such.
122  if (IUGetConfigOnSwitchIndex(getDeviceName(), MotorTypeSP.name, &configSwitch) == 0)
123  {
124  // We are only relative focuser now.
125  if (configSwitch == MOTOR_DC)
127  else
129 
130  MotorTypeSP.s = IPS_OK;
131  }
132 
133  IUResetSwitch(&MotorTypeSP);
134  MotorTypeS[configSwitch].s = ISS_ON;
135  defineProperty(&MotorTypeSP);
136 }
137 
139 {
141 
142  if (isConnected())
143  {
144  defineProperty(&TemperatureNP);
145  defineProperty(&EncoderSP);
146  defineProperty(&MaxSpeedNP);
147  defineProperty(&LEDSP);
148  defineProperty(&FirmwareVersionTP);
149  }
150  else
151  {
152  deleteProperty(TemperatureNP.name);
153  deleteProperty(EncoderSP.name);
154  deleteProperty(MaxSpeedNP.name);
155  deleteProperty(LEDSP.name);
156  deleteProperty(FirmwareVersionTP.name);
157  }
158 
159  return true;
160 }
161 
163 {
164  if (ack())
165  {
166  LOGF_INFO("%s is online. Getting focus parameters...", this->getDeviceName());
167 
168  // Set motor type on startup only.
169  setMotorType((MotorTypeS[MOTOR_DC].s == ISS_ON) ? MOTOR_DC : MOTOR_STEPPER);
170 
171  return true;
172  }
173 
174  LOGF_INFO(
175  "Error retrieving data from %s, please ensure device is powered and the port is correct.", this->getDeviceName());
176  return false;
177 }
178 
179 
180 const char *DMFC::getDefaultName()
181 {
182  return "Pegasus DMFC";
183 }
184 
185 bool DMFC::ack()
186 {
187  int nbytes_written = 0, nbytes_read = 0, rc = -1;
188  char errstr[MAXRBUF];
189  char cmd[2] = {0};
190  char res[16] = {0};
191 
192  cmd[0] = '#';
193  cmd[1] = 0xA;
194 
195  LOGF_DEBUG("CMD <%#02X>", cmd[0]);
196 
197  tcflush(PortFD, TCIOFLUSH);
198 
199  if ((rc = tty_write(PortFD, cmd, 2, &nbytes_written)) != TTY_OK)
200  {
201  tty_error_msg(rc, errstr, MAXRBUF);
202  LOGF_ERROR("Ack error: %s.", errstr);
203  return false;
204  }
205 
206  if ((rc = tty_read_section(PortFD, res, 0xA, DMFC_TIMEOUT, &nbytes_read)) != TTY_OK)
207  {
208  tty_error_msg(rc, errstr, MAXRBUF);
209  LOGF_ERROR("Ack error: %s.", errstr);
210  return false;
211  }
212 
213  // Get rid of 0xA
214  res[nbytes_read - 1] = 0;
215 
216 
217  if( res[nbytes_read - 2] == '\r') res[nbytes_read - 2] = 0;
218 
219  LOGF_DEBUG("RES <%s>", res);
220 
221  tcflush(PortFD, TCIOFLUSH);
222 
223  if((strstr(res, "OK_DMFCN") != nullptr) || (strstr(res, "OK_SMFC") != nullptr) || (strstr(res, "OK_PRDG") != nullptr))
224  return true;
225 
226  return false;
227 }
228 
229 
230 bool DMFC::SyncFocuser(uint32_t ticks)
231 {
232  int nbytes_written = 0, rc = -1;
233  char cmd[16] = {0};
234 
235  snprintf(cmd, 16, "W:%ud", ticks);
236  cmd[strlen(cmd)] = 0xA;
237 
238  LOGF_DEBUG("CMD <%s>", cmd);
239 
240  // Set Position
241  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
242  {
243  char errstr[MAXRBUF];
244  tty_error_msg(rc, errstr, MAXRBUF);
245  LOGF_ERROR("sync error: %s.", errstr);
246  return false;
247  }
248 
249  this->ignoreResponse();
250 
251  return true;
252 }
253 
254 bool DMFC::moveAbsolute(uint32_t newPosition)
255 {
256  int nbytes_written = 0, rc = -1;
257  char cmd[16] = {0};
258 
259  snprintf(cmd, 16, "M:%ud", newPosition);
260  cmd[strlen(cmd)] = 0xA;
261 
262  LOGF_DEBUG("CMD <%s>", cmd);
263 
264  // Set Position
265  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
266  {
267  char errstr[MAXRBUF];
268  tty_error_msg(rc, errstr, MAXRBUF);
269  LOGF_ERROR("Absolute move error: %s.", errstr);
270  return false;
271  }
272 
273  this->ignoreResponse();
274 
275  return true;
276 }
277 
278 bool DMFC::moveRelative(int relativePosition)
279 {
280  int nbytes_written = 0, rc = -1;
281  char cmd[16] = {0};
282 
283  snprintf(cmd, 16, "G:%d", relativePosition);
284  cmd[strlen(cmd)] = 0xA;
285 
286  LOGF_DEBUG("CMD <%s>", cmd);
287 
288  // Set Relative Position
289  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
290  {
291  char errstr[MAXRBUF];
292  tty_error_msg(rc, errstr, MAXRBUF);
293  LOGF_ERROR("Relative move error: %s.", errstr);
294  return false;
295  }
296 
297  this->ignoreResponse();
298 
299  return true;
300 }
301 
302 bool DMFC::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
303 {
304  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
305  {
306  // Motor Type
307  if (!strcmp(name, MotorTypeSP.name))
308  {
309  IUUpdateSwitch(&MotorTypeSP, states, names, n);
310  MotorTypeSP.s = IPS_OK;
311  saveConfig(true, MotorTypeSP.name);
312 
313  // If we're not connected, let's then set the capability now.
314  if (!isConnected())
315  {
316  // We are only relative focuser now.
317  if (MotorTypeS[MOTOR_DC].s == ISS_ON)
319  else
321  }
322  else
323  LOG_INFO("Motor type changed. Please restart driver for this change to take effect.");
324 
325  IDSetSwitch(&MotorTypeSP, nullptr);
326  return true;
327  }
328 
329  // Encoders
330  if (!strcmp(name, EncoderSP.name))
331  {
332  IUUpdateSwitch(&EncoderSP, states, names, n);
333  bool rc = setEncodersEnabled(EncoderS[ENCODERS_ON].s == ISS_ON);
334  EncoderSP.s = rc ? IPS_OK : IPS_ALERT;
335  IDSetSwitch(&EncoderSP, nullptr);
336  return true;
337  }
338 
339  // LED
340  if (!strcmp(name, LEDSP.name))
341  {
342  IUUpdateSwitch(&LEDSP, states, names, n);
343  bool rc = setLedEnabled(LEDS[LED_ON].s == ISS_ON);
344  LEDSP.s = rc ? IPS_OK : IPS_ALERT;
345  IDSetSwitch(&LEDSP, nullptr);
346  return true;
347  }
348  }
349  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
350 }
351 
352 bool DMFC::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
353 {
354  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
355  {
356  // MaxSpeed
357  if (strcmp(name, MaxSpeedNP.name) == 0)
358  {
359  IUUpdateNumber(&MaxSpeedNP, values, names, n);
360  bool rc = setMaxSpeed(MaxSpeedN[0].value);
361  MaxSpeedNP.s = rc ? IPS_OK : IPS_ALERT;
362  IDSetNumber(&MaxSpeedNP, nullptr);
363  return true;
364  }
365  }
366 
367  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
368 }
369 
370 void DMFC::ignoreResponse()
371 {
372  int nbytes_read = 0;
373  char res[64];
374  tty_read_section(PortFD, res, 0xA, DMFC_TIMEOUT, &nbytes_read);
375 }
376 
377 bool DMFC::updateFocusParams()
378 {
379  int nbytes_written = 0, nbytes_read = 0, rc = -1;
380  char errstr[MAXRBUF];
381  char cmd[3] = {0};
382  char res[64];
383  cmd[0] = 'A';
384  cmd[1] = 0xA;
385 
386  LOGF_DEBUG("CMD <%#02X>", cmd[0]);
387 
388  tcflush(PortFD, TCIOFLUSH);
389 
390  if ((rc = tty_write(PortFD, cmd, 2, &nbytes_written)) != TTY_OK)
391  {
392  tty_error_msg(rc, errstr, MAXRBUF);
393  LOGF_ERROR("GetFocusParams error: %s.", errstr);
394  return false;
395  }
396 
397 
398  if ((rc = tty_read_section(PortFD, res, 0xA, DMFC_TIMEOUT, &nbytes_read)) != TTY_OK)
399  {
400  tty_error_msg(rc, errstr, MAXRBUF);
401  LOGF_ERROR("GetFocusParams error: %s.", errstr);
402  return false;
403  }
404 
405  res[nbytes_read - 1] = 0;
406 
407  // Check for '\r' at end of string and replace with nullptr (DMFC firmware version 2.8)
408  if( res[nbytes_read - 2] == '\r') res[nbytes_read - 2] = 0;
409 
410  LOGF_DEBUG("RES <%s>", res);
411 
412  tcflush(PortFD, TCIOFLUSH);
413 
414  char *token = std::strtok(res, ":");
415 
416 
417  // #1 Status
418  if (token == nullptr || ((strstr(token, "OK_DMFCN") == nullptr) && (strstr(token, "OK_SMFC") == nullptr)
419  && (strstr(token, "OK_PRDG") == nullptr)))
420  {
421  LOGF_ERROR("Invalid status response. %s", res);
422  return false;
423  }
424 
425  // #2 Version
426  token = std::strtok(nullptr, ":");
427 
428  if (token == nullptr)
429  {
430  LOG_ERROR("Invalid version response.");
431  return false;
432  }
433 
434  if (FirmwareVersionT[0].text == nullptr || strcmp(FirmwareVersionT[0].text, token))
435  {
436  IUSaveText(&FirmwareVersionT[0], token);
437  FirmwareVersionTP.s = IPS_OK;
438  IDSetText(&FirmwareVersionTP, nullptr);
439  }
440 
441  // #3 Motor Type
442  token = std::strtok(nullptr, ":");
443 
444  if (token == nullptr)
445  {
446  LOG_ERROR("Invalid motor mode response.");
447  return false;
448  }
449 
450  int motorType = atoi(token);
451 
452 
453  if (motorType >= 0 && motorType <= 1)
454  {
455  //1 stepper
456  //0 dc
457  IUResetSwitch(&MotorTypeSP);
458  MotorTypeS[MOTOR_DC].s = (motorType == 0) ? ISS_ON : ISS_OFF;
459  MotorTypeS[MOTOR_STEPPER].s = (motorType == 1) ? ISS_ON : ISS_OFF;
460  MotorTypeSP.s = IPS_OK;
461  IDSetSwitch(&MotorTypeSP, nullptr);
462  }
463 
464  // #4 Temperature
465  token = std::strtok(nullptr, ":");
466 
467  if (token == nullptr)
468  {
469  LOG_ERROR("Invalid temperature response.");
470  return false;
471  }
472 
473  double temperature = atof(token);
474  if (temperature == -127)
475  {
476  TemperatureNP.s = IPS_ALERT;
477  IDSetNumber(&TemperatureNP, nullptr);
478  }
479  else
480  {
481  if (fabs(temperature - TemperatureN[0].value) > TEMPERATURE_THRESHOLD)
482  {
483  TemperatureN[0].value = temperature;
484  TemperatureNP.s = IPS_OK;
485  IDSetNumber(&TemperatureNP, nullptr);
486  }
487  }
488 
489  // #5 Position
490  token = std::strtok(nullptr, ":");
491 
492  if (token == nullptr)
493  {
494  LOG_ERROR("Invalid position response.");
495  return false;
496  }
497 
498  currentPosition = atoi(token);
499  if (currentPosition != FocusAbsPosN[0].value)
500  {
501  FocusAbsPosN[0].value = currentPosition;
502  IDSetNumber(&FocusAbsPosNP, nullptr);
503  }
504 
505  // #6 Moving Status
506  token = std::strtok(nullptr, ":");
507 
508  if (token == nullptr)
509  {
510  LOG_ERROR("Invalid moving status response.");
511  return false;
512  }
513 
514  isMoving = (token[0] == '1');
515 
516  // #7 LED Status
517  token = std::strtok(nullptr, ":");
518 
519  if (token == nullptr)
520  {
521  LOG_ERROR("Invalid LED response.");
522  return false;
523  }
524 
525  int ledStatus = atoi(token);
526  if (ledStatus >= 0 && ledStatus <= 1)
527  {
528  IUResetSwitch(&LEDSP);
529  LEDS[ledStatus].s = ISS_ON;
530  LEDSP.s = IPS_OK;
531  IDSetSwitch(&LEDSP, nullptr);
532  }
533 
534  // #8 Reverse Status
535  token = std::strtok(nullptr, ":");
536 
537  if (token == nullptr)
538  {
539  LOG_ERROR("Invalid reverse response.");
540  return false;
541  }
542 
543  int reverseStatus = atoi(token);
544  if (reverseStatus >= 0 && reverseStatus <= 1)
545  {
547  FocusReverseS[INDI_ENABLED].s = (reverseStatus == 1) ? ISS_ON : ISS_OFF;
548  FocusReverseS[INDI_DISABLED].s = (reverseStatus == 0) ? ISS_ON : ISS_OFF;
550  IDSetSwitch(&FocusReverseSP, nullptr);
551  }
552 
553  // #9 Encoder status
554  token = std::strtok(nullptr, ":");
555 
556  if (token == nullptr)
557  {
558  LOG_ERROR("Invalid encoder response.");
559  return false;
560  }
561 
562  int encoderStatus = atoi(token);
563  if (encoderStatus >= 0 && encoderStatus <= 1)
564  {
565  IUResetSwitch(&EncoderSP);
566  EncoderS[encoderStatus].s = ISS_ON;
567  EncoderSP.s = IPS_OK;
568  IDSetSwitch(&EncoderSP, nullptr);
569  }
570 
571  // #10 Backlash
572  token = std::strtok(nullptr, ":");
573 
574  if (token == nullptr)
575  {
576  LOG_ERROR("Invalid encoder response.");
577  return false;
578  }
579 
580  int backlash = atoi(token);
581  // If backlash is zero then compensation is disabled
582  if (backlash == 0 && FocusBacklashS[INDI_ENABLED].s == ISS_ON)
583  {
584  LOG_WARN("Backlash value is zero, disabling backlash switch...");
585 
589  IDSetSwitch(&FocusBacklashSP, nullptr);
590  }
591  else if (backlash > 0 && (FocusBacklashS[INDI_DISABLED].s == ISS_ON || backlash != FocusBacklashN[0].value))
592  {
593  if (backlash != FocusBacklashN[0].value)
594  {
595  FocusBacklashN[0].value = backlash;
597  IDSetNumber(&FocusBacklashNP, nullptr);
598  }
599 
601  {
605  IDSetSwitch(&FocusBacklashSP, nullptr);
606  }
607  }
608 
609  return true;
610 }
611 
612 bool DMFC::setMaxSpeed(uint16_t speed)
613 {
614  int nbytes_written = 0, rc = -1;
615  char cmd[16] = {0};
616 
617  snprintf(cmd, 16, "S:%d", speed);
618  cmd[strlen(cmd)] = 0xA;
619 
620  LOGF_DEBUG("CMD <%s>", cmd);
621 
622  tcflush(PortFD, TCIOFLUSH);
623 
624  // Set Speed
625  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
626  {
627  char errstr[MAXRBUF];
628  tty_error_msg(rc, errstr, MAXRBUF);
629  LOGF_ERROR("setMaxSpeed error: %s.", errstr);
630  return false;
631  }
632 
633  this->ignoreResponse();
634  return true;
635 }
636 
637 bool DMFC::ReverseFocuser(bool enabled)
638 {
639  int nbytes_written = 0, rc = -1;
640  char cmd[16] = {0};
641 
642  snprintf(cmd, 16, "N:%d", enabled ? 1 : 0);
643  cmd[strlen(cmd)] = 0xA;
644 
645  LOGF_DEBUG("CMD <%s>", cmd);
646 
647  tcflush(PortFD, TCIOFLUSH);
648 
649  // Reverse
650  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
651  {
652  char errstr[MAXRBUF];
653  tty_error_msg(rc, errstr, MAXRBUF);
654  LOGF_ERROR("Reverse error: %s.", errstr);
655  return false;
656  }
657 
658  this->ignoreResponse();
659 
660  return true;
661 }
662 
663 bool DMFC::setLedEnabled(bool enable)
664 {
665  int nbytes_written = 0, rc = -1;
666  char cmd[16] = {0};
667 
668  snprintf(cmd, 16, "L:%d", enable ? 2 : 1);
669  cmd[strlen(cmd)] = 0xA;
670 
671  LOGF_DEBUG("CMD <%s>", cmd);
672 
673  tcflush(PortFD, TCIOFLUSH);
674 
675  // Led
676  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
677  {
678  char errstr[MAXRBUF];
679  tty_error_msg(rc, errstr, MAXRBUF);
680  LOGF_ERROR("Led error: %s.", errstr);
681  return false;
682  }
683 
684  this->ignoreResponse();
685  return true;
686 }
687 
688 bool DMFC::setEncodersEnabled(bool enable)
689 {
690  int nbytes_written = 0, rc = -1;
691  char cmd[16] = {0};
692 
693  snprintf(cmd, 16, "E:%d", enable ? 0 : 1);
694  cmd[strlen(cmd)] = 0xA;
695 
696  LOGF_DEBUG("CMD <%s>", cmd);
697 
698  tcflush(PortFD, TCIOFLUSH);
699 
700  // Encoders
701  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
702  {
703  char errstr[MAXRBUF];
704  tty_error_msg(rc, errstr, MAXRBUF);
705  LOGF_ERROR("Encoder error: %s.", errstr);
706  return false;
707  }
708 
709  this->ignoreResponse();
710  return true;
711 }
712 
713 bool DMFC::SetFocuserBacklash(int32_t steps)
714 {
715  int nbytes_written = 0, rc = -1;
716  char cmd[16] = {0};
717 
718  snprintf(cmd, 16, "C:%d", steps);
719  cmd[strlen(cmd)] = 0xA;
720 
721  LOGF_DEBUG("CMD <%s>", cmd);
722 
723  tcflush(PortFD, TCIOFLUSH);
724 
725  // Backlash
726  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
727  {
728  char errstr[MAXRBUF];
729  tty_error_msg(rc, errstr, MAXRBUF);
730  LOGF_ERROR("Backlash error: %s.", errstr);
731  return false;
732  }
733 
734  this->ignoreResponse();
735  return true;
736 }
737 
739 {
740  if (!enabled)
741  return SetFocuserBacklash(0);
742 
743  return SetFocuserBacklash(FocusBacklashN[0].value > 0 ? FocusBacklashN[0].value : 1);
744 }
745 
746 bool DMFC::setMotorType(uint8_t type)
747 {
748 
749  int nbytes_written = 0, rc = -1;
750  char cmd[16] = {0};
751 
752  //commands:
753  //2 dc
754  //1 stepper
755  snprintf(cmd, 16, "R:%d", (type == MOTOR_STEPPER) ? 1 : 2);
756  cmd[strlen(cmd)] = 0xA;
757 
758  LOGF_DEBUG("CMD <%s>", cmd);
759 
760  tcflush(PortFD, TCIOFLUSH);
761 
762  // Motor Type
763  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
764  {
765  char errstr[MAXRBUF];
766  tty_error_msg(rc, errstr, MAXRBUF);
767  LOGF_ERROR("Motor type error: %s.", errstr);
768  return false;
769  }
770 
771  this->ignoreResponse();
772 
773  return true;
774 }
775 
776 IPState DMFC::MoveAbsFocuser(uint32_t targetTicks)
777 {
778  targetPosition = targetTicks;
779 
780  bool rc = moveAbsolute(targetPosition);
781 
782  if (!rc)
783  return IPS_ALERT;
784 
786 
787  return IPS_BUSY;
788 }
789 
791 {
792  int relativePosition = ticks * ((dir == FOCUS_INWARD) ? -1 : 1);
793  return moveRelative(relativePosition) ? IPS_BUSY : IPS_ALERT;
794 }
795 
797 {
798  if (!isConnected())
799  {
801  return;
802  }
803 
804  bool rc = updateFocusParams();
805 
806  if (rc)
807  {
809  {
810  if (isMoving == false)
811  {
814  IDSetNumber(&FocusAbsPosNP, nullptr);
815  IDSetNumber(&FocusRelPosNP, nullptr);
816  LOG_INFO("Focuser reached requested position.");
817  }
818  }
819  }
820 
822 }
823 
825 {
826  int nbytes_written;
827  char cmd[2] = { 'H', 0xA };
828 
829  if (tty_write(PortFD, cmd, 2, &nbytes_written) == TTY_OK)
830  {
833  IDSetNumber(&FocusAbsPosNP, nullptr);
834  IDSetNumber(&FocusRelPosNP, nullptr);
835  this->ignoreResponse();
836  return true;
837  }
838  else
839  return false;
840 }
841 
842 bool DMFC::saveConfigItems(FILE *fp)
843 {
845  IUSaveConfigSwitch(fp, &MotorTypeSP);
846  IUSaveConfigSwitch(fp, &EncoderSP);
847  IUSaveConfigNumber(fp, &MaxSpeedNP);
848  IUSaveConfigSwitch(fp, &LEDSP);
849 
850  return true;
851 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
Definition: dmfc.h:26
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition: dmfc.cpp:230
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
Definition: dmfc.cpp:738
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: dmfc.cpp:796
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: dmfc.cpp:115
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: dmfc.cpp:842
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: dmfc.cpp:790
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
Definition: dmfc.cpp:637
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: dmfc.cpp:776
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: dmfc.cpp:824
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: dmfc.cpp:138
virtual bool Handshake() override
perform handshake with device to check communication
Definition: dmfc.cpp:162
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: dmfc.cpp:352
DMFC()
Definition: dmfc.cpp:39
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: dmfc.cpp:302
const char * getDefaultName() override
Definition: dmfc.cpp:180
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
Definition: dmfc.cpp:713
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: dmfc.cpp:52
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
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 FocusBacklashNP
ISwitchVectorProperty FocusBacklashSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
uint32_t GetCapability() const
GetFocuserCapability returns the capability of the focuser.
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indifocuser.cpp:95
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
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Connection::Serial * serialConnection
Definition: indifocuser.h:116
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
#define DMFC_TIMEOUT
Definition: dmfc.cpp:33
#define TEMPERATURE_THRESHOLD
Definition: dmfc.cpp:35
#define FOCUS_SETTINGS_TAB
Definition: dmfc.cpp:34
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
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
int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
IUGetConfigOnSwitchIndex Opens configuration file and reads single switch property to find ON switch ...
Definition: indidriver.c:711
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250