40 #include <libnova/sidereal_time.h>
41 #include <libnova/transform.h>
53 #define FINE_SLEW_RATE 0.1
55 #define GOTO_LIMIT 5.5
58 #define PARAMOUNT_TIMEOUT 3
59 #define PARAMOUNT_NORTH 0
60 #define PARAMOUNT_SOUTH 1
61 #define PARAMOUNT_EAST 2
62 #define PARAMOUNT_WEST 3
122 IUFillNumber(&JogRateN[
RA_AXIS],
"JOG_RATE_WE",
"W/E Rate (arcmin)",
"%g", 0, 600, 60, 30);
128 IUFillNumber(&GuideRateN[
RA_AXIS],
"GUIDE_RATE_WE",
"W/E Rate",
"%1.1f", 0.0, 1.0, 0.1, 0.5);
135 IUFillSwitchVector(&HomeSP, HomeS, 1,
getDeviceName(),
"TELESCOPE_HOME",
"Homing",
MAIN_CONTROL_TAB,
IP_RW,
ISR_ATMOST1, 60,
170 if (isTheSkyTracking())
244 int rc = 0, nbytes_written = 0, nbytes_read = 0;
250 "sky6RASCOMTele.ConnectAndDoNotUnpark();"
251 "Out = sky6RASCOMTele.IsConnected + '#';",
258 LOGF_ERROR(
"Error writing Handshake to TheSkyX TCP server. Result: %d", rc);
264 LOGF_ERROR(
"Error reading Handshake from TheSkyX TCP server. Result: %d", rc);
268 if (strcmp(pRES,
"1#") != 0)
270 LOGF_ERROR(
"Error connecting to TheSky. Result: %s", pRES);
277 bool Paramount::getMountRADE()
279 int rc = 0, nbytes_written = 0, nbytes_read = 0;
281 double SkyXRA = 0., SkyXDEC = 0.;
286 "sky6RASCOMTele.GetRaDec();"
287 "Out = String(sky6RASCOMTele.dRa) + ',' + String(sky6RASCOMTele.dDec) + '#';",
294 LOGF_ERROR(
"Error writing GetRaDec to TheSkyX TCP server. Response: %d", rc);
300 LOGF_ERROR(
"Error reading GetRaDec from TheSkyX TCP server. Result: %d", rc);
307 if (sscanf(pRES,
"|No error. Error = 0.%lf,%lf#", &SkyXRA, &SkyXDEC) == 2)
310 currentDEC = SkyXDEC;
314 LOGF_ERROR(
"Error reading coordinates. Result: %s", pRES);
320 int rc = 0, nbytes_written = 0, nbytes_read = 0;
322 int SkyXPierSide = -1;
327 "sky6RASCOMTele.DoCommand(11, \"Pier Side\");"
328 "Out = sky6RASCOMTele.DoCommandOutput + '#';",
335 LOGF_ERROR(
"Error writing DoCommand(Pier Side) to TheSkyX TCP server. Result: %d", rc);
341 LOGF_ERROR(
"Error reading Pier Side from TheSkyX TCP server. Result: %d", rc);
347 if (sscanf(pRES,
"|No error. Error = 0.%d#", &SkyXPierSide) == 1)
352 LOGF_ERROR(
"Error reading Pier Side. Result: %s", pRES);
367 if (isSlewComplete())
375 LOG_INFO(
"Finding home completed.");
378 LOG_INFO(
"Slew is complete. Tracking...");
383 if (isTheSkyParked())
392 char RAStr[64], DecStr[64];
394 fs_sexa(RAStr, currentRA, 2, 3600);
395 fs_sexa(DecStr, currentDEC, 2, 3600);
397 DEBUGF(DBG_SCOPE,
"Current RA: %s Current DEC: %s", RAStr, DecStr);
409 char RAStr[64], DecStr[64];
411 fs_sexa(RAStr, targetRA, 2, 3600);
412 fs_sexa(DecStr, targetDEC, 2, 3600);
416 "sky6RASCOMTele.Asynchronous = true;"
417 "sky6RASCOMTele.SlewToRaDec(%g, %g,'');",
418 targetRA, targetDEC);
420 if (!sendTheSkyOKCommand(pCMD,
"Slewing to target"))
425 LOGF_INFO(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
429 bool Paramount::isSlewComplete()
431 int rc = 0, nbytes_written = 0, nbytes_read = 0;
437 "Out = sky6RASCOMTele.IsSlewComplete + '#';",
444 LOGF_ERROR(
"Error writing IsSlewComplete to TheSkyX TCP server. Result: %d", rc);
450 LOGF_ERROR(
"Error reading IsSlewComplete from TheSkyX TCP server. Result: %d", rc);
457 if (sscanf(pRES,
"|No error. Error = 0.%d#", &isComplete) == 1)
459 return isComplete == 1 ? 1 : 0;
462 LOGF_ERROR(
"Error reading isSlewComplete. Result: %s", pRES);
466 bool Paramount::isTheSkyParked()
468 int rc = 0, nbytes_written = 0, nbytes_read = 0;
474 "Out = sky6RASCOMTele.IsParked() + '#';",
481 LOGF_ERROR(
"Error writing sky6RASCOMTele.IsParked() to TheSkyX TCP server. Result: %d", rc);
487 LOGF_ERROR(
"Error reading sky6RASCOMTele.IsParked() from TheSkyX TCP server. Result: %d", rc);
493 if (strcmp(pRES,
"|No error. Error = 0.true#") == 0)
495 if (strcmp(pRES,
"|No error. Error = 0.false#") == 0)
498 LOGF_ERROR(
"Error checking for park. Invalid response: %s", pRES);
502 bool Paramount::isTheSkyTracking()
504 int rc = 0, nbytes_written = 0, nbytes_read = 0;
510 "Out = sky6RASCOMTele.IsTracking + '#';",
517 LOGF_ERROR(
"Error writing sky6RASCOMTele.IsTracking to TheSkyX TCP server. Result: %d", rc);
523 LOGF_ERROR(
"Error reading sky6RASCOMTele.IsTracking from TheSkyX TCP server. Result: %d", rc);
529 double SkyXTrackRate = 0.;
530 if (sscanf(pRES,
"|No error. Error = 0.%lf#", &SkyXTrackRate) == 1)
532 if (SkyXTrackRate == 0)
534 else if (SkyXTrackRate > 0)
538 LOGF_ERROR(
"Error checking for tracking. Invalid response: %s", pRES);
546 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.Sync(%g, %g,'');", targetRA, targetDEC);
547 if (!sendTheSkyOKCommand(pCMD,
"Syncing to target"))
570 "sky6RASCOMTele.Asynchronous = true;"
571 "sky6RASCOMTele.ParkAndDoNotDisconnect();",
574 if (!sendTheSkyOKCommand(pCMD,
"Parking mount"))
577 LOG_INFO(
"Parking telescope in progress...");
585 strncpy(pCMD,
"sky6RASCOMTele.Unpark();",
MAXRBUF);
586 if (!sendTheSkyOKCommand(pCMD,
"Unparking mount"))
590 if (isTheSkyParked())
591 LOG_ERROR(
"Could not unpark for some reason.");
603 if (strcmp(name,
"JOG_RATE") == 0)
612 if (strcmp(name, GuideRateNP.
name) == 0)
635 if (!strcmp(HomeSP.
name, name))
637 LOG_INFO(
"Moving to home position. Please stand by...");
643 LOG_INFO(
"Mount arrived at home position.");
649 LOG_ERROR(
"Failed to go to home position");
664 strncpy(pCMD,
"sky6RASCOMTele.Abort();",
MAXRBUF);
665 return sendTheSkyOKCommand(pCMD,
"Abort mount slew");
668 bool Paramount::findHome()
672 strncpy(pCMD,
"sky6RASCOMTele.FindHome();"
673 "while(!sky6RASCOMTele.IsSlewComplete) {"
674 "sky6Web.Sleep(1000);}",
676 return sendTheSkyOKCommand(pCMD,
"Find home", 60);
684 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
695 if (!
isSimulation() && !startOpenLoopMotion(motion, rate))
697 LOG_ERROR(
"Error setting N/S motion direction.");
723 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
733 if (!
isSimulation() && !startOpenLoopMotion(motion, rate))
735 LOG_ERROR(
"Error setting W/E motion direction.");
757 bool Paramount::startOpenLoopMotion(uint8_t motion, uint16_t rate)
761 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.DoCommand(9,'%d|%d');", motion, rate);
762 return sendTheSkyOKCommand(pCMD,
"Starting open loop motion");
765 bool Paramount::stopOpenLoopMotion()
769 strncpy(pCMD,
"sky6RASCOMTele.DoCommand(10,'');",
MAXRBUF);
770 return sendTheSkyOKCommand(pCMD,
"Stopping open loop motion");
784 strncpy(pCMD,
"sky6RASCOMTele.SetParkPosition();",
MAXRBUF);
785 if (!sendTheSkyOKCommand(pCMD,
"Setting Park Position"))
812 LOG_ERROR(
"Setting custom parking position directly is not supported. Slew to the desired "
813 "parking position and click Current.");
817 void Paramount::mountSim()
819 static struct timeval ltv
827 double dt, dx, da_ra = 0, da_dec = 0;
831 gettimeofday(&tv,
nullptr);
833 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
836 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
839 if (fabs(targetRA - currentRA) * 15. >=
GOTO_LIMIT)
841 else if (fabs(targetRA - currentRA) * 15. >=
SLEW_LIMIT)
846 if (fabs(targetDEC - currentDEC) >=
GOTO_LIMIT)
848 else if (fabs(targetDEC - currentDEC) >=
SLEW_LIMIT)
853 double motionRate = 0;
856 motionRate = JogRateN[0].value;
858 motionRate = JogRateN[1].value;
862 da_ra = motionRate * dt * 0.05;
863 da_dec = motionRate * dt * 0.05;
869 currentDEC += da_dec;
871 currentDEC -= da_dec;
882 currentRA += da_ra / 15.;
884 currentRA -= da_ra / 15.;
908 dx = targetRA - currentRA;
914 if (fabs(dx) <= da_ra)
926 else if (currentRA > 24)
929 dx = targetDEC - currentDEC;
930 if (fabs(dx) <= da_dec)
956 bool Paramount::sendTheSkyOKCommand(
const char *command,
const char *errorMessage, uint8_t timeout)
958 int rc = 0, nbytes_written = 0, nbytes_read = 0;
967 "catch (err) {Out = err; }",
972 tcflush(
PortFD, TCIOFLUSH);
976 LOGF_ERROR(
"Error writing sendTheSkyOKCommand to TheSkyX TCP server. Result: $%d", rc);
982 LOGF_ERROR(
"Error reading sendTheSkyOKCommand from TheSkyX TCP server. Result: %d", rc);
988 tcflush(
PortFD, TCIOFLUSH);
990 if (strcmp(
"|No error. Error = 0.OK#", pRES) == 0 )
994 LOGF_ERROR(
"sendTheSkyOKCommand Error %s - Invalid response: %s", errorMessage, pRES);
1001 return GuideNS(
static_cast<int>(ms));
1006 return GuideNS(-
static_cast<int>(ms));
1011 return GuideWE(
static_cast<int>(ms));
1016 return GuideWE(-
static_cast<int>(ms));
1023 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1032 "sky6RASCOMTele.Asynchronous = true;"
1033 "sky6DirectGuide.MoveTelescope(%g, %g);", 0., dDec);
1035 if (!sendTheSkyOKCommand(pCMD,
"Guide North-South"))
1038 m_NSTimer.
start(ms);
1047 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1056 "sky6RASCOMTele.Asynchronous = true;"
1057 "sky6DirectGuide.MoveTelescope(%g, %g);", dRA, 0.);
1059 if (!sendTheSkyOKCommand(pCMD,
"Guide West-East"))
1062 m_WETimer.
start(ms);
1067 bool Paramount::setTheSkyTracking(
bool enable,
bool isSidereal,
double raRate,
double deRate)
1069 int on = enable ? 1 : 0;
1070 int ignore = isSidereal ? 1 : 0;
1073 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.SetTracking(%d, %d, %g, %g);", on, ignore, raRate, deRate);
1074 return sendTheSkyOKCommand(pCMD,
"Setting tracking rate");
1079 return setTheSkyTracking(
true,
false, raRate, deRate);
1085 double dRA = 0, dDE = 0;
1096 return setTheSkyTracking(
true, isSidereal, dRA, dDE);
1106 return setTheSkyTracking(0, 0, 0., 0.);
const char * getDeviceName() const
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)
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
uint16_t getDriverInterface() const
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
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....
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
void setTelescopeConnection(const uint8_t &value)
setTelescopeConnection Set telescope connection mode. Child class should call this in the constructor...
double GetAxis2Park() const
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
ISwitchVectorProperty SlewRateSP
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
@ TELESCOPE_HAS_TRACK_RATE
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
INumber ScopeParametersN[4]
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
ISwitchVectorProperty MovementWESP
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
void setSingleShot(bool singleShot)
Set whether the timer is a single-shot timer.
void callOnTimeout(const std::function< void()> &callback)
void start()
Starts or restarts the timer with the timeout specified in interval.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
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 IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
IPState GuideNS(int32_t ms)
IPState GuideWE(int32_t ms)
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool Park() override
Park the telescope to its home position.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool SetParkPosition(double Axis1Value, double Axis2Value) override
SetParkPosition Set desired parking position to the supplied value. This ONLY sets the desired park p...
virtual const char * getDefaultName() override
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
double range24(double r)
range24 Limits a number to be between 0-24 range.
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
#define TRACKRATE_SIDEREAL
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.
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
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.
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.
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.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
#define DEBUGF(priority, msg,...)
const double slewspeeds[SLEWMODES]
std::unique_ptr< Paramount > paramount_mount(new Paramount())
#define PARAMOUNT_TIMEOUT
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.