Instrument Neutral Distributed Interface INDI  1.9.2
pyxis.cpp
Go to the documentation of this file.
1 /*
2  Optec Pyrix Rotator
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 "pyxis.h"
22 
23 #include "indicom.h"
25 
26 #include <cmath>
27 #include <cstring>
28 #include <memory>
29 #include <termios.h>
30 
31 #define PYXIS_TIMEOUT 3
32 #define PYRIX_BUF 7
33 #define PYRIX_CMD 6
34 #define SETTINGS_TAB "Settings"
35 
36 // Recommended default rates for 3 inch and 2 inch rotators
37 #define PYXIS_3INCH_RATE 6
38 #define PYXIS_2INCH_RATE 8
39 
40 // Number of steps per degree for rotators
41 #define PYXIS_3INCH_PER_DEG (128)
42 #define PYXIS_2INCH_PER_DEG 14
43 
44 // 100ms poll rate while rotating
45 #define POLL_100MS 100
46 
47 std::unique_ptr<Pyxis> pyxis(new Pyxis());
48 
50 {
51  // We do not have absolute ticks
53 
55 }
56 
58 {
60 
61  // Rotation Rate
62  IUFillNumber(&RotationRateN[0], "RATE", "Rate", "%.f", 0, 99, 10, 8);
63  IUFillNumberVector(&RotationRateNP, RotationRateN, 1, getDeviceName(), "ROTATION_RATE", "Rotation", SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
64 
65  // Stepping
66  IUFillSwitch(&SteppingS[FULL_STEP], "FULL_STEP", "Full", ISS_OFF);
67  IUFillSwitch(&SteppingS[HALF_STEP], "HALF_STEP", "Half", ISS_OFF);
68  IUFillSwitchVector(&SteppingSP, SteppingS, 2, getDeviceName(), "STEPPING_RATE", "Stepping", SETTINGS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
69 
70  // Power
71  IUFillSwitch(&PowerS[POWER_SLEEP], "POWER_SLEEP", "Sleep", ISS_OFF);
72  IUFillSwitch(&PowerS[POWER_WAKEUP], "POWER_WAKEUP", "Wake Up", ISS_OFF);
73  IUFillSwitchVector(&PowerSP, PowerS, 2, getDeviceName(), "POWER_STATE", "Power", SETTINGS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
74 
75  // Firmware version
76  IUFillText(&FirmwareT[0], "FIRMWARE_VERSION", "Version", "Unknown");
77  IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "FIRMWARE_VERSION", "Firmware", INFO_TAB, IP_RO, 0, IPS_IDLE);
78 
79  // Firmware version
80  IUFillText(&ModelT[0], "HARDWARE_MODEL", "Model", "Unknown");
81  IUFillTextVector(&ModelTP, ModelT, 1, getDeviceName(), "HARDWARE_MODEL", "Model", INFO_TAB, IP_RO, 0, IPS_IDLE);
82 
83 
85 
86  return true ;
87 }
88 
90 {
91  if (Ack())
92  return true;
93 
94  LOG_INFO("Error retrieving data from Pyxis, please ensure Pyxis controller is powered and the port is correct.");
95  return false;
96 }
97 
98 const char * Pyxis::getDefaultName()
99 {
100  return "Pyxis";
101 }
102 
104 {
106 
107  if (isConnected())
108  {
109  defineProperty(&RotationRateNP) ;
110  defineProperty(&SteppingSP);
111  defineProperty(&PowerSP);
112  defineProperty(&FirmwareTP) ;
113  defineProperty(&ModelTP) ;
114 
115  queryParams();
116  }
117  else
118  {
119  deleteProperty(RotationRateNP.name);
120  deleteProperty(SteppingSP.name);
121  deleteProperty(PowerSP.name);
122  deleteProperty(FirmwareTP.name) ;
123  deleteProperty(ModelTP.name) ;
124  }
125 
126  return true;
127 }
128 
129 void Pyxis::queryParams()
130 {
132  // Reverse Parameter
134  int dir = getReverseStatus();
135 
138  if (dir == 0)
140  else if (dir == 1)
142  else
144 
145  IDSetSwitch(&ReverseRotatorSP, nullptr);
146 
147  // Firmware version parameter
148  std::string sversion = getVersion() ;
149  IUSaveText(&FirmwareT[0], sversion.c_str()) ;
150  FirmwareTP.s = IPS_OK;
151  IDSetText(&FirmwareTP, nullptr) ;
152 
153  LOGF_DEBUG("queryParms firmware = %s", sversion.c_str()) ;
154 
155  // Firmware tells us device type, 3 inch or 2 inch, which defines the correct default rotation rate
156  if (atof(sversion.c_str()) >= 3)
157  {
158  uint16_t rate = (atof(sversion.c_str()) >= 3 ? PYXIS_3INCH_RATE : PYXIS_2INCH_RATE) ;
159  bool rc = setRotationRate(rate) ;
160  LOGF_DEBUG("queryParms rate = %d, firmware = %s", rate, sversion.c_str()) ;
161  if (rc)
162  {
163  RotationRateNP.s = IPS_OK ;
164  RotationRateN[0].value = rate ;
165  IDSetNumber(&RotationRateNP, nullptr) ;
166 
167  IUSaveText(&ModelT[0], "Pyxis 3 Inch") ;
168  ModelTP.s = IPS_OK;
169  IDSetText(&ModelTP, nullptr) ;
170  }
171  }
172  else
173  {
174  IUSaveText(&ModelT[0], "Pyxis 2 Inch") ;
175  ModelTP.s = IPS_OK;
176  IDSetText(&ModelTP, nullptr) ;
177  }
178 
179 }
180 
181 bool Pyxis::Ack()
182 {
183  const char *cmd = "CCLINK";
184  char res[1] = {0};
185 
186  int nbytes_written = 0, nbytes_read = 0, rc = -1;
187  char errstr[MAXRBUF];
188 
189  LOGF_DEBUG("CMD <%s>", cmd);
190 
191  tcflush(PortFD, TCIOFLUSH);
192 
193  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
194  {
195  tty_error_msg(rc, errstr, MAXRBUF);
196  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
197  return false;
198  }
199 
200  if ( (rc = tty_read(PortFD, res, 1, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
201  {
202  tty_error_msg(rc, errstr, MAXRBUF);
203  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
204  return false;
205  }
206 
207  LOGF_DEBUG("RES <%c>", res[0]);
208 
209  tcflush(PortFD, TCIOFLUSH);
210 
211  if (res[0] != '!')
212  {
213  LOG_ERROR("Cannot establish communication. Check power is on and homing is complete.");
214  return false;
215  }
216 
217  return true;
218 }
219 
220 bool Pyxis::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
221 {
222  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
223  {
224  if (!strcmp(name, RotationRateNP.name))
225  {
226  bool rc = setRotationRate(static_cast<uint8_t>(values[0]));
227  if (rc)
228  {
229  RotationRateNP.s = IPS_OK;
230  RotationRateN[0].value = values[0];
231  }
232  else
233  RotationRateNP.s = IPS_ALERT;
234 
235  IDSetNumber(&RotationRateNP, nullptr);
236  return true;
237  }
238  }
239 
240  return Rotator::ISNewNumber(dev, name, values, names, n);
241 }
242 
243 bool Pyxis::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
244 {
245  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
246  {
248  // Stepping
250  if (!strcmp(name, SteppingSP.name))
251  {
252  bool rc = false;
253  if (!strcmp(IUFindOnSwitchName(states, names, n), SteppingS[FULL_STEP].name))
254  rc = setSteppingMode(FULL_STEP);
255  else
256  rc = setSteppingMode(HALF_STEP);
257 
258 
259  if (rc)
260  {
261  IUUpdateSwitch(&SteppingSP, states, names, n);
262  SteppingSP.s = IPS_OK;
263  }
264  else
265  SteppingSP.s = IPS_ALERT;
266 
267  IDSetSwitch(&SteppingSP, nullptr);
268  return true;
269  }
270 
272  // Power
274  if (!strcmp(name, PowerSP.name))
275  {
276  bool rc = false;
277  if (!strcmp(IUFindOnSwitchName(states, names, n), PowerS[POWER_WAKEUP].name))
278  {
279  // If not sleeping
280  if (PowerS[POWER_SLEEP].s == ISS_OFF)
281  {
282  PowerSP.s = IPS_OK;
283  LOG_WARN("Controller is not in sleep mode.");
284  IDSetSwitch(&PowerSP, nullptr);
285  return true;
286  }
287 
288  rc = wakeupController();
289 
290  if (rc)
291  {
292  IUResetSwitch(&PowerSP);
293  PowerSP.s = IPS_OK;
294  LOG_INFO("Controller is awake.");
295  }
296  else
297  PowerSP.s = IPS_ALERT;
298 
299  IDSetSwitch(&PowerSP, nullptr);
300  return true;
301  }
302  else
303  {
304  bool rc = sleepController();
305  IUResetSwitch(&PowerSP);
306  if (rc)
307  {
308  PowerSP.s = IPS_OK;
309  PowerS[POWER_SLEEP].s = ISS_ON;
310  LOG_INFO("Controller in sleep mode. No functions can be used until controller is waken up.");
311  }
312  else
313  PowerSP.s = IPS_ALERT;
314 
315  IDSetSwitch(&PowerSP, nullptr);
316  return true;
317  }
318  }
319  }
320 
321  return Rotator::ISNewSwitch(dev, name, states, names, n);
322 }
323 
324 bool Pyxis::setSteppingMode(uint8_t mode)
325 {
326  char cmd[PYRIX_BUF] = {0};
327 
328  int nbytes_written = 0, rc = -1;
329  char errstr[MAXRBUF];
330 
331  snprintf(cmd, PYRIX_BUF, "CZ%dxxx", mode);
332 
333  LOGF_DEBUG("CMD <%s>", cmd);
334 
335  tcflush(PortFD, TCIOFLUSH);
336 
337  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
338  {
339  tty_error_msg(rc, errstr, MAXRBUF);
340  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
341  return false;
342  }
343 
344  return true;
345 }
346 
347 bool Pyxis::setRotationRate(uint8_t rate)
348 {
349  char cmd[PYRIX_BUF] = {0};
350  int nbytes_written = 0, rc = -1;
351  char errstr[MAXRBUF];
352 
353  char res[1] = { 0 } ;
354  int nbytes_read = 0 ;
355 
356  snprintf(cmd, PYRIX_BUF, "CTxx%02d", rate);
357 
358  LOGF_DEBUG("CMD <%s>", cmd);
359 
360  tcflush(PortFD, TCIOFLUSH);
361 
362  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
363  {
364  tty_error_msg(rc, errstr, MAXRBUF);
365  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
366  return false;
367  }
368 
369  if ( (rc = tty_read(PortFD, res, 1, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
370  {
371  tty_error_msg(rc, errstr, MAXRBUF);
372  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
373  return false;
374  }
375 
376  tcflush(PortFD, TCIOFLUSH);
377 
378  LOGF_DEBUG("RES <%c>", res[0]);
379 
380  return (res[0] == '!');
381 }
382 
383 bool Pyxis::sleepController()
384 {
385  const char *cmd = "CSLEEP";
386 
387  int nbytes_written = 0, rc = -1;
388  char errstr[MAXRBUF];
389 
390  LOGF_DEBUG("CMD <%s>", cmd);
391 
392  tcflush(PortFD, TCIOFLUSH);
393 
394  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
395  {
396  tty_error_msg(rc, errstr, MAXRBUF);
397  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
398  return false;
399  }
400 
401  return true;
402 }
403 
404 bool Pyxis::wakeupController()
405 {
406  const char *cmd = "CWAKEUP";
407  char res[1] = { 0 };
408 
409  int nbytes_written = 0, nbytes_read = 0, rc = -1;
410  char errstr[MAXRBUF];
411 
412  LOGF_DEBUG("CMD <%s>", cmd);
413 
414  tcflush(PortFD, TCIOFLUSH);
415 
416  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
417  {
418  tty_error_msg(rc, errstr, MAXRBUF);
419  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
420  return false;
421  }
422 
423  if ( (rc = tty_read(PortFD, res, 1, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
424  {
425  tty_error_msg(rc, errstr, MAXRBUF);
426  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
427  return false;
428  }
429 
430  tcflush(PortFD, TCIOFLUSH);
431 
432  LOGF_DEBUG("RES <%c>", res[0]);
433 
434  return (res[0] == '!');
435 }
436 
438 {
439  const char *cmd = "CHOMES";
440 
441  int nbytes_written = 0, rc = -1;
442  char errstr[MAXRBUF];
443 
444  LOGF_DEBUG("CMD <%s>", cmd);
445 
446  tcflush(PortFD, TCIOFLUSH);
447 
448  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
449  {
450  tty_error_msg(rc, errstr, MAXRBUF);
451  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
452  return IPS_ALERT;
453  }
454 
455  return IPS_BUSY;
456 }
457 
459 {
460  char cmd[PYRIX_BUF] = {0};
461 
462  int nbytes_written = 0, rc = -1;
463  char errstr[MAXRBUF];
464 
465  uint16_t current = static_cast<uint16_t>(GotoRotatorN[0].value) ;
466 
467  targetPA = static_cast<uint16_t>(round(angle));
468 
469  if (targetPA > 359)
470  targetPA = 0;
471 
472  // Rotator will only rotation +-180 degress from home (0 degrees) so it make take
473  // the long way to avoid cable wrap
474  if (current <= 180 && targetPA < 180)
475  direction = (targetPA >= current ? 1 : -1) ;
476  else if (current <= 180 && targetPA > 180)
477  direction = -1 ;
478  else if (current > 180 && targetPA >= 180)
479  direction = (targetPA >= current ? 1 : -1) ;
480  else if (current > 180 && targetPA < 180)
481  direction = 1 ;
482 
483  snprintf(cmd, PYRIX_BUF, "CPA%03d", targetPA);
484 
485  LOGF_DEBUG("CMD <%s>", cmd);
486 
487  tcflush(PortFD, TCIOFLUSH);
488 
489  if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
490  {
491  tty_error_msg(rc, errstr, MAXRBUF);
492  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
493  return IPS_ALERT;
494  }
495 
496  return IPS_BUSY;
497 }
498 
499 bool Pyxis::ReverseRotator(bool enabled)
500 {
501  char cmd[PYRIX_BUF] = {0};
502 
503  int nbytes_written = 0, rc = -1;
504  char errstr[MAXRBUF];
505 
506  snprintf(cmd, PYRIX_BUF, "CD%dxxx", enabled ? 1 : 0);
507 
508  LOGF_DEBUG("CMD <%s>", cmd);
509 
510  tcflush(PortFD, TCIOFLUSH);
511 
512  if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
513  {
514  tty_error_msg(rc, errstr, MAXRBUF);
515  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
516  return false;
517  }
518 
519  return true;
520 }
521 
523 {
524  if (!isConnected() || PowerS[POWER_SLEEP].s == ISS_ON)
525  {
527  return;
528  }
529 
530  if (HomeRotatorSP.s == IPS_BUSY)
531  {
532  if (isMotionComplete())
533  {
535  HomeRotatorS[0].s = ISS_OFF;
536  IDSetSwitch(&HomeRotatorSP, nullptr);
537  LOG_INFO("Homing is complete.");
538  }
539  else
540  {
541  // Fast timer
543  return;
544  }
545  }
546  else if (GotoRotatorNP.s == IPS_BUSY)
547  {
548  if (!isMotionComplete())
549  {
550  LOGF_DEBUG("Motion in %s", "progress") ;
552  return ;
553  }
555  }
556 
557  uint16_t PA = 0;
558  if (getPA(PA) && (PA != static_cast<uint16_t>(GotoRotatorN[0].value)))
559  {
560  GotoRotatorN[0].value = PA;
561  IDSetNumber(&GotoRotatorNP, nullptr);
562  }
563 
565 }
566 
567 bool Pyxis::isMotionComplete()
568 {
569  int nbytes_read = 0, rc = -1;
570  char errstr[MAXRBUF];
571  char res[PYXIS_3INCH_PER_DEG + 1] = { 0 };
572 
573  bool pyxis3inch = atoi(FirmwareT[0].text) >= 3 ;
574 
575  if ( (rc = tty_nread_section(PortFD, res, (pyxis3inch ? PYXIS_3INCH_PER_DEG : PYXIS_2INCH_PER_DEG), 'F', 1, &nbytes_read)) != TTY_OK)
576  {
577  // '!' motion is not complete yet
578  if (rc == TTY_TIME_OUT)
579  return false;
580  else if (rc == TTY_OVERFLOW)
581  {
582  LOGF_DEBUG("RES <%s>", res);
583 
584  int current = static_cast<uint16_t>(GotoRotatorN[0].value) ;
585 
586  current = current + direction ;
587  if (current < 0) current = 359 ;
588  if (current > 360) current = 1 ;
589 
590  GotoRotatorN[0].value = current ;
591  IDSetNumber(&GotoRotatorNP, nullptr);
592 
593  LOGF_DEBUG("ANGLE = %d", current) ;
594  LOGF_DEBUG("TTY_OVERFLOW, nbytes_read = %d", nbytes_read) ;
595  return false ;
596  }
597 
598  tty_error_msg(rc, errstr, MAXRBUF);
599  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
600 
601  if (HomeRotatorSP.s == IPS_BUSY)
602  {
603  HomeRotatorS[0].s = ISS_OFF;
605  LOG_ERROR("Homing failed. Check possible jam.");
606  tcflush(PortFD, TCIOFLUSH);
607  }
608 
609  return false;
610  }
611 
612  LOGF_DEBUG("RES <%s>", res);
613 
614  return true;
615 }
616 
617 #if 0
618 bool Pyxis::isMotionComplete()
619 {
620  int nbytes_read = 0, rc = -1;
621  char errstr[MAXRBUF];
622  char res[1] = { 0 };
623 
624  if ( (rc = tty_read(PortFD, res, 1, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
625  {
626  tty_error_msg(rc, errstr, MAXRBUF);
627  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
628  return false;
629  }
630 
631  LOGF_DEBUG("RES <%c>", res[0]);
632 
633  // Homing still in progress
634  if (res[0] == '!')
635  return false;
636  // Homing is complete
637  else if (res[0] == 'F')
638  return true;
639  // Error
640  else if (HomeRotatorSP.s == IPS_BUSY)
641  {
642  HomeRotatorS[0].s = ISS_OFF;
644  LOG_ERROR("Homing failed. Check possible jam.");
645  tcflush(PortFD, TCIOFLUSH);
646  }
647 
648  return false;
649 }
650 #endif
651 
652 std::string Pyxis::getVersion()
653 {
654  const char *cmd = "CVxxxx";
655  char res[4] = {0};
656 
657  int nbytes_written = 0, nbytes_read = 0, rc = -1;
658  char errstr[MAXRBUF];
659 
660  LOGF_DEBUG("CMD <%s>", cmd);
661 
662  tcflush(PortFD, TCIOFLUSH);
663 
664  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
665  {
666  tty_error_msg(rc, errstr, MAXRBUF);
667  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
668  return std::string("");;
669  }
670 
671  if ( (rc = tty_read(PortFD, res, 3, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
672  {
673  tty_error_msg(rc, errstr, MAXRBUF);
674  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
675  return std::string("") ;
676  }
677 
678  tcflush(PortFD, TCIOFLUSH);
679 
680  LOGF_DEBUG("RES <%s>", res);
681 
682  if (res[0] == '!')
683  return std::string("");
684 
685  return std::string(res) ;;
686 }
687 
688 
689 bool Pyxis::getPA(uint16_t &PA)
690 {
691  const char *cmd = "CGETPA";
692  char res[4] = {0};
693 
694  int nbytes_written = 0, nbytes_read = 0, rc = -1;
695  char errstr[MAXRBUF];
696 
697  LOGF_DEBUG("CMD <%s>", cmd);
698 
699  tcflush(PortFD, TCIOFLUSH);
700 
701  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
702  {
703  tty_error_msg(rc, errstr, MAXRBUF);
704  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
705  return false;
706  }
707 
708  if ( (rc = tty_read(PortFD, res, 3, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
709  {
710  tty_error_msg(rc, errstr, MAXRBUF);
711  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
712  return false;
713  }
714 
715  tcflush(PortFD, TCIOFLUSH);
716 
717  LOGF_DEBUG("RES <%s>", res);
718 
719  if (res[0] == '!')
720  return false;
721 
722  PA = atoi(res);
723 
724  return true;
725 }
726 
727 int Pyxis::getReverseStatus()
728 {
729  const char *cmd = "CMREAD";
730  char res[1] = {0};
731 
732  int nbytes_written = 0, nbytes_read = 0, rc = -1;
733  char errstr[MAXRBUF];
734 
735  LOGF_DEBUG("CMD <%s>", cmd);
736 
737  tcflush(PortFD, TCIOFLUSH);
738 
739  if ( (rc = tty_write(PortFD, cmd, PYRIX_CMD, &nbytes_written)) != TTY_OK)
740  {
741  tty_error_msg(rc, errstr, MAXRBUF);
742  LOGF_ERROR("%s: %s.", __FUNCTION__, errstr);
743  return -1;
744  }
745 
746  if ( (rc = tty_read(PortFD, res, 1, PYXIS_TIMEOUT, &nbytes_read)) != TTY_OK)
747  {
748  tty_error_msg(rc, errstr, MAXRBUF);
749  LOGF_ERROR("%s error: %s.", __FUNCTION__, errstr);
750  return -1;
751  }
752 
753  tcflush(PortFD, TCIOFLUSH);
754 
755  LOGF_DEBUG("RES <%c>", res[0]);
756 
757  return (res[0] == '1' ? 1 : 0);
758 }
IP_RO
@ IP_RO
Definition: indiapi.h:183
Pyxis::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: pyxis.cpp:220
INDI::Rotator::setRotatorConnection
void setRotatorConnection(const uint8_t &value)
setRotatorConnection Set Rotator connection mode. Child class should call this in the constructor bef...
Definition: indirotator.cpp:221
IUFindOnSwitchName
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
Definition: indicom.c:1412
TTY_TIME_OUT
@ TTY_TIME_OUT
Definition: indicom.h:98
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
pyxis.h
Pyxis::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: pyxis.cpp:522
INDI::Rotator::serialConnection
Connection::Serial * serialConnection
Definition: indirotator.h:95
IPState
IPState
Property state.
Definition: indiapi.h:158
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:636
PYXIS_3INCH_RATE
#define PYXIS_3INCH_RATE
Definition: pyxis.cpp:37
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.
SETTINGS_TAB
#define SETTINGS_TAB
Definition: pyxis.cpp:34
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
INDI::Rotator::PortFD
int PortFD
Definition: indirotator.h:98
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
Pyxis::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: pyxis.cpp:57
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
PYXIS_3INCH_PER_DEG
#define PYXIS_3INCH_PER_DEG
Definition: pyxis.cpp:41
round
double round(double value, int decimal_places)
Definition: test_alignment.cpp:32
PYXIS_2INCH_RATE
#define PYXIS_2INCH_RATE
Definition: pyxis.cpp:38
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
Pyxis::Pyxis
Pyxis()
Definition: pyxis.cpp:49
INDI::RotatorInterface::GotoRotatorN
INumber GotoRotatorN[1]
Definition: indirotatorinterface.h:197
POLL_100MS
#define POLL_100MS
Definition: pyxis.cpp:45
TTY_OVERFLOW
@ TTY_OVERFLOW
Definition: indicom.h:102
Connection::Serial::B_19200
@ B_19200
Definition: connectionserial.h:82
INFO_TAB
const char * INFO_TAB
INFO_TAB Where all the properties for general information are located.
Definition: defaultdevice.cpp:45
Pyxis::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: pyxis.cpp:243
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
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:1421
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:1135
Pyxis::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: pyxis.cpp:103
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
ISNewNumber
void ISNewNumber(const char *dev, const char *name, double *values, char *names[], int n)
Update the value of an existing number vector property.
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:462
INDI::Rotator::CONNECTION_SERIAL
@ CONNECTION_SERIAL
Definition: indirotator.h:57
INDI::Rotator::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indirotator.cpp:53
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
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:375
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
PYXIS_TIMEOUT
#define PYXIS_TIMEOUT
Definition: pyxis.cpp:31
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:404
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::RotatorInterface::ROTATOR_CAN_HOME
@ ROTATOR_CAN_HOME
Definition: indirotatorinterface.h:56
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
connectionserial.h
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
PYRIX_BUF
#define PYRIX_BUF
Definition: pyxis.cpp:32
INDI::RotatorInterface::HomeRotatorSP
ISwitchVectorProperty HomeRotatorSP
Definition: indirotatorinterface.h:207
Pyxis
Definition: pyxis.h:26
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::RotatorInterface::ROTATOR_CAN_REVERSE
@ ROTATOR_CAN_REVERSE
Definition: indirotatorinterface.h:58
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
ISNewSwitch
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
Definition: defaultdevice.cpp:60
INDI::RotatorInterface::GotoRotatorNP
INumberVectorProperty GotoRotatorNP
Definition: indirotatorinterface.h:198
PYXIS_2INCH_PER_DEG
#define PYXIS_2INCH_PER_DEG
Definition: pyxis.cpp:42
Pyxis::HomeRotator
virtual IPState HomeRotator() override
HomeRotator Go to home position.
Definition: pyxis.cpp:437
INDI::RotatorInterface::HomeRotatorS
ISwitch HomeRotatorS[1]
Definition: indirotatorinterface.h:206
INDI::Rotator::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indirotator.cpp:110
PYRIX_CMD
#define PYRIX_CMD
Definition: pyxis.cpp:33
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::RotatorInterface::SetCapability
void SetCapability(uint32_t cap)
SetRotatorCapability sets the Rotator capabilities. All capabilities must be initialized.
Definition: indirotatorinterface.h:74
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1428
INDI::RotatorInterface::ReverseRotatorSP
ISwitchVectorProperty ReverseRotatorSP
Definition: indirotatorinterface.h:210
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
INDI::BaseDevice::INDI_DISABLED
@ INDI_DISABLED
Definition: basedevice.h:65
ISState
ISState
Switch state.
Definition: indiapi.h:148
Pyxis::ReverseRotator
virtual bool ReverseRotator(bool enabled) override
ReverseRotator Reverse the direction of the rotator. CW is usually the normal direction,...
Definition: pyxis.cpp:499
Pyxis::getDefaultName
const char * getDefaultName() override
Definition: pyxis.cpp:98
Pyxis::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: pyxis.cpp:89
pyxis
std::unique_ptr< Pyxis > pyxis(new Pyxis())
TTY_OK
@ TTY_OK
Definition: indicom.h:94
INDI::RotatorInterface::ReverseRotatorS
ISwitch ReverseRotatorS[2]
Definition: indirotatorinterface.h:209
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
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
Pyxis::MoveRotator
virtual IPState MoveRotator(double angle) override
MoveRotator Go to specific angle.
Definition: pyxis.cpp:458
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151