From 89922e28d1027408600e89d2d43199bf8d700050 Mon Sep 17 00:00:00 2001 From: naheedsa <97088153+naheedsa@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:06:16 +0300 Subject: [PATCH] Migrate Telescope Simulator (#2007) --- drivers/telescope/telescope_simulator.cpp | 286 +++++++++++----------- drivers/telescope/telescope_simulator.h | 223 +++++++++-------- 2 files changed, 269 insertions(+), 240 deletions(-) diff --git a/drivers/telescope/telescope_simulator.cpp b/drivers/telescope/telescope_simulator.cpp index efc9c43f25..629d608255 100644 --- a/drivers/telescope/telescope_simulator.cpp +++ b/drivers/telescope/telescope_simulator.cpp @@ -40,8 +40,8 @@ ScopeSim::ScopeSim() DBG_SCOPE = static_cast(INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE")); SetTelescopeCapability(TELESCOPE_CAN_PARK | TELESCOPE_CAN_SYNC | TELESCOPE_CAN_GOTO | TELESCOPE_CAN_ABORT | - TELESCOPE_HAS_TIME | TELESCOPE_HAS_LOCATION | TELESCOPE_HAS_TRACK_MODE | TELESCOPE_CAN_CONTROL_TRACK | - TELESCOPE_HAS_TRACK_RATE, + TELESCOPE_HAS_TIME | TELESCOPE_HAS_LOCATION | TELESCOPE_HAS_TRACK_MODE | TELESCOPE_CAN_CONTROL_TRACK | + TELESCOPE_HAS_TRACK_RATE, 4); /* initialize random seed: */ @@ -65,41 +65,40 @@ bool ScopeSim::initProperties() #ifdef USE_SIM_TAB // mount type and alignment properties, these are in the Simulation tab - IUFillSwitch(&mountTypeS[Alignment::ALTAZ], "ALTAZ", "AltAz", ISS_OFF); - IUFillSwitch(&mountTypeS[Alignment::EQ_FORK], "EQ_FORK", "Fork (Eq)", ISS_OFF); - IUFillSwitch(&mountTypeS[Alignment::EQ_GEM], "EQ_GEM", "GEM", ISS_ON); - IUFillSwitchVector(&mountTypeSP, mountTypeS, 3, getDeviceName(), "MOUNT_TYPE", "Mount Type", - "Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE ); - - IUFillSwitch(&simPierSideS[0], "PS_OFF", "Off", ISS_OFF); - IUFillSwitch(&simPierSideS[1], "PS_ON", "On", ISS_ON); - IUFillSwitchVector(&simPierSideSP, simPierSideS, 2, getDeviceName(), "SIM_PIER_SIDE", "Sim Pier Side", - "Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE ); - - IUFillNumber(&mountModelN[0], "MM_IH", "Ha Zero (IH)", "%g", -5, 5, 0.01, 0); - IUFillNumber(&mountModelN[1], "MM_ID", "Dec Zero (ID)", "%g", -5, 5, 0.01, 0); - IUFillNumber(&mountModelN[2], "MM_CH", "Cone (CH)", "%g", -5, 5, 0.01, 0); - IUFillNumber(&mountModelN[3], "MM_NP", "Ha/Dec (NP)", "%g", -5, 5, 0.01, 0); - IUFillNumber(&mountModelN[4], "MM_MA", "Pole Azm (MA)", "%g", -5, 5, 0.01, 0); - IUFillNumber(&mountModelN[5], "MM_ME", "Pole elev (ME)", "%g", -5, 5, 0.01, 0); - IUFillNumberVector(&mountModelNP, mountModelN, 6, getDeviceName(), "MOUNT_MODEL", "Mount Model", - "Simulation", IP_WO, 0, IPS_IDLE); - - IUFillNumber(&flipHourAngleN[0], "FLIP_HA", "Hour Angle (deg)", "%g", -20, 20, 0.1, 0); - IUFillNumberVector(&flipHourAngleNP, flipHourAngleN, 1, getDeviceName(), "FLIP_HA", "Flip Posn.", - "Simulation", IP_WO, 0, IPS_IDLE); - - IUFillNumber(&mountAxisN[0], "PRIMARY", "Primary (Ha)", "%g", -180, 180, 0.01, 0); - IUFillNumber(&mountAxisN[1], "SECONDARY", "Secondary (Dec)", "%g", -180, 180, 0.01, 0); - IUFillNumberVector(&mountAxisNP, mountAxisN, 2, getDeviceName(), "MOUNT_AXES", "Mount Axes", - "Simulation", IP_RO, 0, IPS_IDLE); + mountTypeSP[ALTAZ].fill("ALTAZ", "ALTAZ", ISS_OFF); + mountTypeSP[EQ_FORK].fill("EQ_FORK", "Fork (Eq)", ISS_OFF); + mountTypeSP[EQ_GEM].fill("EQ_GEM", "GEM", ISS_OFF); + mountTypeSP.fill(getDeviceName() ,"MOUNT_TYPE", "Mount Type","Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE); + + simPierSideSP[PS_OFF].fill("PS_OFF", "Off", ISS_OFF); + simPierSideSP[PS_ON].fill("PS_ON", "On", ISS_ON); + simPierSideSP.fill(getDeviceName(), "SIM_PIER_SIDE", "Sim Pier Side", + "Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE); + + mountModelNP[MM_IH].fill("MM_IH", "Ha Zero (IH)", "%g", -5, 5, 0.01, 0); + mountModelNP[MM_ID].fill("MM_ID", "Dec Zero (ID)", "%g", -5, 5, 0.01, 0); + mountModelNP[MM_CH].fill("MM_CH", "Cone (CH)", "%g", -5, 5, 0.01, 0); + mountModelNP[MM_NP].fill("MM_NP", "Ha/Dec (NP)", "%g", -5, 5, 0.01, 0); + mountModelNP[MM_MA].fill("MM_MA", "Pole Azm (MA)", "%g", -5, 5, 0.01, 0); + mountModelNP[MM_ME].fill("MM_ME", "Pole elev (ME)", "%g", -5, 5, 0.01, 0); + mountModelNP.fill(getDeviceName(), "MOUNT_MODEL", "Mount Model", + "Simulation", IP_WO, 0, IPS_IDLE); + + flipHourAngleNP[FLIP_HA].fill("FLIP_HA", "Hour Angle (deg)", "%g", -20, 20, 0.1, 0); + flipHourAngleNP.fill(getDeviceName(), "FLIP_HA", "Flip Posn.", + "Simulation", IP_WO, 0, IPS_IDLE); + + mountAxisNP[PRIMARY].fill("PRIMARY", "Primary (Ha)", "%g", -180, 180, 0.01, 0); + mountAxisNP[SECONDARY].fill("SECONDARY", "Secondary (Dec)", "%g", -180, 180, 0.01, 0); + mountAxisNP.fill(getDeviceName(), "MOUNT_AXES", "Mount Axes", + "Simulation", IP_RO, 0, IPS_IDLE); #endif /* How fast do we guide compared to sidereal rate */ - IUFillNumber(&GuideRateN[RA_AXIS], "GUIDE_RATE_WE", "W/E Rate", "%g", 0, 1, 0.1, 0.5); - IUFillNumber(&GuideRateN[DEC_AXIS], "GUIDE_RATE_NS", "N/S Rate", "%g", 0, 1, 0.1, 0.5); - IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0, - IPS_IDLE); + GuideRateNP[RA_AXIS].fill("GUIDE_RATE_WE", "W/E Rate", "%g", 0, 1, 0.1, 0.5); + GuideRateNP[DEC_AXIS].fill("GUIDE_RATE_NS", "N/S Rate", "%g", 0, 1, 0.1, 0.5); + GuideRateNP.fill(getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0, + IPS_IDLE); IUFillSwitch(&SlewRateS[SLEW_GUIDE], "SLEW_GUIDE", "Guide", ISS_OFF); IUFillSwitch(&SlewRateS[SLEW_CENTERING], "SLEW_CENTERING", "Centering", ISS_OFF); @@ -140,15 +139,15 @@ void ScopeSim::ISGetProperties(const char *dev) INDI::Telescope::ISGetProperties(dev); #ifdef USE_SIM_TAB - defineProperty(&mountTypeSP); - loadConfig(true, mountTypeSP.name); - defineProperty(&simPierSideSP); - loadConfig(true, simPierSideSP.name); - defineProperty(&mountModelNP); - loadConfig(true, mountModelNP.name); - defineProperty(&mountAxisNP); - defineProperty(&flipHourAngleNP); - loadConfig(true, flipHourAngleNP.name); + defineProperty(mountTypeSP); + mountTypeSP.load(); + defineProperty(simPierSideSP); + simPierSideSP.load(); + defineProperty(mountModelNP); + mountModelNP.load(); + defineProperty(mountAxisNP); + defineProperty(flipHourAngleNP); + flipHourAngleNP.load(); #endif } @@ -162,9 +161,9 @@ bool ScopeSim::updateProperties() { defineProperty(&GuideNSNP); defineProperty(&GuideWENP); - defineProperty(&GuideRateNP); + defineProperty(GuideRateNP); + GuideRateNP.load(); defineProperty(HomeSP); - loadConfig(true, GuideRateNP.name); if (InitPark()) { @@ -199,7 +198,7 @@ bool ScopeSim::updateProperties() { deleteProperty(GuideNSNP.name); deleteProperty(GuideWENP.name); - deleteProperty(GuideRateNP.name); + deleteProperty(GuideRateNP.getName()); deleteProperty(HomeSP); } @@ -242,40 +241,40 @@ bool ScopeSim::ReadScopeStatus() bool slewing = axisPrimary.isSlewing || axisSecondary.isSlewing; switch (TrackState) { - case SCOPE_PARKING: - if (!slewing) + case SCOPE_PARKING: + if (!slewing) + { + SetParked(true); + EqNP.s = IPS_IDLE; + LOG_INFO("Telescope slew is complete. Parked"); + } + break; + case SCOPE_SLEWING: + if (!slewing) + { + // It seems to be required that tracking is enabled when a slew finishes but is it correct? + // if the mount was not tracking before the slew should it remain not tracking? + TrackState = SCOPE_TRACKING; + SetTrackEnabled(true); + EqNP.s = IPS_IDLE; + + if (HomeSP.getState() == IPS_BUSY) { - SetParked(true); - EqNP.s = IPS_IDLE; - LOG_INFO("Telescope slew is complete. Parked"); + HomeSP.setState(IPS_OK); + HomeSP.apply(); + LOG_INFO("Home position reached."); } - break; - case SCOPE_SLEWING: - if (!slewing) - { - // It seems to be required that tracking is enabled when a slew finishes but is it correct? - // if the mount was not tracking before the slew should it remain not tracking? - TrackState = SCOPE_TRACKING; - SetTrackEnabled(true); - EqNP.s = IPS_IDLE; + else + LOG_INFO("Telescope slew is complete. Tracking..."); - if (HomeSP.getState() == IPS_BUSY) - { - HomeSP.setState(IPS_OK); - HomeSP.apply(); - LOG_INFO("Home position reached."); - } - else - LOG_INFO("Telescope slew is complete. Tracking..."); - - // check the slew accuracy - auto dRa = targetRA - currentRA; - auto dDec = targetDEC - currentDEC; - LOGF_DEBUG("slew accuracy %f, %f", dRa * 15 * 3600, dDec * 3600); - } - break; - default: - break; + // check the slew accuracy + auto dRa = targetRA - currentRA; + auto dDec = targetDEC - currentDEC; + LOGF_DEBUG("slew accuracy %f, %f", dRa * 15 * 3600, dDec * 3600); + } + break; + default: + break; } if (guidingEW && !axisPrimary.IsGuiding()) @@ -298,16 +297,16 @@ bool ScopeSim::ReadScopeStatus() double axisRA = axisPrimary.position.Degrees(); double axisDE = axisSecondary.position.Degrees(); // No need to spam log until we have some actual changes. - if (std::fabs(mountAxisN[AXIS_RA].value - axisRA) > 0.0001 || - std::fabs(mountAxisN[AXIS_DE].value - axisDE) > 0.0001) + if (std::fabs(mountAxisNP[AXIS_RA].getValue() - axisRA) > 0.0001 || + std::fabs(mountAxisNP[AXIS_DE].getValue() - axisDE) > 0.0001) { - mountAxisN[AXIS_RA].value = axisRA; - mountAxisN[AXIS_DE].value = axisDE; + mountAxisNP[AXIS_RA].setValue(axisRA); + mountAxisNP[AXIS_DE].setValue(axisDE); LOGF_EXTRA1("%s: %f, ra %f", axisPrimary.axisName, axisPrimary.position.Degrees(), ra.Hours()); LOGF_EXTRA1("%s: %f, dec %f", axisSecondary.axisName, axisSecondary.position.Degrees(), dec.Degrees()); - IDSetNumber(&mountAxisNP, nullptr); + mountAxisNP.apply(); } #endif @@ -376,14 +375,14 @@ void ScopeSim::StartSlew(double ra, double dec, TelescopeStatus status) const char * statusStr; switch (status) { - case SCOPE_PARKING: - statusStr = "Parking"; - break; - case SCOPE_SLEWING: - statusStr = "Slewing"; - break; - default: - statusStr = "unknown"; + case SCOPE_PARKING: + statusStr = "Parking"; + break; + case SCOPE_SLEWING: + statusStr = "Slewing"; + break; + default: + statusStr = "unknown"; } TrackState = status; @@ -404,9 +403,9 @@ bool ScopeSim::ISNewNumber(const char *dev, const char *name, double values[], c { if (strcmp(name, "GUIDE_RATE") == 0) { - IUUpdateNumber(&GuideRateNP, values, names, n); - GuideRateNP.s = IPS_OK; - IDSetNumber(&GuideRateNP, nullptr); + GuideRateNP.update(values, names, n); + GuideRateNP.setState(IPS_OK); + GuideRateNP.apply(); return true; } @@ -417,25 +416,24 @@ bool ScopeSim::ISNewNumber(const char *dev, const char *name, double values[], c } #ifdef USE_SIM_TAB - if (strcmp(name, mountModelNP.name) == 0) + if (mountModelNP.isNameMatch(name)) { - IUUpdateNumber(&mountModelNP, values, names, n); - mountModelNP.s = IPS_OK; - IDSetNumber(&mountModelNP, nullptr); - alignment.setCorrections(mountModelN[0].value, mountModelN[1].value, - mountModelN[2].value, mountModelN[3].value, - mountModelN[4].value, mountModelN[5].value); - - saveConfig(true, mountModelNP.name); + mountModelNP.update(values, names, n); + mountModelNP.setState(IPS_OK); + mountModelNP.apply(); + alignment.setCorrections(mountModelNP[MM_IH].getValue(), mountModelNP[MM_ID].getValue(), + mountModelNP[MM_CH].getValue(), mountModelNP[MM_NP].getValue(), + mountModelNP[MM_MA].getValue(), mountModelNP[MM_ME].getValue()); + saveConfig(true, mountModelNP.getName()); return true; } - if (strcmp(name, flipHourAngleNP.name) == 0) + if (flipHourAngleNP.isNameMatch(name)) { - IUUpdateNumber(&flipHourAngleNP, values, names, n); - flipHourAngleNP.s = IPS_OK; - IDSetNumber(&flipHourAngleNP, nullptr); - alignment.setFlipHourAngle(flipHourAngleN[0].value); + flipHourAngleNP.update(values, names, n); + flipHourAngleNP.setState(IPS_OK); + flipHourAngleNP.apply(); + alignment.setFlipHourAngle(flipHourAngleNP[FLIP_HA].getValue()); return true; } #endif @@ -490,28 +488,28 @@ bool ScopeSim::ISNewSwitch(const char *dev, const char *name, ISState *states, c return true; } #ifdef USE_SIM_TAB - if (strcmp(name, mountTypeSP.name) == 0) + if (mountTypeSP.isNameMatch(name)) { - if (IUUpdateSwitch(&mountTypeSP, states, names, n) < 0) + if (!mountTypeSP.update(states, names, n)) return false; - mountTypeSP.s = IPS_OK; - IDSetSwitch(&mountTypeSP, nullptr); + mountTypeSP.setState(IPS_OK); + mountTypeSP.apply(); updateMountAndPierSide(); return true; } - if (strcmp(name, simPierSideSP.name) == 0) + if (simPierSideSP.isNameMatch(name)) { - if (IUUpdateSwitch(&simPierSideSP, states, names, n) < 0) + if (!simPierSideSP.update(states, names, n)) return false; - simPierSideSP.s = IPS_OK; - IDSetSwitch(&simPierSideSP, nullptr); + simPierSideSP.setState(IPS_OK); + simPierSideSP.apply(); updateMountAndPierSide(); return true; } -#endif - // Slew mode +#endif \ + // Slew mode if (strcmp(name, SlewRateSP.name) == 0) { if (IUUpdateSwitch(&SlewRateSP, states, names, n) < 0) @@ -569,7 +567,7 @@ bool ScopeSim::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) IPState ScopeSim::GuideNorth(uint32_t ms) { - double rate = GuideRateN[DEC_AXIS].value; + double rate = GuideRateNP[DEC_AXIS].getValue(); axisSecondary.StartGuide(rate, ms); guidingNS = true; return IPS_BUSY; @@ -577,7 +575,7 @@ IPState ScopeSim::GuideNorth(uint32_t ms) IPState ScopeSim::GuideSouth(uint32_t ms) { - double rate = GuideRateN[DEC_AXIS].value; + double rate = GuideRateNP[DEC_AXIS].getValue(); axisSecondary.StartGuide(-rate, ms); guidingNS = true; return IPS_BUSY; @@ -585,7 +583,7 @@ IPState ScopeSim::GuideSouth(uint32_t ms) IPState ScopeSim::GuideEast(uint32_t ms) { - double rate = GuideRateN[RA_AXIS].value; + double rate = GuideRateNP[RA_AXIS].getValue(); axisPrimary.StartGuide(-rate, ms); guidingEW = true; return IPS_BUSY; @@ -593,7 +591,7 @@ IPState ScopeSim::GuideEast(uint32_t ms) IPState ScopeSim::GuideWest(uint32_t ms) { - double rate = GuideRateN[RA_AXIS].value; + double rate = GuideRateNP[RA_AXIS].getValue(); axisPrimary.StartGuide(rate, ms); guidingEW = true; return IPS_BUSY; @@ -623,21 +621,21 @@ bool ScopeSim::SetTrackMode(uint8_t mode) { switch (static_cast(mode)) { - case TRACK_SIDEREAL: - axisPrimary.TrackRate(Axis::SIDEREAL); - axisSecondary.TrackRate(Axis::OFF); - return true; - case TRACK_SOLAR: - axisPrimary.TrackRate(Axis::SOLAR); - axisSecondary.TrackRate(Axis::OFF); - return true; - case TRACK_LUNAR: - axisPrimary.TrackRate(Axis::LUNAR); - axisSecondary.TrackRate(Axis::OFF); - return true; - case TRACK_CUSTOM: - SetTrackRate(TrackRateN[AXIS_RA].value, TrackRateN[AXIS_DE].value); - return true; + case TRACK_SIDEREAL: + axisPrimary.TrackRate(Axis::SIDEREAL); + axisSecondary.TrackRate(Axis::OFF); + return true; + case TRACK_SOLAR: + axisPrimary.TrackRate(Axis::SOLAR); + axisSecondary.TrackRate(Axis::OFF); + return true; + case TRACK_LUNAR: + axisPrimary.TrackRate(Axis::LUNAR); + axisSecondary.TrackRate(Axis::OFF); + return true; + case TRACK_CUSTOM: + SetTrackRate(TrackRateN[AXIS_RA].value, TrackRateN[AXIS_DE].value); + return true; } return false; } @@ -661,11 +659,12 @@ bool ScopeSim::saveConfigItems(FILE *fp) INDI::Telescope::saveConfigItems(fp); #ifdef USE_SIM_TAB - IUSaveConfigNumber(fp, &GuideRateNP); - IUSaveConfigSwitch(fp, &mountTypeSP); - IUSaveConfigSwitch(fp, &simPierSideSP); - IUSaveConfigNumber(fp, &mountModelNP); - IUSaveConfigNumber(fp, &flipHourAngleNP); + GuideRateNP.save(fp); + mountTypeSP.save(fp); + simPierSideSP.save(fp); + mountModelNP.save(fp); + flipHourAngleNP.save(fp); + #endif return true; } @@ -684,8 +683,8 @@ bool ScopeSim::updateLocation(double latitude, double longitude, double elevatio bool ScopeSim::updateMountAndPierSide() { #ifdef USE_SIM_TAB - int mountType = IUFindOnSwitchIndex(&mountTypeSP); - int pierSide = IUFindOnSwitchIndex(&simPierSideSP); + int mountType = mountTypeSP.findOnSwitchIndex(); + int pierSide = simPierSideSP.findOnSwitchIndex(); if (mountType < 0 || pierSide < 0) return false; @@ -724,4 +723,3 @@ bool ScopeSim::updateMountAndPierSide() } ///////////////////////////////////////////////////////////////////// - diff --git a/drivers/telescope/telescope_simulator.h b/drivers/telescope/telescope_simulator.h index 92a5c2c2de..a754219453 100644 --- a/drivers/telescope/telescope_simulator.h +++ b/drivers/telescope/telescope_simulator.h @@ -41,104 +41,135 @@ */ class ScopeSim : public INDI::Telescope, public INDI::GuiderInterface { - public: - ScopeSim(); - virtual ~ScopeSim() = default; - - virtual const char *getDefaultName() override; - virtual bool Connect() override; - virtual bool Disconnect() override; - virtual bool ReadScopeStatus() override; - virtual bool initProperties() override; - virtual void ISGetProperties(const char *dev) override; - virtual bool updateProperties() override; - - virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override; - virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override; - - protected: - // Slew Rate - virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override; - virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override; - virtual bool Abort() override; - - virtual IPState GuideNorth(uint32_t ms) override; - virtual IPState GuideSouth(uint32_t ms) override; - virtual IPState GuideEast(uint32_t ms) override; - virtual IPState GuideWest(uint32_t ms) override; - - virtual bool SetTrackMode(uint8_t mode) override; - virtual bool SetTrackEnabled(bool enabled) override; - virtual bool SetTrackRate(double raRate, double deRate) override; - - virtual bool Goto(double, double) override; - virtual bool Park() override; - virtual bool UnPark() override; - virtual bool Sync(double ra, double dec) override; - - // Parking - virtual bool SetCurrentPark() override; - virtual bool SetDefaultPark() override; - virtual bool updateLocation(double latitude, double longitude, double elevation) override; - - virtual bool saveConfigItems(FILE *fp) override; - - private: - double currentRA { 0 }; - double currentDEC { 90 }; - double targetRA { 0 }; - double targetDEC { 0 }; - - /// used by GoTo and Park - void StartSlew(double ra, double dec, TelescopeStatus status); - - // bool forceMeridianFlip { false }; // #PS: unused - unsigned int DBG_SCOPE { 0 }; - - int mcRate = 0; - - // double guiderEWTarget[2]; - // double guiderNSTarget[2]; - - bool guidingNS = false; - bool guidingEW = false; - - INumber GuideRateN[2]; - INumberVectorProperty GuideRateNP; - - INDI::PropertySwitch HomeSP {3}; - enum - { - Find, - Set, - Go - }; - double m_Home[2] = {0, 0}; - - Axis axisPrimary { "HaAxis" }; // hour angle mount axis - Axis axisSecondary { "DecAxis" }; // declination mount axis - - int m_PierSide {-1}; - int m_MountType {-1}; - - Alignment alignment; - bool updateMountAndPierSide(); +public: + ScopeSim(); + virtual ~ScopeSim() = default; + + virtual const char *getDefaultName() override; + virtual bool Connect() override; + virtual bool Disconnect() override; + virtual bool ReadScopeStatus() override; + virtual bool initProperties() override; + virtual void ISGetProperties(const char *dev) override; + virtual bool updateProperties() override; + + virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override; + virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override; + +protected: + // Slew Rate + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override; + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override; + virtual bool Abort() override; + + virtual IPState GuideNorth(uint32_t ms) override; + virtual IPState GuideSouth(uint32_t ms) override; + virtual IPState GuideEast(uint32_t ms) override; + virtual IPState GuideWest(uint32_t ms) override; + + virtual bool SetTrackMode(uint8_t mode) override; + virtual bool SetTrackEnabled(bool enabled) override; + virtual bool SetTrackRate(double raRate, double deRate) override; + + virtual bool Goto(double, double) override; + virtual bool Park() override; + virtual bool UnPark() override; + virtual bool Sync(double ra, double dec) override; + + // Parking + virtual bool SetCurrentPark() override; + virtual bool SetDefaultPark() override; + virtual bool updateLocation(double latitude, double longitude, double elevation) override; + + virtual bool saveConfigItems(FILE *fp) override; + +private: + double currentRA { 0 }; + double currentDEC { 90 }; + double targetRA { 0 }; + double targetDEC { 0 }; + + /// used by GoTo and Park + void StartSlew(double ra, double dec, TelescopeStatus status); + + // bool forceMeridianFlip { false }; // #PS: unused + unsigned int DBG_SCOPE { 0 }; + + int mcRate = 0; + + // double guiderEWTarget[2]; + // double guiderNSTarget[2]; + + bool guidingNS = false; + bool guidingEW = false; + + INDI::PropertyNumber GuideRateNP {2}; + enum + { + GUIDE_RATE_WE, + GUIDE_RATE_NS + }; + + INDI::PropertySwitch HomeSP {3}; + enum + { + Find, + Set, + Go + }; + double m_Home[2] = {0, 0}; + + Axis axisPrimary { "HaAxis" }; // hour angle mount axis + Axis axisSecondary { "DecAxis" }; // declination mount axis + + int m_PierSide {-1}; + int m_MountType {-1}; + + Alignment alignment; + bool updateMountAndPierSide(); #ifdef USE_SIM_TAB - // Simulator Tab properties - // Scope type and alignment - ISwitch mountTypeS[3]; - ISwitchVectorProperty mountTypeSP; - ISwitch simPierSideS[2]; - ISwitchVectorProperty simPierSideSP; - - INumber mountModelN[6]; - INumberVectorProperty mountModelNP; - INumber mountAxisN[2]; - INumberVectorProperty mountAxisNP; - - INumber flipHourAngleN[1]; - INumberVectorProperty flipHourAngleNP; + // Simulator Tab properties + // Scope type and alignment + INDI::PropertySwitch mountTypeSP {3}; + enum + { + ALTAZ, + EQ_FORK, + EQ_GEM + }; + + INDI::PropertySwitch simPierSideSP {2}; + enum + { + PS_OFF, + PS_ON + }; + + INDI::PropertyNumber mountModelNP {6}; + enum + { + MM_IH, + MM_ID, + MM_CH, + MM_NP, + MM_MA, + MM_ME + }; + + INDI::PropertyNumber mountAxisNP {2}; + enum + { + PRIMARY, + SECONDARY + }; + + INDI::PropertyNumber flipHourAngleNP {1}; + enum + { + FLIP_HA + }; + #endif };