Instrument Neutral Distributed Interface INDI  1.9.5
pmc8.cpp
Go to the documentation of this file.
1 /*
2  INDI Explore Scientific PMC8 driver
3 
4  Copyright (C) 2017 Michael Fulbright
5 
6  Additional contributors:
7  Thomas Olson, Copyright (C) 2019
8  Karl Rees, Copyright (C) 2019-2021
9 
10  Based on IEQPro driver.
11 
12  This library is free software; you can redistribute it and/or
13  modify it under the terms of the GNU Lesser General Public
14  License as published by the Free Software Foundation; either
15  version 2.1 of the License, or (at your option) any later version.
16 
17  This library is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  Lesser General Public License for more details.
21 
22  You should have received a copy of the GNU Lesser General Public
23  License along with this library; if not, write to the Free Software
24  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26 /* Experimental Mount selector switch G11 vs EXOS2 by Thomas Olson
27  *
28  */
29 
30 #include "pmc8.h"
31 
32 #include <indicom.h>
35 
36 #include <libnova/sidereal_time.h>
37 
38 #include <memory>
39 
40 #include <math.h>
41 #include <string.h>
42 
43 /* Simulation Parameters */
44 #define SLEWRATE 3 /* slew rate, degrees/s */
45 
46 #define MOUNTINFO_TAB "Mount Info"
47 
48 #define PMC8_DEFAULT_PORT 54372
49 #define PMC8_DEFAULT_IP_ADDRESS "192.168.47.1"
50 #define PMC8_TRACKING_AUTODETECT_INTERVAL 10
51 
52 static std::unique_ptr<PMC8> scope(new PMC8());
53 
54 /* Constructor */
56 {
57  currentRA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys());
58  currentDEC = 90;
59 
60  DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE");
61 
65  9);
66 
67  setVersion(0, 3);
68 }
69 
71 {
72 }
73 
74 const char *PMC8::getDefaultName()
75 {
76  return "PMC8";
77 }
78 
80 {
82 
83  // My understanding is that all mounts communicate at 115200
85 
88 
89  // Serial Cable Connection Type
90  // Letting them choose standard cable can speed up connection time significantly
91  IUFillSwitch(&SerialCableTypeS[0], "SERIAL_CABLE_AUTO", "Auto", ISS_ON);
92  IUFillSwitch(&SerialCableTypeS[1], "SERIAL_CABLE_INVERTED", "Inverted", ISS_OFF);
93  IUFillSwitch(&SerialCableTypeS[2], "SERIAL_CABLE_STANDARD", "Standard", ISS_OFF);
94  IUFillSwitchVector(&SerialCableTypeSP, SerialCableTypeS, 3, getDeviceName(), "SERIAL_CABLE_TYPE", "Serial Cable", CONNECTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
95 
96  // Mount Type
97  IUFillSwitch(&MountTypeS[MOUNT_G11], "MOUNT_G11", "G11", ISS_OFF);
98  IUFillSwitch(&MountTypeS[MOUNT_EXOS2], "MOUNT_EXOS2", "EXOS2", ISS_OFF);
99  IUFillSwitch(&MountTypeS[MOUNT_iEXOS100], "MOUNT_iEXOS100", "iEXOS100", ISS_OFF);
100  IUFillSwitchVector(&MountTypeSP, MountTypeS, 3, getDeviceName(), "MOUNT_TYPE", "Mount Type", CONNECTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
101 
102 
103  /* Tracking Mode */
104  // order is important, since driver assumes solar = 1, lunar = 2
105  AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
106  AddTrackMode("TRACK_SOLAR", "Solar");
107  AddTrackMode("TRACK_LUNAR", "Lunar");
108  //AddTrackMode("TRACK_KING", "King"); // King appears to be effectively the same as Solar, at least for EXOS-2, and a bit of pain to implement with auto-detection
109  AddTrackMode("TRACK_CUSTOM", "Custom");
110 
111  // Set TrackRate limits
112  /*TrackRateN[AXIS_RA].min = -PMC8_MAX_TRACK_RATE;
113  TrackRateN[AXIS_RA].max = PMC8_MAX_TRACK_RATE;
114  TrackRateN[AXIS_DE].min = -0.01;
115  TrackRateN[AXIS_DE].max = 0.01;*/
116 
117  // what to do after goto operation
118  IUFillSwitch(&PostGotoS[0], "GOTO_START_TRACKING", "Start / Resume Tracking", ISS_ON);
119  IUFillSwitch(&PostGotoS[1], "GOTO_RESUME_PREVIOUS", "Previous State", ISS_OFF);
120  IUFillSwitch(&PostGotoS[2], "GOTO_STOP_TRACKING", "No Tracking", ISS_OFF);
121  IUFillSwitchVector(&PostGotoSP, PostGotoS, 3, getDeviceName(), "POST_GOTO_SETTINGS", "Post Goto", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
122 
123  // relabel move speeds
124  strcpy(SlewRateSP.sp[0].label, "4x");
125  strcpy(SlewRateSP.sp[1].label, "8x");
126  strcpy(SlewRateSP.sp[2].label, "16x");
127  strcpy(SlewRateSP.sp[3].label, "32x");
128  strcpy(SlewRateSP.sp[4].label, "64x");
129  strcpy(SlewRateSP.sp[5].label, "128x");
130  strcpy(SlewRateSP.sp[6].label, "256x");
131  strcpy(SlewRateSP.sp[7].label, "512x");
132  strcpy(SlewRateSP.sp[8].label, "833x");
133 
134  // settings for ramping up/down when moving
135  IUFillNumber(&RampN[0], "RAMP_INTERVAL", "Interval (ms)", "%g", 20, 1000, 5, 200);
136  IUFillNumber(&RampN[1], "RAMP_BASESTEP", "Base Step", "%g", 1, 256, 1, 4);
137  IUFillNumber(&RampN[2], "RAMP_FACTOR", "Factor", "%g", 1.0, 2.0, 0.1, 1.4);
138  IUFillNumberVector(&RampNP, RampN, 3, getDeviceName(), "RAMP_SETTINGS", "Move Ramp", MOTION_TAB, IP_RW, 0, IPS_IDLE);
139 
140  /* How fast do we guide compared to sidereal rate */
141  IUFillNumber(&GuideRateN[0], "GUIDE_RATE_RA", "RA (x Sidereal)", "%g", 0.1, 1.0, 0.1, 0.4);
142  IUFillNumber(&GuideRateN[1], "GUIDE_RATE_DE", "DEC (x Sidereal)", "%g", 0.1, 1.0, 0.1, 0.4);
143  IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guide Rate", GUIDE_TAB, IP_RW, 0, IPS_IDLE);
144  IUFillNumber(&LegacyGuideRateN[0], "LEGACY_GUIDE_RATE", "x Sidereal", "%g", 0.1, 1.0, 0.1, 0.4);
145  IUFillNumberVector(&LegacyGuideRateNP, LegacyGuideRateN, 1, getDeviceName(), "LEGACY_GUIDE_RATE", "Guide Rate", GUIDE_TAB, IP_RW, 0, IPS_IDLE);
146 
148 
150 
151  // Driver does not support custom parking yet.
153 
154  addAuxControls();
155 
157 
158  IUFillText(&FirmwareT[0], "Version", "Version", "");
159  IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "Firmware", "Firmware", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
160 
162 
163  return true;
164 }
165 
167 {
169 
170  if (isConnected())
171  {
172  getStartupData();
173 
174  defineProperty(&PostGotoSP);
175  loadConfig(true,PostGotoSP.name);
176 
177  defineProperty(&RampNP);
178  loadConfig(true,RampNP.name);
179 
180  if (firmwareInfo.IsRev2Compliant)
181  {
182  defineProperty(&GuideRateNP);
183  }
184  else
185  {
186  defineProperty(&LegacyGuideRateNP);
187  }
188 
191 
192  defineProperty(&FirmwareTP);
193 
194  // do not support park position
197  }
198  else
199  {
200  deleteProperty(PostGotoSP.name);
201 
204 
205  if (firmwareInfo.IsRev2Compliant)
206  {
207  deleteProperty(GuideRateNP.name);
208  }
209  else
210  {
211  deleteProperty(LegacyGuideRateNP.name);
212  }
213 
214  deleteProperty(FirmwareTP.name);
215 
216  deleteProperty(RampNP.name);
217  }
218 
219  return true;
220 }
221 
222 void PMC8::getStartupData()
223 {
224  LOG_DEBUG("Getting firmware data...");
225  if (get_pmc8_firmware(PortFD, &firmwareInfo))
226  {
227  const char *c;
228 
229  FirmwareTP.s = IPS_OK;
230  c = firmwareInfo.MainBoardFirmware.c_str();
231  LOGF_INFO("firmware = %s.", c);
232 
233  // not sure if there's really a point to the mount switch anymore if we know the mount from the firmware - perhaps remove as newer firmware becomes standard?
234  // populate mount type switch in interface from firmware if possible
235  if (firmwareInfo.MountType == MOUNT_EXOS2)
236  {
237  MountTypeS[MOUNT_EXOS2].s = ISS_ON;
238  LOG_INFO("Detected mount type as Exos2.");
239  }
240  else if (firmwareInfo.MountType == MOUNT_G11)
241  {
242  MountTypeS[MOUNT_G11].s = ISS_ON;
243  LOG_INFO("Detected mount type as G11.");
244  }
245  else if (firmwareInfo.MountType == MOUNT_iEXOS100)
246  {
247  MountTypeS[MOUNT_iEXOS100].s = ISS_ON;
248  LOG_INFO("Detected mount type as iExos100.");
249  }
250  else
251  {
252  LOG_INFO("Cannot detect mount type--perhaps this is older firmware?");
253  if (strstr(getDeviceName(), "EXOS2"))
254  {
255  MountTypeS[MOUNT_EXOS2].s = ISS_ON;
256  LOG_INFO("Guessing mount is EXOS2 from device name.");
257  }
258  else if (strstr(getDeviceName(), "iEXOS100"))
259  {
260  MountTypeS[MOUNT_iEXOS100].s = ISS_ON;
261  LOG_INFO("Guessing mount is iEXOS100 from device name.");
262  }
263  else
264  {
265  MountTypeS[MOUNT_G11].s = ISS_ON;
266  LOG_INFO("Guessing mount is G11.");
267  }
268  }
269  MountTypeSP.s = IPS_OK;
270  IDSetSwitch(&MountTypeSP, nullptr);
271 
272  IUSaveText(&FirmwareT[0], c);
273  IDSetText(&FirmwareTP, nullptr);
274  }
275 
276  // get SRF values
277  if (firmwareInfo.IsRev2Compliant)
278  {
279  double rate = 0.4;
281  {
282  GuideRateN[0].value = rate;
283  GuideRateNP.s = IPS_OK;
284  IDSetNumber(&GuideRateNP, nullptr);
285  }
287  {
288  GuideRateN[1].value = rate;
289  GuideRateNP.s = IPS_OK;
290  IDSetNumber(&GuideRateNP, nullptr);
291  }
292  }
293 
294  // PMC8 doesn't store location permanently so read from config and set
295  // Convert to INDI standard longitude (0 to 360 Eastward)
296  double longitude = LocationN[LOCATION_LONGITUDE].value;
297  double latitude = LocationN[LOCATION_LATITUDE].value;
298 
299  // must also keep "low level" aware of position to convert motor counts to RA/DEC
300  set_pmc8_location(latitude, longitude);
301 
302  // seems like best place to put a warning that will be seen in log window of EKOS/etc
303  LOG_INFO("The PMC-Eight driver is in BETA development currently.");
304  LOG_INFO("Be prepared to intervene if something unexpected occurs.");
305 
306 #if 0
307  // FIXEME - Need to handle southern hemisphere for DEC?
308  double HA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys());
309  double DEC = 90;
310 
311  // currently only park at motor position (0, 0)
312  if (InitPark())
313  {
314  // If loading parking data is successful, we just set the default parking values.
316  SetAxis2ParkDefault(DEC);
317  }
318  else
319  {
320  // Otherwise, we set all parking data to default in case no parking data is found.
321  SetAxis1Park(HA);
322  SetAxis2Park(DEC);
324  SetAxis2ParkDefault(DEC);
325  }
326 #endif
327 
328 #if 0
329  // FIXME - Need to implement simulation functionality
330  if (isSimulation())
331  {
332  if (isParked())
334  else
336  }
337 #endif
338 }
339 
340 bool PMC8::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
341 {
342  if (!strcmp(dev, getDeviceName()))
343  {
344  // Guiding Rate
345  if (!strcmp(name, RampNP.name))
346  {
347  IUUpdateNumber(&RampNP, values, names, n);
348  RampNP.s = IPS_OK;
349  IDSetNumber(&RampNP, nullptr);
350 
351  return true;
352  }
353  if (!strcmp(name, LegacyGuideRateNP.name))
354  {
355  IUUpdateNumber(&GuideRateNP, values, names, n);
356 
357  if (set_pmc8_guide_rate(PortFD, PMC8_AXIS_RA, LegacyGuideRateN[0].value))
358  LegacyGuideRateNP.s = IPS_OK;
359  else
360  LegacyGuideRateNP.s = IPS_ALERT;
361 
362  IDSetNumber(&LegacyGuideRateNP, nullptr);
363 
364  return true;
365  }
366  if (!strcmp(name, GuideRateNP.name))
367  {
368  IUUpdateNumber(&GuideRateNP, values, names, n);
369 
370  if (set_pmc8_guide_rate(PortFD, PMC8_AXIS_RA, GuideRateN[0].value) &&
371  set_pmc8_guide_rate(PortFD, PMC8_AXIS_DEC, GuideRateN[1].value))
372  GuideRateNP.s = IPS_OK;
373  else
374  GuideRateNP.s = IPS_ALERT;
375 
376  IDSetNumber(&GuideRateNP, nullptr);
377 
378  return true;
379  }
380  if (!strcmp(name, GuideNSNP.name) || !strcmp(name, GuideWENP.name))
381  {
382  processGuiderProperties(name, values, names, n);
383  return true;
384  }
385  }
386 
387  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
388 }
389 
390 void PMC8::ISGetProperties(const char *dev)
391 {
393  defineProperty(&MountTypeSP);
394  defineProperty(&SerialCableTypeSP);
395  loadConfig(true,SerialCableTypeSP.name);
396 }
397 
398 bool PMC8::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
399 {
400  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
401  {
402  if (strcmp(name, MountTypeSP.name) == 0)
403  {
404  IUUpdateSwitch(&MountTypeSP, states, names, n);
405  int currentMountIndex = IUFindOnSwitchIndex(&MountTypeSP);
406  LOGF_INFO("Selected mount is %s", MountTypeS[currentMountIndex].label);
407 
408  //right now, this lets the user override the parameters for the detected mount. Perhaps we should prevent the user from doing so?
409  set_pmc8_mountParameters(currentMountIndex);
410  MountTypeSP.s = IPS_OK;
411  IDSetSwitch(&MountTypeSP, nullptr);
412  return true;
413  }
414  if (strcmp(name, SerialCableTypeSP.name) == 0)
415  {
416  IUUpdateSwitch(&SerialCableTypeSP, states, names, n);
417  SerialCableTypeSP.s = IPS_OK;
418  IDSetSwitch(&SerialCableTypeSP, nullptr);
419  return true;
420  }
421  if (strcmp(name, PostGotoSP.name) == 0)
422  {
423  IUUpdateSwitch(&PostGotoSP, states, names, n);
424  // for v2 firmware, if halt after goto is selected, tell driver to use ESPt2
425  set_pmc8_goto_resume(!((IUFindOnSwitchIndex(&PostGotoSP) == 2) && firmwareInfo.IsRev2Compliant));
426  PostGotoSP.s = IPS_OK;
427  IDSetSwitch(&PostGotoSP, nullptr);
428  return true;
429  }
430  }
431 
432  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
433 }
434 
436 {
437  bool rc = false;
438 
439  // try to disconnect and reconnect if reconnect flag is set
440 
442  {
443  int rc = Disconnect();
444  if (rc) setConnected(false);
445  rc = Connect();
446  if (rc) setConnected(true, IPS_OK);
447  return false;
448  }
449 
450  if (isSimulation())
451  mountSim();
452 
453  // avoid unnecessary status calls to mount while pulse guiding so we don't lock up the mount for 40+ ms right when it needs to start/stop
454  if (isPulsingNS || isPulsingWE) return true;
455 
456  bool slewing = false;
457 
458  switch (TrackState)
459  {
460  case SCOPE_SLEWING:
461  // are we done?
462  // check slew state
463  rc = get_pmc8_is_scope_slewing(PortFD, slewing);
464  if (!rc)
465  {
466  LOG_ERROR("PMC8::ReadScopeStatus() - unable to check slew state");
467  }
468  else
469  {
470  if (slewing == false)
471  {
472  if ((IUFindOnSwitchIndex(&PostGotoSP) == 0) ||
473  ((IUFindOnSwitchIndex(&PostGotoSP) == 1) && (RememberTrackState == SCOPE_TRACKING)))
474  {
475  LOG_INFO("Slew complete, tracking...");
478 
479  // Don't want to restart tracking after goto with v2 firmware, since mount does automatically
480  // and we might detect that slewing has stopped before it fully settles
481  if (!firmwareInfo.IsRev2Compliant)
482  {
483  if (!SetTrackEnabled(true))
484  {
485  LOG_ERROR("slew complete - unable to enable tracking");
486  return false;
487  }
488  }
489  }
490  else
491  {
492  LOG_INFO("Slew complete.");
494  }
495  }
496  }
497 
498  break;
499 
500  case SCOPE_PARKING:
501  // are we done?
502  // check slew state
503  rc = get_pmc8_is_scope_slewing(PortFD, slewing);
504  if (!rc)
505  {
506  LOG_ERROR("PMC8::ReadScopeStatus() - unable to check slew state");
507  }
508  else
509  {
510  if (slewing == false)
511  {
513  LOG_DEBUG("Mount tracking is off.");
514 
515  SetParked(true);
516 
517  saveConfig(true);
518  }
519  }
520  break;
521 
522  case SCOPE_IDLE:
523  //periodically check to see if we've entered tracking state (e.g. at startup or from other client)
524  if (!trackingPollCounter--)
525  {
526 
527  trackingPollCounter = PMC8_TRACKING_AUTODETECT_INTERVAL;
528 
529  // make sure we aren't moving manually to avoid false positives
530  if (moveInfoDEC.state == PMC8_MOVE_INACTIVE && moveInfoRA.state == PMC8_MOVE_INACTIVE)
531  {
532 
533  double track_rate;
534  uint8_t track_mode;
535 
536  rc = get_pmc8_tracking_data(PortFD,track_rate,track_mode);
537 
538  if (rc && ((int)track_rate>0) && ((int)track_rate<=PMC8_MAX_TRACK_RATE))
539  {
541  TrackModeS[convertFromPMC8TrackMode(track_mode)].s = ISS_ON;
542  TrackModeSP.s = IPS_OK;
543  IDSetSwitch(&TrackModeSP, nullptr);
545  if (track_mode == PMC8_TRACK_CUSTOM)
546  {
548  TrackRateN[AXIS_RA].value = track_rate;
549  IDSetNumber(&TrackRateNP, nullptr);
550  }
551  currentTrackRate = track_rate;
552  DEBUGF(INDI::Logger::DBG_DEBUG, "Mount tracking at %f arcsec / sec", track_rate);
553  }
554  }
555  }
556  break;
557 
558  case SCOPE_TRACKING:
559  //periodically check to see if we've stopped tracking or changed speed (e.g. from other client)
560  if (!trackingPollCounter--)
561  {
562  trackingPollCounter = PMC8_TRACKING_AUTODETECT_INTERVAL;
563 
564  // make sure we aren't moving manually to avoid false positives
565  if (moveInfoDEC.state == PMC8_MOVE_INACTIVE && moveInfoRA.state == PMC8_MOVE_INACTIVE)
566  {
567 
568  double track_rate;
569  uint8_t track_mode;
570 
571  rc = get_pmc8_tracking_data(PortFD,track_rate,track_mode);
572 
573  if (rc && ((int)track_rate==0))
574  {
575  DEBUG(INDI::Logger::DBG_SESSION, "Mount appears to have stopped tracking");
577  }
578  else if (rc && ((int)track_rate<=PMC8_MAX_TRACK_RATE))
579  {
580  if (TrackModeS[convertFromPMC8TrackMode(track_mode)].s != ISS_ON)
581  {
583  TrackModeS[convertFromPMC8TrackMode(track_mode)].s = ISS_ON;
584  IDSetSwitch(&TrackModeSP, nullptr);
585  }
586  if (currentTrackRate != track_rate)
587  {
589  if (track_mode == PMC8_TRACK_CUSTOM)
590  {
592  TrackRateN[AXIS_RA].value = track_rate;
593  IDSetNumber(&TrackRateNP, nullptr);
594  }
595  currentTrackRate = track_rate;
596  }
597  DEBUGF(INDI::Logger::DBG_DEBUG, "Mount tracking at %f arcsec / sec", track_rate);
598  }
599  }
600  }
601 
602  default:
603  break;
604  }
605 
606  rc = get_pmc8_coords(PortFD, currentRA, currentDEC);
607 
608  if (rc)
609  NewRaDec(currentRA, currentDEC);
610 
611  return rc;
612 }
613 
614 bool PMC8::Goto(double r, double d)
615 {
616 
617  if (isPulsingNS ||
618  isPulsingWE ||
619  moveInfoDEC.state != PMC8_MOVE_INACTIVE ||
620  moveInfoRA.state != PMC8_MOVE_INACTIVE ||
622  {
623  LOG_ERROR("Cannot slew while moving or guiding. Please stop moving or guiding first");
624  return false;
625  }
626 
627  // start tracking if we're idle, so mount will track at correct rate post-goto
629  if ((TrackState != SCOPE_TRACKING) && (IUFindOnSwitchIndex(&PostGotoSP) == 0) && firmwareInfo.IsRev2Compliant)
630  {
631  SetTrackEnabled(true);
632  }
633  else if (IUFindOnSwitchIndex(&PostGotoSP) == 2)
634  {
636  }
637 
638  char RAStr[64] = {0}, DecStr[64] = {0};
639 
640  targetRA = r;
641  targetDEC = d;
642 
643  fs_sexa(RAStr, targetRA, 2, 3600);
644  fs_sexa(DecStr, targetDEC, 2, 3600);
645 
646  DEBUGF(INDI::Logger::DBG_SESSION, "Slewing to RA: %s - DEC: %s", RAStr, DecStr);
647 
648  if (slew_pmc8(PortFD, r, d) == false)
649  {
650  LOG_ERROR("Failed to slew.");
651  return false;
652  }
653 
655 
656  return true;
657 }
658 
659 bool PMC8::Sync(double ra, double dec)
660 {
661 
662  targetRA = ra;
663  targetDEC = dec;
664  char RAStr[64] = {0}, DecStr[64] = {0};
665 
666  fs_sexa(RAStr, targetRA, 2, 3600);
667  fs_sexa(DecStr, targetDEC, 2, 3600);
668 
669  DEBUGF(INDI::Logger::DBG_SESSION, "Syncing to RA: %s - DEC: %s", RAStr, DecStr);
670 
671  if (sync_pmc8(PortFD, ra, dec) == false)
672  {
673  LOG_ERROR("Failed to sync.");
674  }
675 
676  EqNP.s = IPS_OK;
677 
678  currentRA = ra;
679  currentDEC = dec;
680 
681  NewRaDec(currentRA, currentDEC);
682 
683  return true;
684 }
685 
687 {
688 
689  //GUIDE Abort guide operations.
690  if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
691  {
693  GuideNSN[0].value = GuideNSN[1].value = 0.0;
694  GuideWEN[0].value = GuideWEN[1].value = 0.0;
695 
696  if (GuideNSTID)
697  {
699  GuideNSTID = 0;
700  }
701 
702  if (GuideWETID)
703  {
705  GuideNSTID = 0;
706  }
707 
708  LOG_INFO("Guide aborted.");
709  IDSetNumber(&GuideNSNP, nullptr);
710  IDSetNumber(&GuideWENP, nullptr);
711 
712  return true;
713  }
714 
715  //MOVE Abort move operations.
716  if ((moveInfoDEC.state == PMC8_MOVE_ACTIVE) || (moveInfoRA.state == PMC8_MOVE_ACTIVE))
717  {
718  if (moveInfoDEC.state == PMC8_MOVE_ACTIVE)
719  {
720  MoveNS((INDI_DIR_NS)moveInfoDEC.moveDir,MOTION_STOP);
721  }
722  if (moveInfoRA.state == PMC8_MOVE_ACTIVE)
723  {
724  MoveWE((INDI_DIR_WE)moveInfoRA.moveDir,MOTION_STOP);
725  }
726  return true;
727  LOG_INFO("Move aborted.");
728  }
729 
730  LOG_INFO("Abort called--stopping all motion.");
731  if (abort_pmc8(PortFD))
732  {
734  return true;
735  }
736  else return false;
737 }
738 
740 {
741 #if 0
742  // FIXME - Currently only support parking at motor position (0, 0)
743  targetRA = GetAxis1Park();
744  targetDEC = GetAxis2Park();
745  if (set_pmc8_radec(PortFD, r, d) == false)
746  {
747  LOG_ERROR("Error setting RA/DEC.");
748  return false;
749  }
750 #endif
751 
752  //if we're already parking, no need to do anything
753  if (TrackState == SCOPE_PARKING)
754  {
755  return true;
756  }
757 
758  if (park_pmc8(PortFD))
759  {
761  LOG_INFO("Telescope parking in progress to motor position (0, 0)");
762  return true;
763  }
764  else
765  {
766  return false;
767  }
768 }
769 
771 {
772  if (unpark_pmc8(PortFD))
773  {
774  SetParked(false);
776  return true;
777  }
778  else
779  {
780  return false;
781  }
782 }
783 
785 {
786  if (isSimulation())
787  {
790  set_pmc8_sim_move_rate(64*15);
791  // set_pmc8_sim_hemisphere(HEMI_NORTH);
792  }
793 
796  {
797  if (IUFindOnSwitchIndex(&SerialCableTypeSP) == 1) conn = PMC8_SERIAL_INVERTED;
798  if (IUFindOnSwitchIndex(&SerialCableTypeSP) == 2) conn = PMC8_SERIAL_STANDARD;
799  }
800  else
801  {
802  conn = PMC8_ETHERNET;
803  }
804 
805  return check_pmc8_connection(PortFD,conn);
806 }
807 
808 bool PMC8::updateTime(ln_date *utc, double utc_offset)
809 {
810  // mark unused
811  INDI_UNUSED(utc);
812  INDI_UNUSED(utc_offset);
813 
814  LOG_ERROR("PMC8::updateTime() not implemented!");
815  return false;
816 
817 }
818 
819 bool PMC8::updateLocation(double latitude, double longitude, double elevation)
820 {
821  INDI_UNUSED(elevation);
822 
823  if (longitude > 180)
824  longitude -= 360;
825 
826  // experimental support for Southern Hemisphere!
827  if (latitude < 0)
828  {
829  LOG_WARN("Southern Hemisphere support still experimental!");
830  //return false;
831  }
832 
833  // must also keep "low level" aware of position to convert motor counts to RA/DEC
834  set_pmc8_location(latitude, longitude);
835 
836  char l[32] = {0}, L[32] = {0};
837  fs_sexa(l, latitude, 3, 3600);
838  fs_sexa(L, longitude, 4, 3600);
839 
840  LOGF_INFO("Site location updated to Lat %.32s - Long %.32s", l, L);
841 
842  return true;
843 }
844 
845 void PMC8::debugTriggered(bool enable)
846 {
847  set_pmc8_debug(enable);
848 }
849 
850 void PMC8::simulationTriggered(bool enable)
851 {
852  set_pmc8_simulation(enable);
853 }
854 
856 {
857  int mode = IUFindOnSwitchIndex(&SlewRateSP);
858  if (mode >= 8) return PMC8_MAX_MOVE_RATE;
859  return 4 * pow(2,mode) * 15;
860 }
861 
862 
864 {
865 
866  PMC8MoveInfo *moveInfo = ((dir == PMC8_N) | (dir == PMC8_S)) ? &moveInfoDEC : &moveInfoRA;
867 
868  if (moveInfo->state != PMC8_MOVE_RAMPING)
869  {
870  return false; //shouldn't be here
871  LOG_ERROR("Ramp function called while not in ramp state");
872  }
873 
874  int newrate = moveInfo->rampLastStep;
875 
876  if (moveInfo->rampDir == PMC8_RAMP_UP)
877  {
878  newrate += RampN[1].value * pow(RampN[2].value,moveInfo->rampIteration++) * 15;
879  }
880  else
881  {
882  newrate -= RampN[1].value * pow(RampN[2].value,--moveInfo->rampIteration) * 15;
883  }
884 
885  int adjrate = newrate;
886 
887  //check to see if we're done
888  if (newrate >= moveInfo->targetRate)
889  {
890  adjrate = moveInfo->targetRate;
891  moveInfo->state = PMC8_MOVE_ACTIVE;
892  }
893  else if (newrate <= 0)
894  {
895  adjrate = 0;
896  moveInfo->state = PMC8_MOVE_INACTIVE;
897  //restore tracking if we're at 0
898  if ((dir == PMC8_E) || (dir == PMC8_W))
899  {
900  if (TrackState == SCOPE_TRACKING)
901  {
902  if (!SetTrackEnabled(true))
903  {
904  LOG_ERROR("slew complete - unable to enable tracking");
905  return false;
906  }
907  }
908 
909  return true;
910  }
911  }
912 
913  //adjust for current tracking rate
914  if (dir == PMC8_E) adjrate += round(currentTrackRate);
915  else if (dir == PMC8_W) adjrate -= round(currentTrackRate);
916 
917  LOGF_EXTRA3("Ramping: mount dir %d, ramping dir %d, iteration %d, step to %d",dir, moveInfo->rampDir, moveInfo->rampIteration, adjrate);
918 
919  if (!set_pmc8_move_rate_axis(PortFD, dir, adjrate))
920  {
921  LOGF_ERROR("Error ramping move rate: mount dir %d, ramping dir %d, iteration %d, step to %d",dir, moveInfo->rampDir, moveInfo->rampIteration, adjrate);
922  moveInfo->state = PMC8_MOVE_INACTIVE;
923  return false;
924  }
925 
926  moveInfo->rampLastStep = newrate;
927 
928  return true;
929 }
930 
931 //MOVE The timer helper functions.
933 {
934  PMC8* pmc8 = static_cast<PMC8*>(p);
935  if (pmc8->ramp_movement(PMC8_N) && (pmc8->moveInfoDEC.state == PMC8_MOVE_RAMPING))
936  pmc8->moveInfoDEC.timer = IEAddTimer(pmc8->RampN[0].value, rampTimeoutHelperN, p);
937 }
939 {
940  PMC8* pmc8 = static_cast<PMC8*>(p);
941  if (pmc8->ramp_movement(PMC8_S) && (pmc8->moveInfoDEC.state == PMC8_MOVE_RAMPING))
942  pmc8->moveInfoDEC.timer = IEAddTimer(pmc8->RampN[0].value, rampTimeoutHelperS, p);
943 }
945 {
946  PMC8* pmc8 = static_cast<PMC8*>(p);
947  if (pmc8->ramp_movement(PMC8_W) && (pmc8->moveInfoRA.state == PMC8_MOVE_RAMPING))
948  pmc8->moveInfoRA.timer = IEAddTimer(pmc8->RampN[0].value, rampTimeoutHelperW, p);
949 }
951 {
952  PMC8* pmc8 = static_cast<PMC8*>(p);
953  if (pmc8->ramp_movement(PMC8_E) && (pmc8->moveInfoRA.state == PMC8_MOVE_RAMPING))
954  pmc8->moveInfoRA.timer = IEAddTimer(pmc8->RampN[0].value, rampTimeoutHelperE, p);
955 }
956 
957 
959 {
960  if (TrackState == SCOPE_PARKED)
961  {
962  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
963  return false;
964  }
965  if (TrackState == SCOPE_SLEWING)
966  {
967  LOG_ERROR("Mount is slewing. Wait to issue move command until goto completes.");
968  return false;
969  }
970  if ((moveInfoDEC.state == PMC8_MOVE_ACTIVE) && (moveInfoDEC.moveDir != dir))
971  {
972  LOG_ERROR("Mount received command to move in opposite direction before stopping. This shouldn't happen.");
973  return false;
974  }
975 
976  // read desired move rate
977  int currentIndex = IUFindOnSwitchIndex(&SlewRateSP);
978  LOGF_DEBUG("MoveNS at slew index %d", currentIndex);
979 
980  switch (command)
981  {
982  case MOTION_START:
983  moveInfoDEC.rampDir = PMC8_RAMP_UP;
984  moveInfoDEC.targetRate = getSlewRate();
985  // if we're still ramping down, we can bypass resetting the state and adding a timer
986  // but we do need to make sure it's the same direction first (if not, kill our previous timer)
987  if (moveInfoDEC.state == PMC8_MOVE_RAMPING)
988  {
989  if (moveInfoDEC.moveDir == dir) return true;
990  IERmTimer(moveInfoDEC.timer);
991  LOG_WARN("Started moving other direction before ramp down completed. This *may* cause mechanical problems with mount. It is adviseable to wait for axis movement to settle before switching directions.");
992  }
993  moveInfoDEC.moveDir = dir;
994  moveInfoDEC.state = PMC8_MOVE_RAMPING;
995  moveInfoDEC.rampIteration = 0;
996  moveInfoDEC.rampLastStep = 0;
997 
998  LOGF_INFO("Moving toward %s.", (dir == DIRECTION_NORTH) ? "North" : "South");
999 
1000  break;
1001 
1002  case MOTION_STOP:
1003  // if we've already started moving other direction, no need to stop
1004  if (moveInfoDEC.moveDir != dir)
1005  {
1006  LOGF_DEBUG("Stop command issued for direction %d, but we're not moving that way", dir);
1007  return false;
1008  }
1009 
1010  moveInfoDEC.rampDir = PMC8_RAMP_DOWN;
1011  // if we're still ramping up, we can bypass adding a timer
1012  if (moveInfoDEC.state == PMC8_MOVE_RAMPING) return true;
1013  moveInfoDEC.state = PMC8_MOVE_RAMPING;
1014 
1015  LOGF_INFO("%s motion stopping.", (dir == DIRECTION_NORTH) ? "North" : "South");
1016 
1017  break;
1018  }
1019 
1020  if (dir == DIRECTION_NORTH)
1021  rampTimeoutHelperN(this);
1022  else
1023  rampTimeoutHelperS(this);
1024 
1025  return true;
1026 }
1027 
1028 
1030 {
1031  if (TrackState == SCOPE_PARKED)
1032  {
1033  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
1034  return false;
1035  }
1036  if (TrackState == SCOPE_SLEWING)
1037  {
1038  LOG_ERROR("Mount is already slewing. Wait to issue move command until done slewing.");
1039  return false;
1040  }
1041  if ((moveInfoRA.state == PMC8_MOVE_ACTIVE) && (moveInfoRA.moveDir != dir))
1042  {
1043  LOG_ERROR("Mount received command to move in opposite direction before stopping. This shouldn't happen.");
1044  return false;
1045  }
1046 
1047  // read desired move rate
1048  int currentIndex = IUFindOnSwitchIndex(&SlewRateSP);
1049  LOGF_DEBUG("MoveWE at slew index %d", currentIndex);
1050 
1051  switch (command)
1052  {
1053  case MOTION_START:
1054  moveInfoRA.rampDir = PMC8_RAMP_UP;
1055  moveInfoRA.targetRate = getSlewRate();
1056  // if we're still ramping down, we can bypass resetting the state and adding a timer
1057  // but we do need to make sure it's the same direction first (if not, kill our previous timer)
1058  if (moveInfoRA.state == PMC8_MOVE_RAMPING)
1059  {
1060  if (moveInfoRA.moveDir == dir) return true;
1061  IERmTimer(moveInfoRA.timer);
1062  LOG_WARN("Started moving other direction before ramp down completed. This *may* cause mechanical problems with mount. It is adviseable to wait for axis movement to settle before switching directions.");
1063  }
1064  moveInfoRA.moveDir = dir;
1065  moveInfoRA.state = PMC8_MOVE_RAMPING;
1066  moveInfoRA.rampIteration = 0;
1067  moveInfoRA.rampLastStep = 0;
1068 
1069  LOGF_INFO("Moving toward %s.", (dir == DIRECTION_WEST) ? "West" : "East");
1070 
1071  break;
1072 
1073  case MOTION_STOP:
1074  // if we've already started moving other direction, no need to stop
1075  if (moveInfoRA.moveDir != dir)
1076  {
1077  LOGF_DEBUG("Stop command issued for direction %d, but we're not moving that way", dir);
1078  return false;
1079  }
1080 
1081  moveInfoRA.rampDir = PMC8_RAMP_DOWN;
1082  // if we're still ramping up, we can bypass adding a timer
1083  if (moveInfoRA.state == PMC8_MOVE_RAMPING) return true;
1084  moveInfoRA.state = PMC8_MOVE_RAMPING;
1085 
1086  LOGF_INFO("%s motion stopping.", (dir == DIRECTION_WEST) ? "West" : "East");
1087 
1088  break;
1089  }
1090 
1091  if (dir == DIRECTION_EAST)
1092  rampTimeoutHelperE(this);
1093  else
1094  rampTimeoutHelperW(this);
1095 
1096  return true;
1097 }
1098 
1100 {
1101  IPState ret = IPS_IDLE;
1102  long timetaken_us = 0;
1103  int timeremain_ms = 0;
1104 
1105  //only guide if tracking
1106  if (TrackState == SCOPE_TRACKING)
1107  {
1108 
1109  // If already moving, then stop movement
1110  if (MovementNSSP.s == IPS_BUSY)
1111  {
1112  int dir = IUFindOnSwitchIndex(&MovementNSSP);
1114  }
1115 
1116  if (GuideNSTID)
1117  {
1119  GuideNSTID = 0;
1120  }
1121 
1122  isPulsingNS = true;
1123  start_pmc8_guide(PortFD, PMC8_N, (int)ms, timetaken_us, 0);
1124 
1125  timeremain_ms = (int)(ms - ((float)timetaken_us) / 1000.0);
1126 
1127  if (timeremain_ms < 0)
1128  timeremain_ms = 0;
1129 
1130  ret = IPS_BUSY;
1131  }
1132  else
1133  {
1134  LOG_INFO("Mount not tracking--cannot guide.");
1135  }
1136  GuideNSTID = IEAddTimer(timeremain_ms, guideTimeoutHelperN, this);
1137  return ret;
1138 }
1139 
1141 {
1142  IPState ret = IPS_IDLE;
1143  long timetaken_us = 0;
1144  int timeremain_ms = 0;
1145 
1146  //only guide if tracking
1147  if (TrackState == SCOPE_TRACKING)
1148  {
1149 
1150  // If already moving, then stop movement
1151  if (MovementNSSP.s == IPS_BUSY)
1152  {
1153  int dir = IUFindOnSwitchIndex(&MovementNSSP);
1155  }
1156 
1157  if (GuideNSTID)
1158  {
1160  GuideNSTID = 0;
1161  }
1162 
1163  isPulsingNS = true;
1164  start_pmc8_guide(PortFD, PMC8_S, (int)ms, timetaken_us, 0);
1165 
1166  timeremain_ms = (int)(ms - ((float)timetaken_us) / 1000.0);
1167 
1168  if (timeremain_ms < 0)
1169  timeremain_ms = 0;
1170 
1171  ret = IPS_BUSY;
1172  }
1173  else
1174  {
1175  LOG_INFO("Mount not tracking--cannot guide.");
1176  }
1177  GuideNSTID = IEAddTimer(timeremain_ms, guideTimeoutHelperS, this);
1178  return ret;
1179 }
1180 
1182 {
1183  IPState ret = IPS_IDLE;
1184  long timetaken_us = 0;
1185  int timeremain_ms = 0;
1186 
1187  //only guide if tracking
1188  if (TrackState == SCOPE_TRACKING)
1189  {
1190 
1191  // If already moving (no pulse command), then stop movement
1192  if (MovementWESP.s == IPS_BUSY)
1193  {
1194  int dir = IUFindOnSwitchIndex(&MovementWESP);
1196  }
1197 
1198  if (GuideWETID)
1199  {
1201  GuideWETID = 0;
1202  }
1203 
1204  isPulsingWE = true;
1205 
1206  start_pmc8_guide(PortFD, PMC8_E, (int)ms, timetaken_us, currentTrackRate);
1207 
1208  timeremain_ms = (int)(ms - ((float)timetaken_us) / 1000.0);
1209 
1210  if (timeremain_ms < 0)
1211  timeremain_ms = 0;
1212 
1213  ret = IPS_BUSY;
1214  }
1215  else
1216  {
1217  LOG_INFO("Mount not tracking--cannot guide.");
1218  }
1219  GuideWETID = IEAddTimer(timeremain_ms, guideTimeoutHelperE, this);
1220  return ret;
1221 }
1222 
1224 {
1225  IPState ret = IPS_IDLE;
1226  long timetaken_us = 0;
1227  int timeremain_ms = 0;
1228 
1229  //only guide if tracking
1230  if (TrackState == SCOPE_TRACKING)
1231  {
1232 
1233  // If already moving (no pulse command), then stop movement
1234  if (MovementWESP.s == IPS_BUSY)
1235  {
1236  int dir = IUFindOnSwitchIndex(&MovementWESP);
1238  }
1239 
1240  if (GuideWETID)
1241  {
1243  GuideWETID = 0;
1244  }
1245 
1246  isPulsingWE = true;
1247  start_pmc8_guide(PortFD, PMC8_W, (int)ms, timetaken_us, currentTrackRate);
1248 
1249  timeremain_ms = (int)(ms - ((float)timetaken_us) / 1000.0);
1250 
1251  if (timeremain_ms < 0)
1252  timeremain_ms = 0;
1253 
1254  ret = IPS_BUSY;
1255  }
1256  else
1257  {
1258  LOG_INFO("Mount not tracking--cannot guide.");
1259  }
1260  GuideWETID = IEAddTimer(timeremain_ms, guideTimeoutHelperW, this);
1261  return ret;
1262 }
1263 
1265 {
1266  // end previous pulse command
1267  stop_pmc8_guide(PortFD, calldir);
1268 
1269  if (calldir == PMC8_N || calldir == PMC8_S)
1270  {
1271  isPulsingNS = false;
1272  GuideNSNP.np[0].value = 0;
1273  GuideNSNP.np[1].value = 0;
1274  GuideNSNP.s = IPS_IDLE;
1275  GuideNSTID = 0;
1276  IDSetNumber(&GuideNSNP, nullptr);
1277  }
1278  if (calldir == PMC8_W || calldir == PMC8_E)
1279  {
1280  isPulsingWE = false;
1281  GuideWENP.np[0].value = 0;
1282  GuideWENP.np[1].value = 0;
1283  GuideWENP.s = IPS_IDLE;
1284  GuideWETID = 0;
1285  IDSetNumber(&GuideWENP, nullptr);
1286  }
1287 
1288  LOG_DEBUG("GUIDE CMD COMPLETED");
1289 }
1290 
1291 //GUIDE The timer helper functions.
1293 {
1294  static_cast<PMC8*>(p)->guideTimeout(PMC8_N);
1295 }
1297 {
1298  static_cast<PMC8*>(p)->guideTimeout(PMC8_S);
1299 }
1301 {
1302  static_cast<PMC8*>(p)->guideTimeout(PMC8_W);
1303 }
1305 {
1306  static_cast<PMC8*>(p)->guideTimeout(PMC8_E);
1307 }
1308 
1309 bool PMC8::SetSlewRate(int index)
1310 {
1311 
1312  INDI_UNUSED(index);
1313 
1314  // slew rate is rate for MoveEW/MOVENE commands - not for GOTOs!!!
1315 
1316  // just return true - we will check SlewRateSP when we do actually moves
1317  return true;
1318 }
1319 
1321 {
1323 
1324  IUSaveConfigSwitch(fp, &SerialCableTypeSP);
1325  IUSaveConfigSwitch(fp, &MountTypeSP);
1326  IUSaveConfigNumber(fp, &RampNP);
1327  IUSaveConfigNumber(fp, &LegacyGuideRateNP);
1328  IUSaveConfigSwitch(fp, &PostGotoSP);
1329 
1330  return true;
1331 }
1332 
1334 {
1335  static struct timeval ltv;
1336  struct timeval tv;
1337  double dt, da, dx;
1338  int nlocked;
1339 
1340  /* update elapsed time since last poll, don't presume exactly POLLMS */
1341  gettimeofday(&tv, nullptr);
1342 
1343  if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1344  ltv = tv;
1345 
1346  dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1347  ltv = tv;
1348  da = SLEWRATE * dt;
1349 
1350  /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
1351  switch (TrackState)
1352  {
1353  case SCOPE_IDLE:
1354  currentRA += (TrackRateN[AXIS_RA].value / 3600.0 * dt) / 15.0;
1356  break;
1357 
1358  case SCOPE_TRACKING:
1359  if (TrackModeS[1].s == ISS_ON)
1360  {
1361  currentRA += ( ((TRACKRATE_SIDEREAL / 3600.0) - (TrackRateN[AXIS_RA].value / 3600.0)) * dt) / 15.0;
1362  currentDEC += ( (TrackRateN[AXIS_DE].value / 3600.0) * dt);
1363  }
1364  break;
1365 
1366  case SCOPE_SLEWING:
1367  case SCOPE_PARKING:
1368  /* slewing - nail it when both within one pulse @ SLEWRATE */
1369  nlocked = 0;
1370 
1371  dx = targetRA - currentRA;
1372 
1373  // Take shortest path
1374  if (fabs(dx) > 12)
1375  dx *= -1;
1376 
1377  if (fabs(dx) <= da)
1378  {
1379  currentRA = targetRA;
1380  nlocked++;
1381  }
1382  else if (dx > 0)
1383  currentRA += da / 15.;
1384  else
1385  currentRA -= da / 15.;
1386 
1387  if (currentRA < 0)
1388  currentRA += 24;
1389  else if (currentRA > 24)
1390  currentRA -= 24;
1391 
1392  dx = targetDEC - currentDEC;
1393  if (fabs(dx) <= da)
1394  {
1395  currentDEC = targetDEC;
1396  nlocked++;
1397  }
1398  else if (dx > 0)
1399  currentDEC += da;
1400  else
1401  currentDEC -= da;
1402 
1403  if (nlocked == 2)
1404  {
1405  if (TrackState == SCOPE_SLEWING)
1407  else
1409  }
1410 
1411  break;
1412 
1413  case SCOPE_PARKED:
1414  // setting system status to parked will automatically
1415  // set the simulated RA/DEC to park position so reread
1418 
1419  break;
1420 
1421  default:
1422  break;
1423  }
1424 
1427 }
1428 
1429 #if 0
1430 // PMC8 only parks to motor position (0, 0) currently
1431 bool PMC8::SetCurrentPark()
1432 {
1435 
1436  return true;
1437 }
1438 
1439 bool PMC8::SetDefaultPark()
1440 {
1441  // By default set RA to HA
1442  SetAxis1Park(ln_get_apparent_sidereal_time(ln_get_julian_from_sys()));
1443 
1444  // Set DEC to 90 or -90 depending on the hemisphere
1445  // SetAxis2Park((HemisphereS[HEMI_NORTH].s == ISS_ON) ? 90 : -90);
1446  SetAxis2Park(90);
1447 
1448  return true;
1449 }
1450 #else
1452 {
1453  LOG_ERROR("PPMC8::SetCurrentPark() not implemented!");
1454  return false;
1455 }
1456 
1458 {
1459  LOG_ERROR("PMC8::SetDefaultPark() not implemented!");
1460  return false;
1461 }
1462 #endif
1463 
1464 uint8_t PMC8::convertToPMC8TrackMode(uint8_t mode)
1465 {
1466  switch (mode)
1467  {
1468  case TRACK_SIDEREAL:
1469  return PMC8_TRACK_SIDEREAL;
1470  break;
1471  case TRACK_LUNAR:
1472  return PMC8_TRACK_LUNAR;
1473  break;
1474  case TRACK_SOLAR:
1475  return PMC8_TRACK_SOLAR;
1476  break;
1477  case TRACK_CUSTOM:
1478  return PMC8_TRACK_CUSTOM;
1479  break;
1480  default:
1481  return PMC8_TRACK_UNDEFINED;
1482  }
1483 }
1484 
1485 uint8_t PMC8::convertFromPMC8TrackMode(uint8_t mode)
1486 {
1487  switch (mode)
1488  {
1489  case PMC8_TRACK_SIDEREAL:
1490  return TRACK_SIDEREAL;
1491  break;
1492  case PMC8_TRACK_LUNAR:
1493  return TRACK_LUNAR;
1494  break;
1495  case PMC8_TRACK_SOLAR:
1496  return TRACK_SOLAR;
1497  break;
1498  default:
1499  return TRACK_CUSTOM;
1500  }
1501 }
1502 
1503 bool PMC8::SetTrackMode(uint8_t mode)
1504 {
1505  uint8_t pmc8_mode;
1506 
1507  LOGF_DEBUG("PMC8::SetTrackMode called mode=%d", mode);
1508 
1509  // FIXME - Need to make sure track modes are handled properly!
1510  //PMC8_TRACK_RATE rate = static_cast<PMC8_TRACK_RATE>(mode);
1511  // not sure what needs fixing
1512 
1513  pmc8_mode = convertToPMC8TrackMode(mode);
1514 
1515  if (pmc8_mode == PMC8_TRACK_UNDEFINED)
1516  {
1517  LOGF_ERROR("PMC8::SetTrackMode mode=%d not supported!", mode);
1518  return false;
1519  }
1520 
1521  if (pmc8_mode == PMC8_TRACK_CUSTOM)
1522  {
1524  {
1525  return true;
1526  }
1527  }
1528  else
1529  {
1530  if (set_pmc8_track_mode(PortFD, pmc8_mode))
1531  return true;
1532  }
1533 
1534  return false;
1535 }
1536 
1537 bool PMC8::SetTrackRate(double raRate, double deRate)
1538 {
1539  static bool deRateWarning = true;
1540  double pmc8RARate;
1541 
1542  LOGF_DEBUG("PMC8::SetTrackRate called raRate=%f deRate=%f", raRate, deRate);
1543 
1544  // Convert to arcsecs/s to +/- 0.0100 accepted by
1545  //double pmc8RARate = raRate - TRACKRATE_SIDEREAL;
1546 
1547  // for now just send rate
1548  pmc8RARate = raRate;
1549 
1550  if (deRate != 0 && deRateWarning)
1551  {
1552  // Only send warning once per session
1553  deRateWarning = false;
1554  LOG_WARN("Custom Declination tracking rate is not implemented yet.");
1555  }
1556 
1557  if (set_pmc8_ra_tracking(PortFD, pmc8RARate))
1558  return true;
1559 
1560  LOG_ERROR("PMC8::SetTrackRate not implemented!");
1561  return false;
1562 }
1563 
1564 bool PMC8::SetTrackEnabled(bool enabled)
1565 {
1566 
1567  LOGF_DEBUG("PMC8::SetTrackEnabled called enabled=%d", enabled);
1568 
1569  // need to determine current tracking mode and start tracking
1570  if (enabled)
1571  {
1572 
1574  {
1575  LOG_ERROR("PMC8::SetTrackEnabled - unable to enable tracking");
1576  return false;
1577  }
1578  }
1579  else
1580  {
1581  bool rc;
1582 
1584  if (!rc)
1585  {
1586  LOG_ERROR("PMC8::SetTrackEnabled - unable to set RA track rate to 0");
1587  return false;
1588  }
1589 
1590  // currently only support tracking rate in RA
1591  // rc=set_pmc8_custom_dec_track_rate(PortFD, 0);
1592  // if (!rc)
1593  // {
1594  // LOG_ERROR("PMC8::SetTrackREnabled - unable to set DEC track rate to 0");
1595  // return false;
1596  // }
1597  }
1598 
1599  return true;
1600 }
1601 
INDI::Telescope::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: inditelescope.cpp:816
get_pmc8_is_scope_slewing
bool get_pmc8_is_scope_slewing(int fd, bool &isslew)
Definition: pmc8driver.cpp:700
DIRECTION_NORTH
@ DIRECTION_NORTH
Definition: indibasetypes.h:45
DIRECTION_SOUTH
@ DIRECTION_SOUTH
Definition: indibasetypes.h:46
INDI::Telescope::TELESCOPE_CAN_PARK
@ TELESCOPE_CAN_PARK
Definition: inditelescope.h:161
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::Telescope::SCOPE_IDLE
@ SCOPE_IDLE
Definition: inditelescope.h:75
pmc8.h
PMC8::SetTrackRate
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
Definition: pmc8.cpp:1537
INDI::Telescope::TELESCOPE_HAS_TRACK_RATE
@ TELESCOPE_HAS_TRACK_RATE
Definition: inditelescope.h:169
PMC8_MOVE_INACTIVE
@ PMC8_MOVE_INACTIVE
Definition: pmc8.h:32
INDI::Telescope::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: inditelescope.cpp:658
ST_TRACKING
@ ST_TRACKING
Definition: pmc8driver.h:44
set_pmc8_device
void set_pmc8_device(const char *name)
Definition: pmc8driver.cpp:235
PMC8::ramp_movement
bool ramp_movement(PMC8_DIRECTION calldir)
Definition: pmc8.cpp:863
abort_pmc8
bool abort_pmc8(int fd)
Definition: pmc8driver.cpp:1846
PMC8_SERIAL_STANDARD
@ PMC8_SERIAL_STANDARD
Definition: pmc8driver.h:63
INDI::DefaultDevice::addAuxControls
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
Definition: defaultdevice.cpp:665
INDI::Logger::getInstance
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
Definition: indilogger.cpp:354
IPState
IPState
Property state.
Definition: indiapi.h:158
INDI::Telescope::initProperties
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: inditelescope.cpp:82
INDI::Telescope::LocationN
INumber LocationN[3]
Definition: inditelescope.h:719
INDI::Telescope::SCOPE_SLEWING
@ SCOPE_SLEWING
Definition: inditelescope.h:76
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
INDI::Telescope::SCOPE_PARKING
@ SCOPE_PARKING
Definition: inditelescope.h:78
INDI::DefaultDevice::setConnected
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
Definition: defaultdevice.cpp:847
PMC8::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: pmc8.cpp:784
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
PMC8::ReadScopeStatus
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: pmc8.cpp:435
set_pmc8_custom_ra_track_rate
bool set_pmc8_custom_ra_track_rate(int fd, double rate)
Definition: pmc8driver.cpp:1019
PMC8::guideTimeoutHelperW
static void guideTimeoutHelperW(void *p)
Definition: pmc8.cpp:1300
PMC8::SetDefaultPark
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: pmc8.cpp:1457
PMC8_DIRECTION
PMC8_DIRECTION
Definition: pmc8driver.h:59
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
MOTION_TAB
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
Definition: defaultdevice.cpp:36
connectiontcp.h
stop_pmc8_tracking_motion
bool stop_pmc8_tracking_motion(int fd)
Definition: pmc8driver.cpp:759
INDI::BaseDevice::GUIDER_INTERFACE
@ GUIDER_INTERFACE
Definition: basedevice.h:74
PMC8::GuideNSTID
int GuideNSTID
Definition: pmc8.h:122
INDI_DIR_NS
INDI_DIR_NS
Definition: indibasetypes.h:44
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
FirmwareInfo::IsRev2Compliant
bool IsRev2Compliant
Definition: pmc8driver.h:77
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
INDI::Telescope::MovementNSSP
ISwitchVectorProperty MovementNSSP
Definition: inditelescope.h:742
PMC8_N
@ PMC8_N
Definition: pmc8driver.h:59
INDI::GuiderInterface::GuideWENP
INumberVectorProperty GuideWENP
Definition: indiguiderinterface.h:113
set_pmc8_sim_system_status
void set_pmc8_sim_system_status(PMC8_SYSTEM_STATUS value)
Definition: pmc8driver.cpp:250
INDI::Telescope::NewRaDec
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
Definition: inditelescope.cpp:693
INDI::DefaultDevice::isSimulation
bool isSimulation() const
Definition: defaultdevice.cpp:734
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
DIRECTION_EAST
@ DIRECTION_EAST
Definition: indibasetypes.h:52
PMC8::getDefaultName
virtual const char * getDefaultName() override
Definition: pmc8.cpp:74
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
PMC8_S
@ PMC8_S
Definition: pmc8driver.h:59
INDI_DIR_WE
INDI_DIR_WE
Definition: indibasetypes.h:50
INDI::Telescope::TrackModeS
ISwitch * TrackModeS
Definition: inditelescope.h:843
Connection::Serial::B_115200
@ B_115200
Definition: connectionserial.h:82
PMC8::guideTimeoutHelperS
static void guideTimeoutHelperS(void *p)
Definition: pmc8.cpp:1296
PMC8_TRACK_CUSTOM
@ PMC8_TRACK_CUSTOM
Definition: pmc8driver.h:54
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
round
double round(double value, int decimal_places)
Definition: test_alignment.cpp:32
PMC8::guideTimeoutHelperN
static void guideTimeoutHelperN(void *p)
Definition: pmc8.cpp:1292
INDI::Telescope::GetAxis1Park
double GetAxis1Park() const
Definition: inditelescope.cpp:2252
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::Telescope::SetAxis2Park
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:2283
INDI::Telescope::SetAxis1ParkDefault
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
Definition: inditelescope.cpp:2277
get_pmc8_tracking_data
bool get_pmc8_tracking_data(int fd, double &rate, uint8_t &mode)
Definition: pmc8driver.cpp:822
set_pmc8_goto_resume
void set_pmc8_goto_resume(bool resume)
Definition: pmc8driver.cpp:2201
LOGF_EXTRA3
#define LOGF_EXTRA3(fmt,...)
Definition: indilogger.h:86
GUIDE_TAB
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
Definition: defaultdevice.cpp:42
PMC8::updateProperties
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: pmc8.cpp:166
INDI::Telescope::InitPark
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Definition: inditelescope.cpp:1950
INDI::Telescope::TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_HAS_TRACK_MODE
Definition: inditelescope.h:167
stop_pmc8_guide
bool stop_pmc8_guide(int fd, PMC8_DIRECTION gdir)
Definition: pmc8driver.cpp:1438
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
FirmwareInfo::MainBoardFirmware
std::string MainBoardFirmware
Definition: ieqprolegacydriver.h:59
set_pmc8_radec
bool set_pmc8_radec(int fd, double ra, double dec)
Definition: pmc8driver.cpp:1987
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
set_pmc8_mountParameters
void set_pmc8_mountParameters(int index)
Definition: pmc8driver.cpp:201
PMC8_MOVE_RAMPING
@ PMC8_MOVE_RAMPING
Definition: pmc8.h:32
set_pmc8_track_mode
bool set_pmc8_track_mode(int fd, uint8_t mode)
Definition: pmc8driver.cpp:979
PMC8::UnPark
virtual bool UnPark() override
Unpark the telescope if already parked.
Definition: pmc8.cpp:770
INDI::Logger::DBG_SESSION
@ DBG_SESSION
Definition: indilogger.h:194
set_pmc8_guide_rate
bool set_pmc8_guide_rate(int fd, PMC8_AXIS axis, double rate)
Definition: pmc8driver.cpp:1142
range24
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition: indicom.c:1485
INDI::GuiderInterface::initGuiderProperties
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
Definition: indiguiderinterface.cpp:36
PMC8_DEFAULT_PORT
#define PMC8_DEFAULT_PORT
Definition: pmc8.cpp:48
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::Telescope::EqNP
INumberVectorProperty EqNP
Definition: inditelescope.h:701
PMC8MoveInfo::targetRate
int targetRate
Definition: pmc8.h:39
INDI::Telescope::tcpConnection
Connection::TCP * tcpConnection
Definition: inditelescope.h:866
PMC8::SetTrackEnabled
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
Definition: pmc8.cpp:1564
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
unpark_pmc8
bool unpark_pmc8(int fd)
Definition: pmc8driver.cpp:1827
DEBUG
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
PMC8::MoveWE
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
Definition: pmc8.cpp:1029
INDI::Telescope::TrackRateN
INumber TrackRateN[2]
Definition: inditelescope.h:851
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
INDI::Telescope::TrackState
TelescopeStatus TrackState
Definition: inditelescope.h:693
INDI::Telescope::isParked
bool isParked()
isParked is mount currently parked?
Definition: inditelescope.cpp:1945
PMC8MoveInfo::rampIteration
int rampIteration
Definition: pmc8.h:40
INDI::Logger::DBG_DEBUG
@ DBG_DEBUG
Definition: indilogger.h:195
PMC8_TRACK_LUNAR
@ PMC8_TRACK_LUNAR
Definition: pmc8driver.h:54
PMC8_E
@ PMC8_E
Definition: pmc8driver.h:59
PMC8::rampTimeoutHelperE
static void rampTimeoutHelperE(void *p)
Definition: pmc8.cpp:950
PMC8_CONNECTION_TYPE
PMC8_CONNECTION_TYPE
Definition: pmc8driver.h:63
INDI::GuiderInterface::GuideNSNP
INumberVectorProperty GuideNSNP
Definition: indiguiderinterface.h:111
set_pmc8_move_rate_axis
bool set_pmc8_move_rate_axis(int fd, PMC8_DIRECTION dir, int reqrate)
Definition: pmc8driver.cpp:733
start_pmc8_guide
bool start_pmc8_guide(int fd, PMC8_DIRECTION gdir, int ms, long &timetaken_us, double ratehint)
Definition: pmc8driver.cpp:1279
IEAddTimer
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition: eventloop.c:525
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
INDI::Telescope::TELESCOPE_HAS_LOCATION
@ TELESCOPE_HAS_LOCATION
Definition: inditelescope.h:164
PMC8::guideTimeoutHelperE
static void guideTimeoutHelperE(void *p)
Definition: pmc8.cpp:1304
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
MOUNT_EXOS2
@ MOUNT_EXOS2
Definition: pmc8driver.h:61
PMC8::guideTimeout
void guideTimeout(PMC8_DIRECTION calldir)
Definition: pmc8.cpp:1264
PMC8::rampTimeoutHelperN
static void rampTimeoutHelperN(void *p)
Definition: pmc8.cpp:932
PMC8_TRACK_SOLAR
@ PMC8_TRACK_SOLAR
Definition: pmc8driver.h:54
park_pmc8
bool park_pmc8(int fd)
Definition: pmc8driver.cpp:1814
ra
double ra
Definition: ieqprolegacydriver.cpp:43
INDI::Telescope::TRACK_SIDEREAL
@ TRACK_SIDEREAL
Definition: inditelescope.h:95
get_pmc8_guide_rate
bool get_pmc8_guide_rate(int fd, PMC8_AXIS axis, double &rate)
Definition: pmc8driver.cpp:1194
PMC8_MAX_MOVE_RATE
#define PMC8_MAX_MOVE_RATE
Definition: pmc8driver.h:39
PMC8::simulationTriggered
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
Definition: pmc8.cpp:850
set_pmc8_debug
void set_pmc8_debug(bool enable)
Definition: pmc8driver.cpp:223
INDI::DefaultDevice::Connect
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: defaultdevice.cpp:1058
INDI::Telescope::TrackModeSP
ISwitchVectorProperty TrackModeSP
Definition: inditelescope.h:842
INDI::DefaultDevice::getDriverInterface
virtual uint16_t getDriverInterface() override
Definition: defaultdevice.cpp:896
PMC8_AXIS_RA
@ PMC8_AXIS_RA
Definition: pmc8driver.h:58
INDI::Telescope::TelescopeMotionCommand
TelescopeMotionCommand
Definition: inditelescope.h:81
set_sim_system_status
void set_sim_system_status(IEQ_SYSTEM_STATUS value)
Definition: ieqprolegacydriver.cpp:74
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
set_pmc8_sim_track_rate
void set_pmc8_sim_track_rate(PMC8_TRACK_RATE value)
Definition: pmc8driver.cpp:270
get_pmc8_coords
bool get_pmc8_coords(int fd, double &ra, double &dec)
Definition: pmc8driver.cpp:2033
INDI::Telescope::SetTelescopeCapability
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount=0)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
Definition: inditelescope.cpp:1818
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
PMC8::GuideWest
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
Definition: pmc8.cpp:1223
connectionserial.h
_INumberVectorProperty::np
INumber * np
Definition: indiapi.h:334
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::Telescope::TELESCOPE_CAN_ABORT
@ TELESCOPE_CAN_ABORT
Definition: inditelescope.h:162
Connection::CONNECTION_TAB
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
Definition: connectioninterface.cpp:41
FirmwareInfo::MountType
PMC8_MOUNT_TYPES MountType
Definition: pmc8driver.h:76
INDI::Telescope::MOTION_START
@ MOTION_START
Definition: inditelescope.h:83
INDI::Telescope::TrackRateNP
INumberVectorProperty TrackRateNP
Definition: inditelescope.h:850
dec
double dec
Definition: ieqprolegacydriver.cpp:44
INDI::Telescope::MovementWESP
ISwitchVectorProperty MovementWESP
Definition: inditelescope.h:746
set_pmc8_simulation
void set_pmc8_simulation(bool enable)
Definition: pmc8driver.cpp:228
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::Telescope::TELESCOPE_CAN_CONTROL_TRACK
@ TELESCOPE_CAN_CONTROL_TRACK
Definition: inditelescope.h:168
get_pmc8_firmware
bool get_pmc8_firmware(int fd, FirmwareInfo *info)
Definition: pmc8driver.cpp:526
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
PMC8::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: pmc8.cpp:340
PMC8::~PMC8
~PMC8() override
Definition: pmc8.cpp:70
PMC8::SetTrackMode
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
Definition: pmc8.cpp:1503
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::Telescope::SetAxis1Park
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:2269
MOUNT_iEXOS100
@ MOUNT_iEXOS100
Definition: pmc8driver.h:61
INDI::Telescope::ParkOptionSP
ISwitchVectorProperty ParkOptionSP
Definition: inditelescope.h:731
PMC8::Abort
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
Definition: pmc8.cpp:686
PMC8_SERIAL_AUTO
@ PMC8_SERIAL_AUTO
Definition: pmc8driver.h:63
get_pmc8_reconnect_flag
bool get_pmc8_reconnect_flag()
Definition: pmc8driver.cpp:2191
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
PMC8::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: pmc8.cpp:398
INDI::Telescope::PARK_NONE
@ PARK_NONE
Definition: inditelescope.h:108
INDI::Telescope::SCOPE_TRACKING
@ SCOPE_TRACKING
Definition: inditelescope.h:77
PMC8::rampTimeoutHelperW
static void rampTimeoutHelperW(void *p)
Definition: pmc8.cpp:944
PMC8::updateLocation
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
Definition: pmc8.cpp:819
INDI::Telescope::LOCATION_LATITUDE
@ LOCATION_LATITUDE
Definition: inditelescope.h:117
INDI::Telescope::TrackStateSP
ISwitchVectorProperty TrackStateSP
Definition: inditelescope.h:846
LOG_DEBUG
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
INDI::Telescope::SCOPE_PARKED
@ SCOPE_PARKED
Definition: inditelescope.h:79
INDI::GuiderInterface::GuideWEN
INumber GuideWEN[2]
Definition: indiguiderinterface.h:112
set_pmc8_sim_dec
void set_pmc8_sim_dec(double dec)
Definition: pmc8driver.cpp:285
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
INDI::Telescope::serialConnection
Connection::Serial * serialConnection
Definition: inditelescope.h:865
PMC8_SERIAL_INVERTED
@ PMC8_SERIAL_INVERTED
Definition: pmc8driver.h:63
INDI::Telescope::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: inditelescope.cpp:320
PMC8::updateTime
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
Definition: pmc8.cpp:808
INDI::Telescope::TRACK_CUSTOM
@ TRACK_CUSTOM
Definition: inditelescope.h:98
PMC8::GuideSouth
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
Definition: pmc8.cpp:1140
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::Telescope::SetParkDataType
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
Definition: inditelescope.cpp:1873
set_pmc8_ra_tracking
bool set_pmc8_ra_tracking(int fd, double rate)
Definition: pmc8driver.cpp:1007
check_pmc8_connection
bool check_pmc8_connection(int fd, PMC8_CONNECTION_TYPE connection)
Definition: pmc8driver.cpp:290
INDI::Telescope::SetAxis2ParkDefault
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
Definition: inditelescope.cpp:2291
INDI::Telescope::TELESCOPE_CAN_GOTO
@ TELESCOPE_CAN_GOTO
Definition: inditelescope.h:159
PMC8_TRACKING_AUTODETECT_INTERVAL
#define PMC8_TRACKING_AUTODETECT_INTERVAL
Definition: pmc8.cpp:50
PMC8_AXIS_DEC
@ PMC8_AXIS_DEC
Definition: pmc8driver.h:58
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
PMC8_W
@ PMC8_W
Definition: pmc8driver.h:59
INDI::Telescope::TELESCOPE_CAN_SYNC
@ TELESCOPE_CAN_SYNC
Definition: inditelescope.h:160
name
const char * name
Definition: indiserver.c:116
SLEWRATE
#define SLEWRATE
Definition: pmc8.cpp:44
INDI::Telescope::SetParked
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:1937
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
PMC8_RAMP_UP
@ PMC8_RAMP_UP
Definition: pmc8.h:33
PMC8MoveInfo::state
PMC8_MOVE_STATE state
Definition: pmc8.h:37
INDI::Telescope::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: inditelescope.cpp:1029
Connection::TCP::setDefaultHost
void setDefaultHost(const char *addressHost)
Definition: connectiontcp.cpp:395
PMC8::debugTriggered
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
Definition: pmc8.cpp:845
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
PMC8::Sync
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition: pmc8.cpp:659
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
INDI::Telescope::SlewRateSP
ISwitchVectorProperty SlewRateSP
Definition: inditelescope.h:749
PMC8::PMC8
PMC8()
Definition: pmc8.cpp:55
PMC8::SetCurrentPark
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: pmc8.cpp:1451
Connection::TCP::setDefaultPort
void setDefaultPort(uint32_t addressPort)
Definition: connectiontcp.cpp:406
AXIS_RA
@ AXIS_RA
Definition: indibasetypes.h:33
PMC8_MAX_TRACK_RATE
#define PMC8_MAX_TRACK_RATE
Definition: pmc8driver.h:36
INDI::Logger::addDebugLevel
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
Definition: indilogger.cpp:87
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
DIRECTION_WEST
@ DIRECTION_WEST
Definition: indibasetypes.h:51
PMC8_RAMP_DOWN
@ PMC8_RAMP_DOWN
Definition: pmc8.h:33
INDI::Telescope::LOCATION_LONGITUDE
@ LOCATION_LONGITUDE
Definition: inditelescope.h:118
iEQ::ST_PARKED
@ ST_PARKED
Definition: ieqdriverbase.h:38
slew_pmc8
bool slew_pmc8(int fd, double ra, double dec)
Definition: pmc8driver.cpp:1878
TRACKRATE_SIDEREAL
#define TRACKRATE_SIDEREAL
Definition: indicom.h:54
DEBUGF
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
currentRA
#define currentRA
Definition: ieq45.cpp:47
fs_sexa
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string.
Definition: indicom.c:137
set_pmc8_location
void set_pmc8_location(double latitude, double longitude)
Definition: pmc8driver.cpp:240
PMC8MoveInfo
Definition: pmc8.h:35
PMC8::Goto
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
Definition: pmc8.cpp:614
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
INDI::Telescope::MOTION_STOP
@ MOTION_STOP
Definition: inditelescope.h:84
PMC8::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: pmc8.cpp:390
set_pmc8_sim_move_rate
void set_pmc8_sim_move_rate(int value)
Definition: pmc8driver.cpp:275
PMC8MoveInfo::timer
int timer
Definition: pmc8.h:43
PMC8_DEFAULT_IP_ADDRESS
#define PMC8_DEFAULT_IP_ADDRESS
Definition: pmc8.cpp:49
INDI::Telescope::RememberTrackState
TelescopeStatus RememberTrackState
RememberTrackState Remember last state of Track State to fall back to in case of errors or aborts.
Definition: inditelescope.h:698
INDI::Telescope::AddTrackMode
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
Definition: inditelescope.cpp:1676
INDI::Telescope::ParkPositionNP
INumberVectorProperty ParkPositionNP
Definition: inditelescope.h:727
PMC8::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: pmc8.cpp:1320
PMC8::Park
virtual bool Park() override
Park the telescope to its home position.
Definition: pmc8.cpp:739
ISState
ISState
Switch state.
Definition: indiapi.h:148
INDI::Telescope::TRACK_SOLAR
@ TRACK_SOLAR
Definition: inditelescope.h:96
PMC8::GuideWETID
int GuideWETID
Definition: pmc8.h:123
INDI::Telescope::PortFD
int PortFD
Definition: inditelescope.h:864
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
PMC8::GuideNorth
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
Definition: pmc8.cpp:1099
_ISwitchVectorProperty::sp
ISwitch * sp
Definition: indiapi.h:384
INDI::Telescope::updateProperties
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: inditelescope.cpp:356
INDI::Telescope::GetAxis2Park
double GetAxis2Park() const
Definition: inditelescope.cpp:2260
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1465
INDI::DefaultDevice::Disconnect
virtual bool Disconnect()
Disconnect from device.
Definition: defaultdevice.cpp:1083
PMC8::MoveNS
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
Definition: pmc8.cpp:958
set_pmc8_sim_ra
void set_pmc8_sim_ra(double ra)
Definition: pmc8driver.cpp:280
PMC8_TRACK_UNDEFINED
@ PMC8_TRACK_UNDEFINED
Definition: pmc8driver.h:54
INDI::GuiderInterface::GuideNSN
INumber GuideNSN[2]
Definition: indiguiderinterface.h:110
PMC8::getSlewRate
int getSlewRate()
Definition: pmc8.cpp:855
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
PMC8MoveInfo::moveDir
uint8_t moveDir
Definition: pmc8.h:38
INDI::Telescope::TRACK_LUNAR
@ TRACK_LUNAR
Definition: inditelescope.h:97
PMC8_TRACK_SIDEREAL
@ PMC8_TRACK_SIDEREAL
Definition: pmc8driver.h:54
PMC8
Definition: pmc8.h:47
PMC8_MOVE_ACTIVE
@ PMC8_MOVE_ACTIVE
Definition: pmc8.h:32
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.
PMC8MoveInfo::rampDir
PMC8_RAMP_DIRECTION rampDir
Definition: pmc8.h:42
INDI::DefaultDevice::setDriverInterface
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
Definition: defaultdevice.cpp:902
MOUNT_G11
@ MOUNT_G11
Definition: pmc8driver.h:61
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
sync_pmc8
bool sync_pmc8(int fd, double ra, double dec)
Definition: pmc8driver.cpp:1941
AXIS_DE
@ AXIS_DE
Definition: indibasetypes.h:34
currentDEC
#define currentDEC
Definition: ieq45.cpp:48
PMC8MoveInfo::rampLastStep
int rampLastStep
Definition: pmc8.h:41
IERmTimer
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer() or IEAddPeriodicTimer().
Definition: eventloop.c:545
INDI::GuiderInterface::processGuiderProperties
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
Definition: indiguiderinterface.cpp:49
PMC8::SetSlewRate
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
Definition: pmc8.cpp:1309
PMC8::initProperties
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: pmc8.cpp:79
INDI::DefaultDevice::getActiveConnection
Connection::Interface * getActiveConnection()
Definition: defaultdevice.cpp:1245
PMC8_ETHERNET
@ PMC8_ETHERNET
Definition: pmc8driver.h:63
PMC8::mountSim
void mountSim()
Definition: pmc8.cpp:1333
PMC8::GuideEast
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
Definition: pmc8.cpp:1181
PMC8::rampTimeoutHelperS
static void rampTimeoutHelperS(void *p)
Definition: pmc8.cpp:938
iEQ::ST_STOPPED
@ ST_STOPPED
Definition: ieqdriverbase.h:32
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151