40#include <libnova/sidereal_time.h>
41#include <libnova/transform.h>
53#define FINE_SLEW_RATE 0.1
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
126 IUFillNumber(&JogRateN[
RA_AXIS],
"JOG_RATE_WE",
"W/E Rate (arcmin)",
"%g", 0, 600, 60, 30);
132 IUFillNumber(&GuideRateN[
RA_AXIS],
"GUIDE_RATE_WE",
"W/E Rate",
"%1.1f", 0.0, 1.0, 0.1, 0.5);
169 if (isTheSkyTracking())
238 int rc = 0, nbytes_written = 0, nbytes_read = 0;
244 "sky6RASCOMTele.ConnectAndDoNotUnpark();"
245 "Out = sky6RASCOMTele.IsConnected + '#';",
252 LOGF_ERROR(
"Error writing Handshake to TheSkyX TCP server. Result: %d", rc);
258 LOGF_ERROR(
"Error reading Handshake from TheSkyX TCP server. Result: %d", rc);
262 if (strcmp(pRES,
"1#") != 0)
264 LOGF_ERROR(
"Error connecting to TheSky. Result: %s", pRES);
271bool Paramount::getMountRADE()
273 int rc = 0, nbytes_written = 0, nbytes_read = 0;
275 double SkyXRA = 0., SkyXDEC = 0.;
280 "sky6RASCOMTele.GetRaDec();"
281 "Out = String(sky6RASCOMTele.dRa) + ',' + String(sky6RASCOMTele.dDec) + '#';",
288 LOGF_ERROR(
"Error writing GetRaDec to TheSkyX TCP server. Response: %d", rc);
294 LOGF_ERROR(
"Error reading GetRaDec from TheSkyX TCP server. Result: %d", rc);
301 if (sscanf(pRES,
"|No error. Error = 0.%lf,%lf#", &SkyXRA, &SkyXDEC) == 2)
304 currentDEC = SkyXDEC;
308 LOGF_ERROR(
"Error reading coordinates. Result: %s", pRES);
314 int rc = 0, nbytes_written = 0, nbytes_read = 0;
316 int SkyXPierSide = -1;
321 "sky6RASCOMTele.DoCommand(11, \"Pier Side\");"
322 "Out = sky6RASCOMTele.DoCommandOutput + '#';",
329 LOGF_ERROR(
"Error writing DoCommand(Pier Side) to TheSkyX TCP server. Result: %d", rc);
335 LOGF_ERROR(
"Error reading Pier Side from TheSkyX TCP server. Result: %d", rc);
341 if (sscanf(pRES,
"|No error. Error = 0.%d#", &SkyXPierSide) == 1)
346 LOGF_ERROR(
"Error reading Pier Side. Result: %s", pRES);
361 if (isSlewComplete())
369 LOG_INFO(
"Finding home completed.");
373 LOG_INFO(
"Slew is complete. Tracking...");
378 if (isTheSkyParked())
387 char RAStr[64], DecStr[64];
389 fs_sexa(RAStr, currentRA, 2, 3600);
390 fs_sexa(DecStr, currentDEC, 2, 3600);
392 DEBUGF(DBG_SCOPE,
"Current RA: %s Current DEC: %s", RAStr, DecStr);
404 char RAStr[64], DecStr[64];
406 fs_sexa(RAStr, targetRA, 2, 3600);
407 fs_sexa(DecStr, targetDEC, 2, 3600);
411 "sky6RASCOMTele.Asynchronous = true;"
412 "sky6RASCOMTele.SlewToRaDec(%g, %g,'');",
413 targetRA, targetDEC);
415 if (!sendTheSkyOKCommand(pCMD,
"Slewing to target"))
420 LOGF_INFO(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
424bool Paramount::isSlewComplete()
426 int rc = 0, nbytes_written = 0, nbytes_read = 0;
432 "Out = sky6RASCOMTele.IsSlewComplete + '#';",
439 LOGF_ERROR(
"Error writing IsSlewComplete to TheSkyX TCP server. Result: %d", rc);
445 LOGF_ERROR(
"Error reading IsSlewComplete from TheSkyX TCP server. Result: %d", rc);
452 if (sscanf(pRES,
"|No error. Error = 0.%d#", &isComplete) == 1)
454 return isComplete == 1 ? 1 : 0;
457 LOGF_ERROR(
"Error reading isSlewComplete. Result: %s", pRES);
461bool Paramount::isTheSkyParked()
463 int rc = 0, nbytes_written = 0, nbytes_read = 0;
469 "Out = sky6RASCOMTele.IsParked() + '#';",
476 LOGF_ERROR(
"Error writing sky6RASCOMTele.IsParked() to TheSkyX TCP server. Result: %d", rc);
482 LOGF_ERROR(
"Error reading sky6RASCOMTele.IsParked() from TheSkyX TCP server. Result: %d", rc);
488 if (strcmp(pRES,
"|No error. Error = 0.true#") == 0)
490 if (strcmp(pRES,
"|No error. Error = 0.false#") == 0)
493 LOGF_ERROR(
"Error checking for park. Invalid response: %s", pRES);
497bool Paramount::isTheSkyTracking()
499 int rc = 0, nbytes_written = 0, nbytes_read = 0;
505 "Out = sky6RASCOMTele.IsTracking + '#';",
512 LOGF_ERROR(
"Error writing sky6RASCOMTele.IsTracking to TheSkyX TCP server. Result: %d", rc);
518 LOGF_ERROR(
"Error reading sky6RASCOMTele.IsTracking from TheSkyX TCP server. Result: %d", rc);
524 double SkyXTrackRate = 0.;
525 if (sscanf(pRES,
"|No error. Error = 0.%lf#", &SkyXTrackRate) == 1)
527 if (SkyXTrackRate == 0)
529 else if (SkyXTrackRate > 0)
533 LOGF_ERROR(
"Error checking for tracking. Invalid response: %s", pRES);
541 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.Sync(%g, %g,'');", targetRA, targetDEC);
542 if (!sendTheSkyOKCommand(pCMD,
"Syncing to target"))
565 "sky6RASCOMTele.Asynchronous = true;"
566 "sky6RASCOMTele.ParkAndDoNotDisconnect();",
569 if (!sendTheSkyOKCommand(pCMD,
"Parking mount"))
572 LOG_INFO(
"Parking telescope in progress...");
580 strncpy(pCMD,
"sky6RASCOMTele.Unpark();",
MAXRBUF);
581 if (!sendTheSkyOKCommand(pCMD,
"Unparking mount"))
585 if (isTheSkyParked())
586 LOG_ERROR(
"Could not unpark for some reason.");
602 if (strcmp(name,
"JOG_RATE") == 0)
611 if (strcmp(name, GuideRateNP.
name) == 0)
628 strncpy(pCMD,
"sky6RASCOMTele.Abort();",
MAXRBUF);
629 return sendTheSkyOKCommand(pCMD,
"Abort mount slew");
632bool Paramount::findHome()
636 strncpy(pCMD,
"sky6RASCOMTele.FindHome();"
637 "while(!sky6RASCOMTele.IsSlewComplete) {"
638 "sky6Web.Sleep(1000);}",
640 return sendTheSkyOKCommand(pCMD,
"Find home", 60);
648 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
659 if (!
isSimulation() && !startOpenLoopMotion(motion, rate))
661 LOG_ERROR(
"Error setting N/S motion direction.");
687 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
697 if (!
isSimulation() && !startOpenLoopMotion(motion, rate))
699 LOG_ERROR(
"Error setting W/E motion direction.");
721bool Paramount::startOpenLoopMotion(uint8_t motion, uint16_t rate)
725 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.DoCommand(9,'%d|%d');", motion, rate);
726 return sendTheSkyOKCommand(pCMD,
"Starting open loop motion");
729bool Paramount::stopOpenLoopMotion()
733 strncpy(pCMD,
"sky6RASCOMTele.DoCommand(10,'');",
MAXRBUF);
734 return sendTheSkyOKCommand(pCMD,
"Stopping open loop motion");
748 strncpy(pCMD,
"sky6RASCOMTele.SetParkPosition();",
MAXRBUF);
749 if (!sendTheSkyOKCommand(pCMD,
"Setting Park Position"))
776 LOG_ERROR(
"Setting custom parking position directly is not supported. Slew to the desired "
777 "parking position and click Current.");
781void Paramount::mountSim()
783 static struct timeval ltv
791 double dt, dx, da_ra = 0, da_dec = 0;
795 gettimeofday(&tv,
nullptr);
797 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
800 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
803 if (fabs(targetRA - currentRA) * 15. >=
GOTO_LIMIT)
805 else if (fabs(targetRA - currentRA) * 15. >=
SLEW_LIMIT)
810 if (fabs(targetDEC - currentDEC) >=
GOTO_LIMIT)
812 else if (fabs(targetDEC - currentDEC) >=
SLEW_LIMIT)
817 double motionRate = 0;
820 motionRate = JogRateN[0].value;
822 motionRate = JogRateN[1].value;
826 da_ra = motionRate * dt * 0.05;
827 da_dec = motionRate * dt * 0.05;
833 currentDEC += da_dec;
835 currentDEC -= da_dec;
846 currentRA += da_ra / 15.;
848 currentRA -= da_ra / 15.;
872 dx = targetRA - currentRA;
878 if (fabs(dx) <= da_ra)
890 else if (currentRA > 24)
893 dx = targetDEC - currentDEC;
894 if (fabs(dx) <= da_dec)
920bool Paramount::sendTheSkyOKCommand(
const char *command,
const char *errorMessage, uint8_t timeout)
922 int rc = 0, nbytes_written = 0, nbytes_read = 0;
931 "catch (err) {Out = err; }",
936 tcflush(
PortFD, TCIOFLUSH);
940 LOGF_ERROR(
"Error writing sendTheSkyOKCommand to TheSkyX TCP server. Result: $%d", rc);
946 LOGF_ERROR(
"Error reading sendTheSkyOKCommand from TheSkyX TCP server. Result: %d", rc);
952 tcflush(
PortFD, TCIOFLUSH);
954 if (strcmp(
"|No error. Error = 0.OK#", pRES) == 0 )
958 LOGF_ERROR(
"sendTheSkyOKCommand Error %s - Invalid response: %s", errorMessage, pRES);
965 return GuideNS(
static_cast<int>(ms));
970 return GuideNS(-
static_cast<int>(ms));
975 return GuideWE(
static_cast<int>(ms));
980 return GuideWE(-
static_cast<int>(ms));
987 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
996 "sky6RASCOMTele.Asynchronous = true;"
997 "sky6DirectGuide.MoveTelescope(%g, %g);", 0., dDec);
999 if (!sendTheSkyOKCommand(pCMD,
"Guide North-South"))
1002 m_NSTimer.
start(ms);
1011 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1020 "sky6RASCOMTele.Asynchronous = true;"
1021 "sky6DirectGuide.MoveTelescope(%g, %g);", dRA, 0.);
1023 if (!sendTheSkyOKCommand(pCMD,
"Guide West-East"))
1026 m_WETimer.
start(ms);
1031bool Paramount::setTheSkyTracking(
bool enable,
bool isSidereal,
double raRate,
double deRate)
1033 int on = enable ? 1 : 0;
1034 int ignore = isSidereal ? 1 : 0;
1037 snprintf(pCMD,
MAXRBUF,
"sky6RASCOMTele.SetTracking(%d, %d, %g, %g);", on, ignore, raRate, deRate);
1038 return sendTheSkyOKCommand(pCMD,
"Setting tracking rate");
1043 return setTheSkyTracking(
true,
false, raRate, deRate);
1049 double dRA = 0, dDE = 0;
1060 return setTheSkyTracking(
true, isSidereal, dRA, dDE);
1070 return setTheSkyTracking(0, 0, 0., 0.);
1078 LOG_INFO(
"Moving to home position. Please stand by...");
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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.
uint32_t getDriverInterface() const
INDI::PropertyNumber GuideNSNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyNumber GuideWENP
void initProperties(const char *groupName)
Initialize guider properties. It is recommended to call this function within initProperties() of your...
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void setLabel(const char *label)
int findOnSwitchIndex() const
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
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.
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....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
@ TELESCOPE_HAS_TRACK_RATE
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
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...
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
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 IPState ExecuteHomeAction(TelescopeHomeAction action) override
Execute a homing action.
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
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
INDI::PropertyNumber TrackRateNP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertySwitch HomeSP
INDI::PropertySwitch SlewRateSP
INDI::PropertySwitch MovementWESP
INDI::PropertyNumber LocationNP
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 sidereal time given longitude and system clock.
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 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 IDSetNumber(const INumberVectorProperty *nvp, 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,...)
#define TRACKRATE_SIDEREAL
const double slewspeeds[SLEWMODES]
#define PARAMOUNT_TIMEOUT
std::unique_ptr< Paramount > paramount_mount(new Paramount())
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.