Instrument Neutral Distributed Interface INDI  1.9.5
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))
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  {
420  LOGF_ERROR("Invalid status response. %s", res);
421  return false;
422  }
423 
424  // #2 Version
425  token = std::strtok(nullptr, ":");
426 
427  if (token == nullptr)
428  {
429  LOG_ERROR("Invalid version response.");
430  return false;
431  }
432 
433  if (FirmwareVersionT[0].text == nullptr || strcmp(FirmwareVersionT[0].text, token))
434  {
435  IUSaveText(&FirmwareVersionT[0], token);
436  FirmwareVersionTP.s = IPS_OK;
437  IDSetText(&FirmwareVersionTP, nullptr);
438  }
439 
440  // #3 Motor Type
441  token = std::strtok(nullptr, ":");
442 
443  if (token == nullptr)
444  {
445  LOG_ERROR("Invalid motor mode response.");
446  return false;
447  }
448 
449  int motorType = atoi(token);
450 
451 
452  if (motorType >= 0 && motorType <= 1)
453  {
454  //1 stepper
455  //0 dc
456  IUResetSwitch(&MotorTypeSP);
457  MotorTypeS[MOTOR_DC].s = (motorType == 0) ? ISS_ON : ISS_OFF;
458  MotorTypeS[MOTOR_STEPPER].s = (motorType == 1) ? ISS_ON : ISS_OFF;
459  MotorTypeSP.s = IPS_OK;
460  IDSetSwitch(&MotorTypeSP, nullptr);
461  }
462 
463  // #4 Temperature
464  token = std::strtok(nullptr, ":");
465 
466  if (token == nullptr)
467  {
468  LOG_ERROR("Invalid temperature response.");
469  return false;
470  }
471 
472  double temperature = atof(token);
473  if (temperature == -127)
474  {
475  TemperatureNP.s = IPS_ALERT;
476  IDSetNumber(&TemperatureNP, nullptr);
477  }
478  else
479  {
480  if (fabs(temperature - TemperatureN[0].value) > TEMPERATURE_THRESHOLD)
481  {
482  TemperatureN[0].value = temperature;
483  TemperatureNP.s = IPS_OK;
484  IDSetNumber(&TemperatureNP, nullptr);
485  }
486  }
487 
488  // #5 Position
489  token = std::strtok(nullptr, ":");
490 
491  if (token == nullptr)
492  {
493  LOG_ERROR("Invalid position response.");
494  return false;
495  }
496 
497  currentPosition = atoi(token);
498  if (currentPosition != FocusAbsPosN[0].value)
499  {
500  FocusAbsPosN[0].value = currentPosition;
501  IDSetNumber(&FocusAbsPosNP, nullptr);
502  }
503 
504  // #6 Moving Status
505  token = std::strtok(nullptr, ":");
506 
507  if (token == nullptr)
508  {
509  LOG_ERROR("Invalid moving status response.");
510  return false;
511  }
512 
513  isMoving = (token[0] == '1');
514 
515  // #7 LED Status
516  token = std::strtok(nullptr, ":");
517 
518  if (token == nullptr)
519  {
520  LOG_ERROR("Invalid LED response.");
521  return false;
522  }
523 
524  int ledStatus = atoi(token);
525  if (ledStatus >= 0 && ledStatus <= 1)
526  {
527  IUResetSwitch(&LEDSP);
528  LEDS[ledStatus].s = ISS_ON;
529  LEDSP.s = IPS_OK;
530  IDSetSwitch(&LEDSP, nullptr);
531  }
532 
533  // #8 Reverse Status
534  token = std::strtok(nullptr, ":");
535 
536  if (token == nullptr)
537  {
538  LOG_ERROR("Invalid reverse response.");
539  return false;
540  }
541 
542  int reverseStatus = atoi(token);
543  if (reverseStatus >= 0 && reverseStatus <= 1)
544  {
546  FocusReverseS[INDI_ENABLED].s = (reverseStatus == 1) ? ISS_ON : ISS_OFF;
547  FocusReverseS[INDI_DISABLED].s = (reverseStatus == 0) ? ISS_ON : ISS_OFF;
549  IDSetSwitch(&FocusReverseSP, nullptr);
550  }
551 
552  // #9 Encoder status
553  token = std::strtok(nullptr, ":");
554 
555  if (token == nullptr)
556  {
557  LOG_ERROR("Invalid encoder response.");
558  return false;
559  }
560 
561  int encoderStatus = atoi(token);
562  if (encoderStatus >= 0 && encoderStatus <= 1)
563  {
564  IUResetSwitch(&EncoderSP);
565  EncoderS[encoderStatus].s = ISS_ON;
566  EncoderSP.s = IPS_OK;
567  IDSetSwitch(&EncoderSP, nullptr);
568  }
569 
570  // #10 Backlash
571  token = std::strtok(nullptr, ":");
572 
573  if (token == nullptr)
574  {
575  LOG_ERROR("Invalid encoder response.");
576  return false;
577  }
578 
579  int backlash = atoi(token);
580  // If backlash is zero then compensation is disabled
581  if (backlash == 0 && FocusBacklashS[INDI_ENABLED].s == ISS_ON)
582  {
583  LOG_WARN("Backlash value is zero, disabling backlash switch...");
584 
588  IDSetSwitch(&FocusBacklashSP, nullptr);
589  }
590  else if (backlash > 0 && (FocusBacklashS[INDI_DISABLED].s == ISS_ON || backlash != FocusBacklashN[0].value))
591  {
592  if (backlash != FocusBacklashN[0].value)
593  {
594  FocusBacklashN[0].value = backlash;
596  IDSetNumber(&FocusBacklashNP, nullptr);
597  }
598 
600  {
604  IDSetSwitch(&FocusBacklashSP, nullptr);
605  }
606  }
607 
608  return true;
609 }
610 
611 bool DMFC::setMaxSpeed(uint16_t speed)
612 {
613  int nbytes_written = 0, rc = -1;
614  char cmd[16] = {0};
615 
616  snprintf(cmd, 16, "S:%d", speed);
617  cmd[strlen(cmd)] = 0xA;
618 
619  LOGF_DEBUG("CMD <%s>", cmd);
620 
621  tcflush(PortFD, TCIOFLUSH);
622 
623  // Set Speed
624  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
625  {
626  char errstr[MAXRBUF];
627  tty_error_msg(rc, errstr, MAXRBUF);
628  LOGF_ERROR("setMaxSpeed error: %s.", errstr);
629  return false;
630  }
631 
632  this->ignoreResponse();
633  return true;
634 }
635 
636 bool DMFC::ReverseFocuser(bool enabled)
637 {
638  int nbytes_written = 0, rc = -1;
639  char cmd[16] = {0};
640 
641  snprintf(cmd, 16, "N:%d", enabled ? 1 : 0);
642  cmd[strlen(cmd)] = 0xA;
643 
644  LOGF_DEBUG("CMD <%s>", cmd);
645 
646  tcflush(PortFD, TCIOFLUSH);
647 
648  // Reverse
649  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
650  {
651  char errstr[MAXRBUF];
652  tty_error_msg(rc, errstr, MAXRBUF);
653  LOGF_ERROR("Reverse error: %s.", errstr);
654  return false;
655  }
656 
657  this->ignoreResponse();
658 
659  return true;
660 }
661 
662 bool DMFC::setLedEnabled(bool enable)
663 {
664  int nbytes_written = 0, rc = -1;
665  char cmd[16] = {0};
666 
667  snprintf(cmd, 16, "L:%d", enable ? 2 : 1);
668  cmd[strlen(cmd)] = 0xA;
669 
670  LOGF_DEBUG("CMD <%s>", cmd);
671 
672  tcflush(PortFD, TCIOFLUSH);
673 
674  // Led
675  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
676  {
677  char errstr[MAXRBUF];
678  tty_error_msg(rc, errstr, MAXRBUF);
679  LOGF_ERROR("Led error: %s.", errstr);
680  return false;
681  }
682 
683  this->ignoreResponse();
684  return true;
685 }
686 
687 bool DMFC::setEncodersEnabled(bool enable)
688 {
689  int nbytes_written = 0, rc = -1;
690  char cmd[16] = {0};
691 
692  snprintf(cmd, 16, "E:%d", enable ? 0 : 1);
693  cmd[strlen(cmd)] = 0xA;
694 
695  LOGF_DEBUG("CMD <%s>", cmd);
696 
697  tcflush(PortFD, TCIOFLUSH);
698 
699  // Encoders
700  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
701  {
702  char errstr[MAXRBUF];
703  tty_error_msg(rc, errstr, MAXRBUF);
704  LOGF_ERROR("Encoder error: %s.", errstr);
705  return false;
706  }
707 
708  this->ignoreResponse();
709  return true;
710 }
711 
712 bool DMFC::SetFocuserBacklash(int32_t steps)
713 {
714  int nbytes_written = 0, rc = -1;
715  char cmd[16] = {0};
716 
717  snprintf(cmd, 16, "C:%d", steps);
718  cmd[strlen(cmd)] = 0xA;
719 
720  LOGF_DEBUG("CMD <%s>", cmd);
721 
722  tcflush(PortFD, TCIOFLUSH);
723 
724  // Backlash
725  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
726  {
727  char errstr[MAXRBUF];
728  tty_error_msg(rc, errstr, MAXRBUF);
729  LOGF_ERROR("Backlash error: %s.", errstr);
730  return false;
731  }
732 
733  this->ignoreResponse();
734  return true;
735 }
736 
738 {
739  if (!enabled)
740  return SetFocuserBacklash(0);
741 
742  return SetFocuserBacklash(FocusBacklashN[0].value > 0 ? FocusBacklashN[0].value : 1);
743 }
744 
745 bool DMFC::setMotorType(uint8_t type)
746 {
747 
748  int nbytes_written = 0, rc = -1;
749  char cmd[16] = {0};
750 
751  //commands:
752  //2 dc
753  //1 stepper
754  snprintf(cmd, 16, "R:%d", (type == MOTOR_STEPPER) ? 1 : 2);
755  cmd[strlen(cmd)] = 0xA;
756 
757  LOGF_DEBUG("CMD <%s>", cmd);
758 
759  tcflush(PortFD, TCIOFLUSH);
760 
761  // Motor Type
762  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
763  {
764  char errstr[MAXRBUF];
765  tty_error_msg(rc, errstr, MAXRBUF);
766  LOGF_ERROR("Motor type error: %s.", errstr);
767  return false;
768  }
769 
770  this->ignoreResponse();
771 
772  return true;
773 }
774 
775 IPState DMFC::MoveAbsFocuser(uint32_t targetTicks)
776 {
777  targetPosition = targetTicks;
778 
779  bool rc = moveAbsolute(targetPosition);
780 
781  if (!rc)
782  return IPS_ALERT;
783 
785 
786  return IPS_BUSY;
787 }
788 
790 {
791  int relativePosition = ticks * ((dir == FOCUS_INWARD) ? -1 : 1);
792  return moveRelative(relativePosition) ? IPS_BUSY : IPS_ALERT;
793 }
794 
796 {
797  if (!isConnected())
798  {
800  return;
801  }
802 
803  bool rc = updateFocusParams();
804 
805  if (rc)
806  {
808  {
809  if (isMoving == false)
810  {
813  IDSetNumber(&FocusAbsPosNP, nullptr);
814  IDSetNumber(&FocusRelPosNP, nullptr);
815  LOG_INFO("Focuser reached requested position.");
816  }
817  }
818  }
819 
821 }
822 
824 {
825  int nbytes_written;
826  char cmd[2] = { 'H', 0xA };
827 
828  if (tty_write(PortFD, cmd, 2, &nbytes_written) == TTY_OK)
829  {
832  IDSetNumber(&FocusAbsPosNP, nullptr);
833  IDSetNumber(&FocusRelPosNP, nullptr);
834  this->ignoreResponse();
835  return true;
836  }
837  else
838  return false;
839 }
840 
841 bool DMFC::saveConfigItems(FILE *fp)
842 {
844  IUSaveConfigSwitch(fp, &MotorTypeSP);
845  IUSaveConfigSwitch(fp, &EncoderSP);
846  IUSaveConfigNumber(fp, &MaxSpeedNP);
847  IUSaveConfigSwitch(fp, &LEDSP);
848 
849  return true;
850 }
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
DMFC
Definition: dmfc.h:25
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::FocuserInterface::FOCUSER_CAN_SYNC
@ FOCUSER_CAN_SYNC
Definition: indifocuserinterface.h:78
DMFC::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: dmfc.cpp:823
DMFC::DMFC
DMFC()
Definition: dmfc.cpp:39
INDI::FocuserInterface::FOCUSER_CAN_REL_MOVE
@ FOCUSER_CAN_REL_MOVE
Definition: indifocuserinterface.h:75
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
DMFC::ISGetProperties
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
DMFC_TIMEOUT
#define DMFC_TIMEOUT
Definition: dmfc.cpp:33
dmfc.h
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
IPState
IPState
Property state.
Definition: indiapi.h:158
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
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
INDI::Focuser::ISGetProperties
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:111
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
IUFillNumber
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidriver.c:348
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
DMFC::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: dmfc.cpp:841
IUFillTextVector
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: indidriver.c:477
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
INDI::Focuser::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: indifocuser.cpp:241
INDI::DefaultDevice::setVersion
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
Definition: defaultdevice.cpp:1219
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::Focuser::serialConnection
Connection::Serial * serialConnection
Definition: indifocuser.h:113
DMFC::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: dmfc.cpp:52
tty_read_section
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:557
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
Connection::Serial::B_19200
@ B_19200
Definition: connectionserial.h:82
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1455
IUFillText
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: indidriver.c:369
INDI::FocuserInterface::FocusReverseSP
ISwitchVectorProperty FocusReverseSP
Definition: indifocuserinterface.h:302
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
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
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
INDI::FocuserInterface::FocusBacklashSP
ISwitchVectorProperty FocusBacklashSP
Definition: indifocuserinterface.h:306
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
type
__le16 type
Definition: pwc-ioctl.h:2
Connection::Serial::setDefaultBaudRate
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
Definition: connectionserial.cpp:381
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::GetCapability
uint32_t GetCapability() const
GetFocuserCapability returns the capability of the focuser.
Definition: indifocuserinterface.h:86
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
DMFC::SetFocuserBacklashEnabled
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
Definition: dmfc.cpp:737
INDI::FocuserInterface::FOCUS_INWARD
@ FOCUS_INWARD
Definition: indifocuserinterface.h:68
IUFillSwitchVector
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:412
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
IUFillNumberVector
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:455
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
connectionserial.h
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
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
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
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
DMFC::getDefaultName
const char * getDefaultName() override
Definition: dmfc.cpp:180
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
INDI::FocuserInterface::FocusBacklashS
ISwitch FocusBacklashS[2]
Definition: indifocuserinterface.h:307
DMFC::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: dmfc.cpp:795
DMFC::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: dmfc.cpp:138
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
DMFC::SyncFocuser
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition: dmfc.cpp:230
TEMPERATURE_THRESHOLD
#define TEMPERATURE_THRESHOLD
Definition: dmfc.cpp:35
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
name
const char * name
Definition: indiserver.c:116
DMFC::ISNewNumber
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::ReverseFocuser
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
Definition: dmfc.cpp:636
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::FocuserInterface::FocusReverseS
ISwitch FocusReverseS[2]
Definition: indifocuserinterface.h:303
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
INDI::DefaultDevice::saveConfig
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
Definition: defaultdevice.cpp:221
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
DMFC::SetFocuserBacklash
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
Definition: dmfc.cpp:712
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
INDI::FocuserInterface::FOCUSER_HAS_BACKLASH
@ FOCUSER_HAS_BACKLASH
Definition: indifocuserinterface.h:80
ISState
ISState
Switch state.
Definition: indiapi.h:148
FOCUS_SETTINGS_TAB
#define FOCUS_SETTINGS_TAB
Definition: dmfc.cpp:34
IUGetConfigOnSwitchIndex
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:1270
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
DMFC::ISNewSwitch
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
TTY_OK
@ TTY_OK
Definition: indicom.h:94
INDI::FocuserInterface::FocusBacklashNP
INumberVectorProperty FocusBacklashNP
Definition: indifocuserinterface.h:310
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
DMFC::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: dmfc.cpp:775
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
DMFC::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: dmfc.cpp:789
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
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
DMFC::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: dmfc.cpp:162
INDI::BaseDevice::INDI_DISABLED
@ INDI_DISABLED
Definition: basedevice.h:65
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151