28#include <libnova/transform.h>
29#include <libnova/sidereal_time.h>
38#define MOUNTINFO_TAB "Mount Info"
42static std::unique_ptr<IOptronV3> scope(
new IOptronV3());
149 IUFillText(&PECInfoT[0],
"PEC_INFO",
"Status",
"");
155 IUFillNumber(&GuideRateN[0],
"RA_GUIDE_RATE",
"x Sidereal",
"%g", 0.01, 0.9, 0.1, 0.5);
156 IUFillNumber(&GuideRateN[1],
"DE_GUIDE_RATE",
"x Sidereal",
"%g", 0.1, 0.99, 0.1, 0.5);
164 IUFillSwitchVector(&SlewModeSP, SlewModeS, 2,
getDeviceName(),
"Slew Type",
"Slew Type",
MOTION_TAB,
IP_RW,
ISR_1OFMANY, 0,
184 MeridianActionSP.
load();
187 MeridianLimitNP[0].
fill(
"VALUE",
"Degrees",
"%.f", 0, 10, 1, 0);
189 MeridianLimitNP.
load();
276void IOptronV3::getStartupData()
279 if (driver->getFirmwareInfo(&firmwareInfo))
292 double RARate = 0, DERate = 0;
293 if (driver->getGuideRate(&RARate, &DERate))
295 GuideRateN[
RA_AXIS].value = RARate;
296 GuideRateN[
DEC_AXIS].value = DERate;
300 int utcOffsetMinutes = 0;
301 bool dayLightSavings =
false;
303 if (driver->getUTCDateTime(&JD, &utcOffsetMinutes, &dayLightSavings))
306 ln_get_timet_from_julian(JD, &utc_time);
311 utc = gmtime(&utc_time);
312 strftime(ts,
sizeof(ts),
"%Y-%m-%dT%H:%M:%S", utc);
317 char offset[8] = {0};
320 utcOffsetMinutes += 60;
322 snprintf(offset, 8,
"%.2f", utcOffsetMinutes / 60.0);
324 LOGF_INFO(
"Mount UTC Offset: %s", offset);
329 LOGF_INFO(
"Mount Daylight Savings: %s", dayLightSavings ?
"ON" :
"OFF");
337 double longitude = 0, latitude = 0;
338 if (driver->getStatus(&scopeInfo))
347 char l[32] = {0}, L[32] = {0};
351 LOGF_INFO(
"Mount Location: Lat %.32s - Long %.32s", l, L);
367 if (driver->getMeridianBehavior(action, degrees))
369 MeridianActionSP.
reset();
372 MeridianLimitNP[0].setValue(degrees);
374 LOGF_INFO(
"Reading mount meridian behavior: When mount reaches %.f degrees past meridian, it will %s.",
375 MeridianLimitNP[0].getValue(), MeridianActionSP[
IOP_MB_STOP].getState() ==
ISS_ON ?
"stop" :
"flip");
394 driver->setParkAz(parkAZ);
395 driver->setParkAlt(parkAL);
400 if (driver->getStatus(&newInfo))
413 GetPECDataStatus(
true);
418 GetPECDataStatus(
true);
442 if (!strcmp(name, GuideRateNP.
name))
446 if (driver->setGuideRate(GuideRateN[
RA_AXIS].value, GuideRateN[
DEC_AXIS].value))
461 auto lastLimit = MeridianLimitNP[0].getValue();
462 MeridianLimitNP.
update(values, names, n);
464 if (lastLimit != MeridianLimitNP[0].getValue())
470 LOGF_INFO(
"Setting mount meridian behavior: When mount reaches %.f degrees past meridian, it will %s.",
471 MeridianLimitNP[0].getValue(), MeridianActionSP[
IOP_MB_STOP].getState() ==
ISS_ON ?
"stop" :
"flip");
477 MeridianLimitNP.
apply();
493 if (!strcmp(name, SlewModeSP.
name))
504 if (!strcmp(name, DaylightSP.
name))
508 if (driver->setDaylightSaving(DaylightS[0].s ==
ISS_ON))
523 MeridianActionSP.
update(states, names, n);
531 LOGF_INFO(
"Setting mount meridian behavior: When mount reaches %.f degrees past meridian, it will %s.",
532 MeridianLimitNP[0].getValue(), MeridianActionSP[
IOP_MB_STOP].getState() ==
ISS_ON ?
"stop" :
"flip");
537 MeridianActionSP.
apply();
553 LOGF_WARN(
"Mount PEC busy recording, %d s", PECTime);
557 driver->setPECEnabled(
false);
565 if (GetPECDataStatus(
true))
568 driver->setPECEnabled(
true);
578 if (!strcmp(name, PECTrainingSP.
name))
587 LOGF_WARN(
"Mount PEC busy recording, %d s", PECTime);
593 driver->setPETEnabled(
false);
596 LOG_WARN(
"PEC Training cancelled by user, chip disabled");
606 driver->setPETEnabled(
true);
610 LOG_INFO(
"PEC recording started...");
614 LOG_WARN(
"PEC Training only possible while guiding");
621 GetPECDataStatus(
true);
645 rc = driver->getStatus(&newInfo);
718 LOG_INFO(
"Slew complete, tracking...");
720 LOG_INFO(
"Meridian flip complete, tracking...");
739 if(GetPECDataStatus(
false))
741 LOGF_INFO(
"%d second worm cycle recorded", PECTime);
749 snprintf(PECText,
MAXINDILABEL,
"Recording: %d s", PECTime);
755 driver->setPETEnabled(
false);
757 LOGF_ERROR(
"Tracking error, recording cancelled %d s", PECTime);
775 char RAStr[64] = {0}, DecStr[64] = {0}, AzStr[64] = {0}, AltStr[64] = {0};
781 fs_sexa(AzStr, horizontalCoords.azimuth, 2, 3600);
782 fs_sexa(AltStr, horizontalCoords.altitude, 2, 3600);
783 std::string pierSide =
"Uknkown";
788 DEBUGF(
DBG_SCOPE,
"RA: %s DE: %s AZ: %s AL: %s PierSide: %s CWState %d", RAStr, DecStr, AzStr, AltStr, pierSide.c_str(), cwState);
800 if (m_ParkingCounter >= MAX_PARK_COUNTER)
802 m_ParkingCounter = 0;
816 CWStateS[cwState].s =
ISS_ON;
830 char RAStr[64] = {0}, DecStr[64] = {0};
832 fs_sexa(RAStr, targetRA, 2, 3600);
833 fs_sexa(DecStr, targetDEC, 2, 3600);
835 if (driver->setRA(
ra) ==
false || driver->setDE(de) ==
false)
843 rc = driver->slewNormal();
845 rc = driver->slewCWUp();
855 LOGF_INFO(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
861 if (driver->setRA(
ra) ==
false || driver->setDE(de) ==
false)
867 if (driver->sync() ==
false)
884 return driver->abort();
900 m_ParkingCounter = 0;
901 LOG_INFO(
"Parking is in progress...");
919 if (driver->unpark())
933 if (driver->checkConnection(
PortFD) ==
false)
945 bool rc1 = driver->setUTCDateTime(ln_get_julian_day(utc));
947 bool rc2 = driver->setUTCOffset(utc_offset * 60);
963 if (driver->setLongitude(longitude) ==
false)
969 if (driver->setLatitude(latitude) ==
false)
975 char l[32] = {0}, L[32] = {0};
977 fs_sexa(L, longitude, 4, 3600);
979 LOGF_INFO(
"Site location updated to Lat %.32s - Long %.32s", l, L);
986 driver->setDebug(enable);
991 driver->setSimulation(enable);
998 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1007 LOG_ERROR(
"Error setting N/S motion direction.");
1017 LOG_ERROR(
"Error stopping N/S motion.");
1032 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1041 LOG_ERROR(
"Error setting N/S motion direction.");
1051 LOG_ERROR(
"Error stopping W/E motion.");
1064 bool rc = driver->startGuide(
IOP_N, (uint32_t)ms);
1070 bool rc = driver->startGuide(
IOP_S, (uint32_t)ms);
1076 bool rc = driver->startGuide(
IOP_E, (uint32_t)ms);
1082 bool rc = driver->startGuide(
IOP_W, (uint32_t)ms);
1089 return driver->setSlewRate(rate);
1099 MeridianLimitNP.
save(fp);
1100 MeridianActionSP.
save(fp);
1107 static struct timeval ltv;
1113 gettimeofday(&tv,
nullptr);
1115 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1118 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1121 da = currentSlewRate * dt;
1199 double parkAZ = horizontalCoords.azimuth;
1203 double parkAlt = horizontalCoords.altitude;
1204 char AzStr[16], AltStr[16];
1205 fs_sexa(AzStr, parkAZ, 2, 3600);
1206 fs_sexa(AltStr, parkAlt, 2, 3600);
1207 LOGF_DEBUG(
"Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr, AltStr);
1210 driver->setParkAz(parkAZ);
1211 driver->setParkAlt(parkAlt);
1221 driver->setParkAz(0);
1230 if (driver->setTrackMode(rate))
1243 if (ieqRARate < 0.1 || ieqRARate > 1.9)
1245 LOG_ERROR(
"Rate is outside permitted limits of 0.1 to 1.9 sidereal rate (1.504 to 28.578 arcsecs/s)");
1250 if (driver->setCustomRATrackRate(ieqRARate))
1267 return driver->setTrackEnabled(enabled);
1271bool IOptronV3::GetPECDataStatus(
bool enabled)
1273 if(driver->getPETEnabled(
true))
1279 LOG_INFO(
"Mount PEC Chip Ready and Trained");
1289 LOG_INFO(
"Mount PEC Chip Needs Training");
1300 if (firmwareInfo.
Model.find(
"CEM") == std::string::npos &&
1301 firmwareInfo.
Model.find(
"GEM45") == std::string::npos &&
1302 firmwareInfo.
Model.find(
"HAE") == std::string::npos &&
1303 firmwareInfo.
Model.find(
"HAZ") == std::string::npos &&
1304 firmwareInfo.
Model.find(
"HEM") == std::string::npos)
1306 LOG_WARN(
"Home search is not supported in this model.");
1310 if (driver->findHome() ==
false)
1315 LOG_INFO(
"Searching for home position...");
1319 if (driver->setCurrentHome() ==
false)
1324 LOG_INFO(
"Home position set to current coordinates.");
1328 if (driver->gotoHome() ==
false)
1333 LOG_INFO(
"Slewing to home position...");
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
void setDefaultPort(const char *port)
setDefaultPort Set default port. Call this function in initProperties() of your driver if you want to...
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
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)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
uint32_t getDriverInterface() const
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
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
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
void setLabel(const char *label)
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
int findOnSwitchIndex() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
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.
bool isParked()
isParked is mount currently parked?
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
Connection::Serial * serialConnection
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....
Connection::TCP * tcpConnection
void setPECState(TelescopePECState state)
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
IGeographicCoordinates m_Location
@ TELESCOPE_CAN_HOME_FIND
@ 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...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
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.
static const uint16_t IOP_SLEW_RATES[]
virtual bool Goto(double ra, double de) override
Move the scope to the supplied RA and DEC coordinates.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
virtual const char * getDefaultName() override
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual IPState ExecuteHomeAction(TelescopeHomeAction action) override
Execute a homing action.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool Park() override
Park the telescope to its home position.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool Sync(double ra, double de) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
INDI::PropertyNumber TrackRateNP
INDI::PropertyNumber EqNP
INDI::PropertySwitch PECStateSP
INDI::PropertySwitch HomeSP
INDI::PropertySwitch SlewRateSP
INDI::PropertySwitch TrackModeSP
INDI::PropertyText TimeTP
INDI::PropertyNumber LocationNP
double range24(double r)
range24 Limits a number to be between 0-24 range.
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[].
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 IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
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 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.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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 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.
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.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
IUGetConfigNumber Opens configuration file and reads single number property.
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(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
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
Encapsulates classes and structures required for iOptron Command Set v3 implementation.
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.
std::string ControllerFirmware
std::string MainBoardFirmware
IOP_HEMISPHERE hemisphere
IOP_SYSTEM_STATUS systemStatus
IOP_TIME_SOURCE timeSource