Instrument Neutral Distributed Interface INDI  2.0.2
lx200_pegasus_nyx101.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2021 Chrysikos Efstathios. All rights reserved.
3 
4  Pegasus NYX
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the Free
8  Software Foundation; either version 2 of the License, or (at your option)
9  any later version.
10 
11  This program is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 
21  The full GNU General Public License is included in this distribution in the
22  file called LICENSE.
23 *******************************************************************************/
24 
25 #include "lx200_pegasus_nyx101.h"
26 #include "lx200driver.h"
27 #include "indicom.h"
29 #include <libnova/transform.h>
30 
31 #include <cmath>
32 #include <cstring>
33 #include <stdio.h>
34 #include <termios.h>
35 #include <unistd.h>
36 #include <regex>
37 
38 const char *SETTINGS_TAB = "Settings";
39 const char *STATUS_TAB = "Status";
40 
42 {
43  setVersion(1, 0);
44 
46 
55  SLEW_MODES);
56 }
57 
59 {
61 
65 
66  // Mount Type
67  int mountType = Equatorial;
68  IUGetConfigOnSwitchIndex(getDeviceName(), "MOUNT_TYPE", &mountType);
69  MountTypeSP[AltAz].fill("AltAz", "AltAz", mountType == AltAz ? ISS_ON : ISS_OFF);
70  MountTypeSP[Equatorial].fill("Equatorial", "Equatorial", mountType == Equatorial ? ISS_ON : ISS_OFF);
71  MountTypeSP.fill(getDeviceName(), "MOUNT_TYPE", "Mount Type", SETTINGS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
72 
73  if (mountType == Equatorial)
75 
76  // Guide Rate
77  int guideRate = 1;
78  IUGetConfigOnSwitchIndex(getDeviceName(), "GUIDE_RATE", &guideRate);
79  GuideRateSP[0].fill("0.25","0.25", guideRate == 0 ? ISS_ON : ISS_OFF);
80  GuideRateSP[1].fill("0.50","0.50", guideRate == 1 ? ISS_ON : ISS_OFF);
81  GuideRateSP[2].fill("1.00","1.00", guideRate == 2 ? ISS_ON : ISS_OFF);
82  GuideRateSP.fill(getDeviceName(), "GUIDE_RATE", "Guide Rate", SETTINGS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
83 
84  //Go Home
85  HomeSP[0].fill("Home", "Go", ISS_OFF);
86  HomeSP.fill(getDeviceName(), "HOME_GO", "Home go", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
87 
88  //Reset Home
89  ResetHomeSP[0].fill("Home", "Reset", ISS_OFF);
90  ResetHomeSP.fill(getDeviceName(), "HOME_RESET", "Home Reset", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
91 
92  verboseReport = false;
93  VerboseReportSP[0].fill("On","On", ISS_OFF);
94  VerboseReportSP[1].fill("Off","Off", ISS_ON);
95  VerboseReportSP.fill(getDeviceName(), "REPORT_VERBOSE", "Verbose", STATUS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
96 
97  Report[0].fill("Report","GU","-");
98  Report.fill(getDeviceName(), "Report", "Report", STATUS_TAB, IP_RO, 60, IPS_IDLE);
99 
100  IsTracking[0].fill("IsTracking","n","-");
101  IsTracking.fill(getDeviceName(),"IsTracking","IsTracking",STATUS_TAB, IP_RO, 60, IPS_IDLE);
102 
103  IsSlewCompleted[0].fill("IsSlewCompleted","N","-");
104  IsSlewCompleted.fill(getDeviceName(),"IsSlewCompleted","IsSlewCompleted",STATUS_TAB, IP_RO, 60, IPS_IDLE);
105 
106  IsParked[0].fill("IsParked","p/P","-");
107  IsParked.fill(getDeviceName(),"IsParked","IsParked",STATUS_TAB, IP_RO, 60, IPS_IDLE);
108 
109  IsParkginInProgress[0].fill("IsParkginInProgress","I","-");
110  IsParkginInProgress.fill(getDeviceName(),"IsParkginInProgress","IsParkginInProgress",STATUS_TAB, IP_RO, 60, IPS_IDLE);
111 
112  IsAtHomePosition[0].fill("IsAtHomePosition","H","-");
113  IsAtHomePosition.fill(getDeviceName(),"IsAtHomePosition","IsAtHomePosition",STATUS_TAB, IP_RO, 60, IPS_IDLE);
114 
115  TrackSidereal[0].fill("TrackSidereal","","-");
116  TrackSidereal.fill(getDeviceName(),"TrackSidereal","TrackSidereal",STATUS_TAB, IP_RO, 60, IPS_IDLE);
117 
118  TrackLunar[0].fill("TrackLunar","(","-");
119  TrackLunar.fill(getDeviceName(),"TrackLunar","TrackLunar",STATUS_TAB, IP_RO, 60, IPS_IDLE);
120 
121  TrackSolar[0].fill("TrackSolar","O","-");
122  TrackSolar.fill(getDeviceName(),"TrackSolar","TrackSolar",STATUS_TAB, IP_RO, 60, IPS_IDLE);
123 
124  MountAltAz[0].fill("MountAltAz","A","-");
125  MountAltAz.fill(getDeviceName(),"MountAltAz","MountAltAz",STATUS_TAB, IP_RO, 60, IPS_IDLE);
126 
127  MountEquatorial[0].fill("MountEquatorial","E","-");
128  MountEquatorial.fill(getDeviceName(),"MountEquatorial","MountEquatorial",STATUS_TAB, IP_RO, 60, IPS_IDLE);
129 
130  PierNone[0].fill("PierNone","","-");
131  PierNone.fill(getDeviceName(),"PierNone","PierNone",STATUS_TAB, IP_RO, 60, IPS_IDLE);
132 
133  PierEast[0].fill("PierEast","T","-");
134  PierEast.fill(getDeviceName(),"PierEast","PierEast",STATUS_TAB, IP_RO, 60, IPS_IDLE);
135 
136  PierWest[0].fill("PierWest","W","-");
137  PierWest.fill(getDeviceName(),"PierWest","PierWest",STATUS_TAB, IP_RO, 60, IPS_IDLE);
138 
139  DoesRefractionComp[0].fill("DoesRefractionComp","r","-");
140  DoesRefractionComp.fill(getDeviceName(),"DoesRefractionComp","DoesRefractionComp",STATUS_TAB, IP_RO, 60, IPS_IDLE);
141 
142  WaitingAtHome[0].fill("WaitingAtHome","w","-");
143  WaitingAtHome.fill(getDeviceName(),"WaitingAtHome","WaitingAtHome",STATUS_TAB, IP_RO, 60, IPS_IDLE);
144 
145  IsHomePaused[0].fill("IsHomePaused","u","-");
146  IsHomePaused.fill(getDeviceName(),"IsHomePaused","IsHomePaused",STATUS_TAB, IP_RO, 60, IPS_IDLE);
147 
148  ParkFailed[0].fill("ParkFailed","F","-");
149  ParkFailed.fill(getDeviceName(),"ParkFailed","ParkFailed",STATUS_TAB, IP_RO, 60, IPS_IDLE);
150 
151  SlewingHome[0].fill("SlewingHome","h","-");
152  SlewingHome.fill(getDeviceName(),"SlewingHome","SlewingHome",STATUS_TAB, IP_RO, 60, IPS_IDLE);
153 
154 
155  // Slew Rates
156  strncpy(SlewRateS[0].label, "2x", MAXINDILABEL);
157  strncpy(SlewRateS[1].label, "8x", MAXINDILABEL);
158  strncpy(SlewRateS[2].label, "16x", MAXINDILABEL);
159  strncpy(SlewRateS[3].label, "64x", MAXINDILABEL);
160  strncpy(SlewRateS[4].label, "128x", MAXINDILABEL);
161  strncpy(SlewRateS[5].label, "200x", MAXINDILABEL);
162  strncpy(SlewRateS[6].label, "300x", MAXINDILABEL);
163  strncpy(SlewRateS[7].label, "600x", MAXINDILABEL);
164  strncpy(SlewRateS[8].label, "900x", MAXINDILABEL);
165  strncpy(SlewRateS[9].label, "1200x", MAXINDILABEL);
167 
168  SlewRateS[9].s = ISS_ON;
169 
170 
171  return true;
172 }
173 
175 {
177 
178  if (isConnected())
179  {
180  char status[DRIVER_LEN] = {0};
181  if (sendCommand(":GU#", status))
182  {
183  if(strchr(status,'P'))
184  SetParked(true);
185  else
186  SetParked(false);
187 
188  MountTypeSP.reset();
189  MountTypeSP[AltAz].setState(strchr(status, 'A') ? ISS_ON : ISS_OFF);
190  MountTypeSP[Equatorial].setState(strchr(status, 'E') ? ISS_ON : ISS_OFF);
191  MountTypeSP.setState(IPS_OK);
192  MountTypeSP.apply();
193  }
194 
195  if(sendCommand(":GX90#", status))
196  {
197  std::string c = status;
198 
199  GuideRateSP.reset();
200  GuideRateSP[0].setState((c.find("0.25") != std::string::npos) ? ISS_ON : ISS_OFF);
201  GuideRateSP[1].setState((c.find("0.50") != std::string::npos) ? ISS_ON : ISS_OFF);
202  GuideRateSP[2].setState((c.find("1.00") != std::string::npos) ? ISS_ON : ISS_OFF);
203  GuideRateSP.setState((IPS_OK));
204  GuideRateSP.apply();
205  }
206 
207  defineProperty(MountTypeSP);
208  defineProperty(GuideRateSP);
209  defineProperty(HomeSP);
210  defineProperty(ResetHomeSP);
211  defineProperty(Report);
212  defineProperty(VerboseReportSP);
213  defineProperty(IsTracking);
214  defineProperty(IsSlewCompleted);
215  defineProperty(IsParked);
216  defineProperty(IsParkginInProgress);
217  defineProperty(IsAtHomePosition);
218  defineProperty(TrackSidereal);
219  defineProperty(TrackLunar);
220  defineProperty(TrackSolar);
221  defineProperty(MountAltAz);
222  defineProperty(MountEquatorial);
223  defineProperty(PierNone);
224  defineProperty(PierEast);
225  defineProperty(PierWest);
226  defineProperty(DoesRefractionComp);
227  defineProperty(WaitingAtHome);
228  defineProperty(IsHomePaused);
229  defineProperty(ParkFailed);
230  defineProperty(SlewingHome);
231  }
232  else
233  {
234  deleteProperty(MountTypeSP);
235  deleteProperty(GuideRateSP);
236  deleteProperty(HomeSP);
237  deleteProperty(ResetHomeSP);
238  deleteProperty(Report);
239  deleteProperty(VerboseReportSP);
240  deleteProperty(IsTracking);
241  deleteProperty(IsSlewCompleted);
242  deleteProperty(IsParked);
243  deleteProperty(IsParkginInProgress);
244  deleteProperty(IsAtHomePosition);
245  deleteProperty(TrackSidereal);
246  deleteProperty(TrackLunar);
247  deleteProperty(TrackSolar);
248  deleteProperty(MountAltAz);
249  deleteProperty(MountEquatorial);
250  deleteProperty(PierNone);
251  deleteProperty(PierEast);
252  deleteProperty(PierWest);
253  deleteProperty(DoesRefractionComp);
254  deleteProperty(WaitingAtHome);
255  deleteProperty(IsHomePaused);
256  deleteProperty(ParkFailed);
257  deleteProperty(SlewingHome);
258 
259  }
260 
261  return true;
262 }
263 
264 
266 {
267  return "Pegasus NYX-101";
268 }
269 
270 const char *ON = "ON";
271 const char *OFF = "OFF";
272 
273 void LX200NYX101::SetPropertyText(INDI::PropertyText propertyTxt, IPState state)
274 {
275  if(!verboseReport)
276  return;
277 
278  if(state == IPS_OK)
279  {
280  propertyTxt[0].setText(ON);
281  }
282  else if(state == IPS_BUSY)
283  {
284  propertyTxt[0].setText(OFF);
285  }
286  else if(state == IPS_IDLE)
287  {
288  propertyTxt[0].setText("-");
289  }
290  propertyTxt.setState(state);
291  propertyTxt.apply();
292 }
293 
295 {
296  if (!isConnected())
297  return false;
298 
299  bool _IsTracking = true;
300  SetPropertyText(IsTracking, IPS_OK);
301 
302  bool _IsSlewCompleted = false;
303  SetPropertyText(IsSlewCompleted, IPS_BUSY);
304 
305  bool _IsParked = false;
306  SetPropertyText(IsParked, IPS_BUSY);
307 
308  //bool _IsParkginInProgress = false;
309  SetPropertyText(IsParkginInProgress, IPS_BUSY);
310 
311  //bool _IsAtHomePosition = false;
312  SetPropertyText(IsAtHomePosition, IPS_BUSY);
313 
314  TelescopeTrackMode _TrackingMode = TRACK_SIDEREAL;
315 
316  //MountType _MountType = Equatorial;
317 
318  TelescopePierSide _PierSide = PIER_UNKNOWN;
319 
320  //bool _DoesRefractionComp = false;
321  SetPropertyText(DoesRefractionComp, IPS_BUSY);
322 
323  //bool _WaitingAtHome = false;
324  SetPropertyText(WaitingAtHome, IPS_BUSY);
325 
326  //bool _IsHomePaused = false;
327  SetPropertyText(IsHomePaused, IPS_BUSY);
328 
329  //bool _ParkFailed = false;
330  SetPropertyText(ParkFailed, IPS_BUSY);
331 
332  //bool _SlewingHome = false;
333  SetPropertyText(SlewingHome, IPS_BUSY);
334 
335 
336 
337 
338  char status[DRIVER_LEN] = {0};
339  if(sendCommand(":GU#", status))
340  {
341  Report[0].text = status;
342  Report.apply();
343  int index = 0;
344  while(true)
345  {
346  switch (status[index++])
347  {
348  case 'n':
349  _IsTracking = false;
350  SetPropertyText(IsTracking, IPS_BUSY);
351  continue;
352  case 'N':
353  _IsSlewCompleted = true;
354  SetPropertyText(IsSlewCompleted, IPS_OK);
355  continue;
356  case 'p':
357  _IsParked = false;
358  SetPropertyText(IsParked, IPS_BUSY);
359  continue;
360  case 'P':
361  _IsParked = true;
362  SetPropertyText(IsParked, IPS_OK);
363  continue;
364  case 'I':
365  //_IsParkginInProgress = true;
366  SetPropertyText(IsParkginInProgress, IPS_OK);
367  continue;
368  case 'H':
369  //_IsAtHomePosition = true;
370  SetPropertyText(IsAtHomePosition, IPS_OK);
371  continue;
372  case '(':
373  _TrackingMode = TRACK_LUNAR;
374  continue;
375  case 'O':
376  _TrackingMode = TRACK_SOLAR;
377  continue;
378  case 'k':
379  //Not Supported by TelescopeTrackMode
380  continue;
381  case 'A':
382  //_MountType = AltAz;
383  SetPropertyText(MountAltAz, IPS_OK);
384  SetPropertyText(MountEquatorial, IPS_BUSY);
385  continue;
386  case 'E':
387  //_MountType = Equatorial;
388  SetPropertyText(MountEquatorial, IPS_OK);
389  SetPropertyText(MountAltAz, IPS_BUSY);
390  continue;
391  case 'T':
392  _PierSide = PIER_EAST;
393  continue;
394  case 'W':
395  _PierSide = PIER_WEST;
396  continue;
397  case 'r':
398  //_DoesRefractionComp = true;
399  SetPropertyText(DoesRefractionComp, IPS_OK);
400  continue;
401  case 'w':
402  //_WaitingAtHome = true;
403  SetPropertyText(WaitingAtHome, IPS_OK);
404  continue;
405  case 'u':
406  //_IsHomePaused = true;
407  SetPropertyText(IsHomePaused, IPS_OK);
408  continue;
409  case 'F':
410  //_ParkFailed = true;
411  SetPropertyText(ParkFailed, IPS_OK);
412  continue;
413  case 'h':
414  //_SlewingHome = true;
415  SetPropertyText(SlewingHome, IPS_OK);
416  continue;
417  case '#':
418  break;
419  default:
420  continue;
421  }
422  break;
423  }
424  }
425 
426  switch(_TrackingMode)
427  {
429  SetPropertyText(TrackSidereal, IPS_OK);
430  SetPropertyText(TrackLunar, IPS_BUSY);
431  SetPropertyText(TrackSolar, IPS_BUSY);
432  break;
434  SetPropertyText(TrackLunar, IPS_OK);
435  SetPropertyText(TrackSidereal, IPS_BUSY);
436  SetPropertyText(TrackSolar, IPS_BUSY);
437  break;
439  SetPropertyText(TrackSolar, IPS_OK);
440  SetPropertyText(TrackSidereal, IPS_BUSY);
441  SetPropertyText(TrackLunar, IPS_BUSY);
442  break;
444  break;
445  }
446 
447  switch(_PierSide)
448  {
450  SetPropertyText(PierNone, IPS_OK);
451  SetPropertyText(PierEast, IPS_BUSY);
452  SetPropertyText(PierWest, IPS_BUSY);
453  break;
455  SetPropertyText(PierEast, IPS_OK);
456  SetPropertyText(PierNone, IPS_BUSY);
457  SetPropertyText(PierWest, IPS_BUSY);
458  break;
460  SetPropertyText(PierWest, IPS_OK);
461  SetPropertyText(PierEast, IPS_BUSY);
462  SetPropertyText(PierNone, IPS_BUSY);
463  break;
464  }
465 
466 
467  if (TrackState == SCOPE_SLEWING)
468  {
469  if (_IsSlewCompleted)
470  {
472  LOG_INFO("Slew is complete. Tracking...");
473  }
474  }
475  else if (TrackState != SCOPE_PARKED && _IsParked)
476  {
477  SetParked(true);
478  }
479  else
480  {
481  auto wasTracking = TrackStateS[INDI_ENABLED].s == ISS_ON;
482  if (wasTracking != _IsTracking)
483  TrackState = _IsTracking ? SCOPE_TRACKING : SCOPE_IDLE;
484  }
485 
486 
488  {
489  EqNP.s = IPS_ALERT;
490  IDSetNumber(&EqNP, "Error reading Ra - Dec");
491  return false;
492  }
493 
494  if (HasPierSide())
495  {
496  char response[DRIVER_LEN] = {0};
497  if (sendCommand(":Gm#", response))
498  {
499  if (response[0] == 'W')
501  else if (response[0] == 'E')
503  else
505  }
506  }
507 
509 
510  return true;
511 }
512 
513 bool LX200NYX101::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
514 {
515  return LX200Generic::ISNewNumber(dev, name, values, names, n);
516 }
517 
518 bool LX200NYX101::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
519 {
520  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
521  {
522  // Mount Type
523  if (MountTypeSP.isNameMatch(name))
524  {
525  int previousType = MountTypeSP.findOnSwitchIndex();
526  MountTypeSP.update(states, names, n);
527  IPState state = IPS_OK;
528  if (isConnected())
529  {
530  auto targetType = MountTypeSP.findOnSwitchIndex();
531  state = setMountType(targetType) ? IPS_OK : IPS_ALERT;
532  if (state == IPS_OK && previousType != targetType)
533  LOG_WARN("Restart mount in order to apply changes to Mount Type.");
534  }
535  MountTypeSP.setState(state);
536  MountTypeSP.apply();
537  return true;
538  }
539  else if(GuideRateSP.isNameMatch(name))
540  {
541  int previousType = GuideRateSP.findOnSwitchIndex();
542  GuideRateSP.update(states, names, n);
543  IPState state = IPS_OK;
544  if (isConnected())
545  {
546  auto targetType = GuideRateSP.findOnSwitchIndex();
547  state = setGuideRate(targetType) ? IPS_OK : IPS_ALERT;
548  if (state == IPS_OK && previousType != targetType)
549  LOG_WARN("RA and DEC guide rate changed.");
550  }
551  GuideRateSP.setState(state);
552  GuideRateSP.apply();
553  return true;
554  }
555  else if(HomeSP.isNameMatch(name))
556  {
557  HomeSP.update(states, names, n);
558  IPState state = IPS_OK;
559  if (isConnected())
560  {
561  HomeSP[0].setState(ISS_OFF);
562  sendCommand(":hC#");
563  }
564  HomeSP.setState(state);
565  HomeSP.apply();
566  return true;
567  }
568  else if(ResetHomeSP.isNameMatch(name))
569  {
570  ResetHomeSP.update(states, names, n);
571  IPState state = IPS_OK;
572  if (isConnected())
573  {
574  ResetHomeSP[0].setState(ISS_OFF);
575  sendCommand(":hF#");
576  }
577  ResetHomeSP.setState(state);
578  ResetHomeSP.apply();
579  return true;
580  }
581  else if(VerboseReportSP.isNameMatch(name))
582  {
583  VerboseReportSP.update(states, names, n);
584  int index = VerboseReportSP.findOnSwitchIndex();
585  VerboseReportSP[index].setState(ISS_OFF);
586 
587  if(index == 0)
588  verboseReport = true;
589  else
590  {
591 
592  SetPropertyText(IsTracking, IPS_IDLE);
593  SetPropertyText(IsSlewCompleted, IPS_IDLE);
594  SetPropertyText(IsParked, IPS_IDLE);
595  SetPropertyText(IsParkginInProgress, IPS_IDLE);
596  SetPropertyText(IsAtHomePosition, IPS_IDLE);
597  SetPropertyText(TrackSidereal, IPS_IDLE);
598  SetPropertyText(TrackLunar, IPS_IDLE);
599  SetPropertyText(TrackSolar, IPS_IDLE);
600  SetPropertyText(MountAltAz, IPS_IDLE);
601  SetPropertyText(MountEquatorial, IPS_IDLE);
602  SetPropertyText(PierNone, IPS_IDLE);
603  SetPropertyText(PierEast, IPS_IDLE);
604  SetPropertyText(PierWest, IPS_IDLE);
605  SetPropertyText(DoesRefractionComp, IPS_IDLE);
606  SetPropertyText(WaitingAtHome, IPS_IDLE);
607  SetPropertyText(IsHomePaused, IPS_IDLE);
608  SetPropertyText(ParkFailed, IPS_IDLE);
609  SetPropertyText(SlewingHome, IPS_IDLE);
610  verboseReport = false;
611  }
612 
613 
614  VerboseReportSP.setState(index == 0 ? IPS_OK : IPS_IDLE);
615  VerboseReportSP.apply();
616  return true;
617  }
618  }
619  return LX200Generic::ISNewSwitch(dev, name, states, names, n);
620 }
621 
623 {
624  double value = 0.0;
625  switch(index)
626  {
627  case 0:
628  value = 0.01;
629  break;
630  case 1:
631  value = 0.03;
632  break;
633  case 2:
634  value = 0.07;
635  break;
636  case 3:
637  value = 0.27;
638  break;
639  case 4:
640  value = 0.50;
641  break;
642  case 5:
643  value = 0.65;
644  break;
645  case 6:
646  value = 0.80;
647  break;
648  case 7:
649  value = 1;
650  break;
651  case 8:
652  value = 2.5;
653  break;
654  case 9:
655  value = 5;
656  break;
657  };
658 
659  char decCommand[DRIVER_LEN] = {0};
660  snprintf(decCommand, DRIVER_LEN, ":RE%f#", value);
661 
662  char raCommand[DRIVER_LEN] = {0};
663  snprintf(raCommand, DRIVER_LEN, ":RA%f#", value);
664 
665  return sendCommand(decCommand) && sendCommand(raCommand);
666 }
667 
668 bool LX200NYX101::setGuideRate(int rate)
669 {
670  char command[DRIVER_LEN] = {0};
671  snprintf(command, DRIVER_LEN, ":R%d#", rate);
672  return sendCommand(command);
673 }
674 
675 bool LX200NYX101::setMountType(int type)
676 {
677  return sendCommand((type == Equatorial) ? ":SXEM,1#" : "::SXEM,3#");
678 }
679 
680 bool LX200NYX101::goToPark()
681 {
682  LOG_INFO("Park requested.");
683  return sendCommand(":hP#");
684 }
685 
686 bool LX200NYX101::goToUnPark()
687 {
688  return sendCommand(":hR#");
689 }
690 
692 {
693  bool rc = goToPark();
694  if (rc)
696 
697  return rc;
698 }
699 
701 {
702  bool rc = goToUnPark();
703  if(rc)
704  SetParked(false);
705 
706  return rc;
707 }
708 
710 {
711  char response[DRIVER_LEN] = {0};
712  bool rc = sendCommand(enabled ? ":Te#" : ":Td#", response, 4, 1);
713  return rc && response[0] == '1';
714 }
715 
716 bool LX200NYX101::setUTCOffset(double offset)
717 {
718  int h {0}, m {0}, s {0};
719  char command[DRIVER_LEN] = {0};
720  offset *= -1;
721  getSexComponents(offset, &h, &m, &s);
722 
723  snprintf(command, DRIVER_LEN, ":SG%c%02d:%02d#", offset >= 0 ? '+' : '-', std::abs(h), m);
724  return setStandardProcedure(PortFD, command) == 0;
725 }
726 
727 bool LX200NYX101::setLocalDate(uint8_t days, uint8_t months, uint16_t years)
728 {
729  char command[DRIVER_LEN] = {0};
730  snprintf(command, DRIVER_LEN, ":SC%02d/%02d/%02d#", months, days, years % 100);
731  return setStandardProcedure(PortFD, command) == 0;
732 }
733 
734 bool LX200NYX101::updateLocation(double latitude, double longitude, double elevation)
735 {
736  INDI_UNUSED(elevation);
737  int d{0}, m{0}, s{0};
738 
739  // JM 2021-04-10: MUST convert from INDI longitude to standard longitude.
740  // DO NOT REMOVE
741  if (longitude > 180)
742  longitude = longitude - 360;
743 
744  char command[DRIVER_LEN] = {0};
745  // Reverse as per Meade way
746  longitude *= -1;
747  getSexComponents(longitude, &d, &m, &s);
748  snprintf(command, DRIVER_LEN, ":Sg%c%03d*%02d:%02d#", longitude >= 0 ? '+' : '-', std::abs(d), m, s);
749  if (setStandardProcedure(PortFD, command) < 0)
750  {
751  LOG_ERROR("Error setting site longitude coordinates");
752  return false;
753  }
754 
755  getSexComponents(latitude, &d, &m, &s);
756  snprintf(command, DRIVER_LEN, ":St%c%02d*%02d:%02d#", latitude >= 0 ? '+' : '-', std::abs(d), m, s);
757  if (setStandardProcedure(PortFD, command) < 0)
758  {
759  LOG_ERROR("Error setting site latitude coordinates");
760  return false;
761  }
762 
763  return true;
764 }
765 
766 
767 bool LX200NYX101::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
768 {
769  int nbytes_written = 0, nbytes_read = 0, rc = -1;
770 
771  tcflush(PortFD, TCIOFLUSH);
772 
773  if (cmd_len > 0)
774  {
775  char hex_cmd[DRIVER_LEN * 3] = {0};
776  hexDump(hex_cmd, cmd, cmd_len);
777  LOGF_DEBUG("CMD <%s>", hex_cmd);
778  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
779  }
780  else
781  {
782  LOGF_DEBUG("CMD <%s>", cmd);
783  rc = tty_write_string(PortFD, cmd, &nbytes_written);
784  }
785 
786  if (rc != TTY_OK)
787  {
788  char errstr[MAXRBUF] = {0};
789  tty_error_msg(rc, errstr, MAXRBUF);
790  LOGF_ERROR("Serial write error: %s.", errstr);
791  return false;
792  }
793 
794  if (res == nullptr)
795  {
796  tcdrain(PortFD);
797  return true;
798  }
799 
800  if (res_len > 0)
801  rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
802  else
803  rc = tty_nread_section(PortFD, res, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
804 
805  if (rc != TTY_OK)
806  {
807  char errstr[MAXRBUF] = {0};
808  tty_error_msg(rc, errstr, MAXRBUF);
809  LOGF_ERROR("Serial read error: %s.", errstr);
810  return false;
811  }
812 
813  if (res_len > 0)
814  {
815  char hex_res[DRIVER_LEN * 3] = {0};
816  hexDump(hex_res, res, res_len);
817  LOGF_DEBUG("RES <%s>", hex_res);
818  }
819  else
820  {
821  LOGF_DEBUG("RES <%s>", res);
822  }
823 
824  tcflush(PortFD, TCIOFLUSH);
825 
826  return true;
827 }
828 
829 void LX200NYX101::hexDump(char * buf, const char * data, int size)
830 {
831  for (int i = 0; i < size; i++)
832  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
833 
834  if (size > 0)
835  buf[3 * size - 1] = '\0';
836 }
837 
838 std::vector<std::string> LX200NYX101::split(const std::string &input, const std::string &regex)
839 {
840  // passing -1 as the submatch index parameter performs splitting
841  std::regex re(regex);
842  std::sregex_token_iterator
843  first{input.begin(), input.end(), re, -1},
844  last;
845  return {first, last};
846 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
TelescopeStatus TrackState
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
ISwitchVectorProperty SlewRateSP
Connection::Serial * serialConnection
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
ISwitch * SlewRateS
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
ISwitch TrackStateS[2]
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool setUTCOffset(double offset) override
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool setLocalDate(uint8_t days, uint8_t months, uint16_t years) override
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool Park() override
Park the telescope to its home position.
virtual const char * getDefaultName() override
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void setLX200Capability(uint32_t cap)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
#define MAXINDILABEL
Definition: indiapi.h:192
@ ISR_1OFMANY
Definition: indiapi.h:173
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:254
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
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
#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
const char * SETTINGS_TAB
const char * STATUS_TAB
const char * OFF
const char * ON
int setStandardProcedure(int fd, const char *data)
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
@ LX200_24
Definition: lx200driver.h:64
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2