diff --git a/indi-celestronaux/auxproto.cpp b/indi-celestronaux/auxproto.cpp index d2c183fed..397af2ec7 100644 --- a/indi-celestronaux/auxproto.cpp +++ b/indi-celestronaux/auxproto.cpp @@ -261,6 +261,8 @@ const char * AUXCommand::commandName(AUXCommands command) const return "MC_SET_AUTOGUIDE_RATE"; case MC_GET_AUTOGUIDE_RATE: return "MC_GET_AUTOGUIDE_RATE"; + case FOC_GET_HS_POSITIONS: + return "FOC_GET_HS_POSITIONS"; default : return nullptr; } @@ -295,6 +297,8 @@ int AUXCommand::responseDataSize() { switch (m_Command) { + case FOC_GET_HS_POSITIONS: + return 8; case MC_GET_POSITION: case MC_GET_CORDWRAP_POS: return 3; @@ -354,6 +358,8 @@ const char * AUXCommand::moduleName(AUXTargets n) return "APP"; case GPS : return "GPS"; + case FOCUS : + return "FOCUS"; case WiFi: return "WiFi"; case BAT : diff --git a/indi-celestronaux/auxproto.h b/indi-celestronaux/auxproto.h index 61a8048d5..ffeb22483 100644 --- a/indi-celestronaux/auxproto.h +++ b/indi-celestronaux/auxproto.h @@ -61,7 +61,8 @@ enum AUXCommands GPS_GET_YEAR = 0x04, GPS_GET_TIME = 0x33, GPS_TIME_VALID = 0x36, - GPS_LINKED = 0x37 + GPS_LINKED = 0x37, + FOC_GET_HS_POSITIONS = 0x2c }; enum AUXTargets @@ -72,6 +73,7 @@ enum AUXTargets HCP = 0x0d, AZM = 0x10, ALT = 0x11, + FOCUS = 0x12, APP = 0x20, GPS = 0xb0, WiFi = 0xb5, diff --git a/indi-celestronaux/celestronaux.cpp b/indi-celestronaux/celestronaux.cpp index e5751799e..015f9ae69 100644 --- a/indi-celestronaux/celestronaux.cpp +++ b/indi-celestronaux/celestronaux.cpp @@ -59,7 +59,8 @@ double anglediff(double a, double b) /// ///////////////////////////////////////////////////////////////////////////////////// CelestronAUX::CelestronAUX() - : ScopeStatus(IDLE), + : FI(this), + ScopeStatus(IDLE), DBG_CAUX(INDI::Logger::getInstance().addDebugLevel("AUX", "CAUX")), DBG_SERIAL(INDI::Logger::getInstance().addDebugLevel("Serial", "CSER")) { @@ -73,7 +74,7 @@ CelestronAUX::CelestronAUX() TELESCOPE_CAN_CONTROL_TRACK | TELESCOPE_HAS_TRACK_MODE | TELESCOPE_HAS_TRACK_RATE - , 8); + , 8); //Both communication available, Serial and network (tcp/ip). setTelescopeConnection(CONNECTION_TCP | CONNECTION_SERIAL); @@ -311,6 +312,28 @@ bool CelestronAUX::initProperties() setDriverInterface(getDriverInterface() | GUIDER_INTERFACE); + ///////////////////////////////////////////////////////////////////////////////////// + /// Focus Tab + ///////////////////////////////////////////////////////////////////////////////////// + + FI::initProperties(FOCUS_TAB); + + // override some default initialization values + FocusMaxPosN[0].max = 60000; + FocusMaxPosN[0].min = 0; + FocusMaxPosN[0].value = 0; + FocusMaxPosNP.p = IP_RO; + FocusMaxPosNP.timeout = 0; + FocusMaxPosNP.s = IPS_IDLE; + + FocusAbsPosNP.s = IPS_IDLE; + + FocusBacklashN[0].min = 0; + FocusBacklashN[0].max = 1000; + FocusBacklashN[0].step = 1; + FocusBacklashN[0].value = 0; + + ///////////////////////////////////////////////////////////////////////////////////// /// Connection ///////////////////////////////////////////////////////////////////////////////////// @@ -350,6 +373,7 @@ bool CelestronAUX::initProperties() FirmwareTP[FW_AZM].fill("Ra/AZM version", "", nullptr); FirmwareTP[FW_ALT].fill("Dec/ALT version", "", nullptr); FirmwareTP[FW_WiFi].fill("WiFi version", "", nullptr); + FirmwareTP[FW_FOCUS].fill("Focuser version", "", nullptr); FirmwareTP[FW_BAT].fill("Battery version", "", nullptr); FirmwareTP[FW_GPS].fill("GPS version", "", nullptr); FirmwareTP.fill(getDeviceName(), "Firmware Info", "Firmware Info", MOUNTINFO_TAB, IP_RO, 0, IPS_IDLE); @@ -494,7 +518,7 @@ bool CelestronAUX::updateProperties() getModel(AZM); getVersions(); // display firmware versions - char fwText[16] = {0}; + char fwText[24] = {0}; formatModelString(fwText, sizeof(fwText), m_ModelVersion); FirmwareTP[FW_MODEL].setText(fwText); formatVersionString(fwText, 10, m_HCVersion); @@ -511,8 +535,71 @@ bool CelestronAUX::updateProperties() FirmwareTP[FW_BAT].setText(fwText); formatVersionString(fwText, 10, m_GPSVersion); FirmwareTP[FW_GPS].setText(fwText); + formatVersionString(fwText, 10, m_FocusVersion); + FirmwareTP[FW_FOCUS].setText(fwText); defineProperty(FirmwareTP); + bool hasFocuser = false; + for(size_t i = 0; i < sizeof(m_FocusVersion); i++){ + if (m_FocusVersion[i]){ + hasFocuser = true; + LOG_INFO("Detected AUX focuser"); + break; + } + } + + if(hasFocuser){ + m_FocusLimitMin = 0xffffffff; + m_FocusLimitMax = 0; + getFocusLimits(); + + if(m_FocusLimitMax > m_FocusLimitMin){ + + LOGF_DEBUG("Received focuser calibration limits: max %i, min %i", m_FocusLimitMax, m_FocusLimitMin); + + FocusMaxPosN->value = m_FocusLimitMax - m_FocusLimitMin; + FocusMaxPosNP.s = IPS_OK; + + FocusAbsPosN->max = FocusMaxPosN->value; + IUUpdateMinMax(&FocusAbsPosNP); + + FI::SetCapability(FOCUSER_CAN_ABS_MOVE | FOCUSER_CAN_REL_MOVE | FOCUSER_CAN_ABORT ); + setDriverInterface(getDriverInterface() | FOCUSER_INTERFACE); + syncDriverInfo(); + + getFocusPosition(); + FocusAbsPosN->value = m_FocusTarget = m_FocusPosition - m_FocusLimitMin; + FocusAbsPosNP.s = IPS_OK; + + m_FocusEnabled = true; + LOG_INFO("AUX focuser enabled"); + + + } + else{ + + LOG_WARN("No valid focuser calibration received"); + + + // FocusMinPosNP[0].setValue(FocusMinPosNP[0].min); + // FocusMinPosNP.setState(IPS_ALERT); + // defineProperty(FocusMinPosNP); + + FocusMaxPosN->value = FocusMaxPosN->max; + FocusMaxPosNP.s = IPS_ALERT; + + m_FocusEnabled = false; + LOG_INFO("AUX focuser disabled"); + + } + + FI::updateProperties(); + + } + + + + // When no HC is attached, the following three commands needs to be send // to the motor controller (MC): MC_SET_POSITION, MC_SET_CORDWRAP_POSITION // and MC_CORDWRAP_ON. These three commands are also send by the HC @@ -584,6 +671,8 @@ bool CelestronAUX::updateProperties() } deleteProperty(FirmwareTP.getName()); + + FI::updateProperties(); } return true; @@ -744,6 +833,13 @@ bool CelestronAUX::ISNewNumber(const char *dev, const char *name, double values[ // Process Alignment Properties ProcessAlignmentNumberProperties(this, name, values, names, n); + + // Process Focus Properties + if (strstr(name, "FOCUS_")) + { + return FI::processNumber(dev, name, values, names, n); + } + } return INDI::Telescope::ISNewNumber(dev, name, values, names, n); @@ -892,6 +988,13 @@ bool CelestronAUX::ISNewSwitch(const char *dev, const char *name, ISState *state // Process alignment properties ProcessAlignmentSwitchProperties(this, name, states, names, n); + + // Process Focus Properties + if (strstr(name, "FOCUS_")) + { + return FI::processSwitch(dev, name, states, names, n); + } + } return INDI::Telescope::ISNewSwitch(dev, name, states, names, n); @@ -1036,6 +1139,7 @@ bool CelestronAUX::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) m_AxisStatus[AXIS_ALT] = (command == MOTION_START) ? SLEWING : STOPPED; ScopeStatus = SLEWING_MANUAL; TrackState = SCOPE_SLEWING; + m_ManualMotionActive |= (command == MOTION_START); if (command == MOTION_START) { return slewByRate(AXIS_ALT, ((m_AxisDirection[AXIS_ALT] == FORWARD) ? 1 : -1) * rate); @@ -1057,6 +1161,7 @@ bool CelestronAUX::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) m_AxisStatus[AXIS_AZ] = (command == MOTION_START) ? SLEWING : STOPPED; ScopeStatus = SLEWING_MANUAL; TrackState = SCOPE_SLEWING; + m_ManualMotionActive |= (command == MOTION_START); if (command == MOTION_START) { return slewByRate(AXIS_AZ, ((m_AxisDirection[AXIS_AZ] == FORWARD) ? 1 : -1) * rate); @@ -1122,6 +1227,43 @@ bool CelestronAUX::guidePulse(INDI_EQ_AXIS axis, uint32_t ms, int8_t rate) return true; } +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::AbortFocuser(){ + + if (focusByRate(0)){ + m_FocusStatus = STOPPED; + return true; + } + else + return false; + +} + +IPState CelestronAUX::MoveRelFocuser(FocusDirection dir, uint32_t ticks){ + + return MoveAbsFocuser(dir == FOCUS_OUTWARD ? FocusAbsPosN->value + ticks: FocusAbsPosN->value - ticks); + +} + +IPState CelestronAUX::MoveAbsFocuser(uint32_t targetTicks) +{ + if (!m_FocusEnabled) + { + LOG_ERROR("Move is not allowed because the focuser is not calibrated"); + return IPS_ALERT; + } + + getFocusPosition(); + if (targetTicks == m_FocusPosition - m_FocusLimitMin) + return IPS_OK; + else{ + focusTo(m_FocusTarget = targetTicks + m_FocusLimitMin); + return IPS_BUSY; + } +} + ///////////////////////////////////////////////////////////////////////////////////// /// @@ -1698,6 +1840,37 @@ void CelestronAUX::TimerHit() HomeSP.apply(); } } + + // update Focus + if(m_FocusEnabled && isConnected()){ + + // poll position to detect changes due to HC use or motor overrun (e.g. after abort) + getFocusPosition(); + + // update client only if changed to reduce traffic + uint32_t newFocusAbsPos = m_FocusPosition - m_FocusLimitMin; + if (newFocusAbsPos != FocusAbsPosN->value){ + FocusAbsPosN->value = newFocusAbsPos; + IDSetNumber(&FocusAbsPosNP, nullptr); + } + + if(m_FocusStatus == SLEWING){ + getFocusStatus(); + + if (m_FocusStatus == STOPPED){ + + if (FocusAbsPosNP.s == IPS_BUSY){ + FocusAbsPosNP.s = IPS_OK; + IDSetNumber(&FocusAbsPosNP, nullptr); + } + if (FocusRelPosNP.s == IPS_BUSY){ + FocusRelPosNP.s = IPS_OK; + FocusRelPosN->value = 0; + IDSetNumber(&FocusRelPosNP, nullptr); + } + } + } + } } ///////////////////////////////////////////////////////////////////////////////////// @@ -2177,6 +2350,7 @@ void CelestronAUX::getVersions() getVersion(ALT); getVersion(GPS); getVersion(WiFi); + getVersion(FOCUS); getVersion(BAT); // These are the same as battery controller @@ -2186,6 +2360,74 @@ void CelestronAUX::getVersions() //getVersion(ANY); } +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::getFocusLimits() +{ + AUXCommand cmd(FOC_GET_HS_POSITIONS, APP, FOCUS); + if (! sendAUXCommand(cmd)) + return false; + if (! readAUXResponse(cmd)) + return false; + return true; +}; + +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::getFocusStatus() +{ + AUXCommand cmd(MC_SLEW_DONE, APP, FOCUS); + if (! sendAUXCommand(cmd)) + return false; + if (! readAUXResponse(cmd)) + return false; + return true; +}; + +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::getFocusPosition() +{ + AUXCommand cmd(MC_GET_POSITION, APP, FOCUS); + if (! sendAUXCommand(cmd)) + return false; + if (! readAUXResponse(cmd)) + return false; + return true; +}; + +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::focusTo(uint32_t steps) +{ + AUXCommand cmd(MC_GOTO_FAST, APP, FOCUS); + cmd.setData(steps, 3); + if (! sendAUXCommand(cmd)) + return false; + m_FocusStatus = SLEWING; + if (! readAUXResponse(cmd)) + return false; + return true; +}; +///////////////////////////////////////////////////////////////////////////////////// +/// +///////////////////////////////////////////////////////////////////////////////////// +bool CelestronAUX::focusByRate(int8_t rate) +{ + + AUXCommand cmd(rate >= 0 ? MC_MOVE_POS : MC_MOVE_NEG, APP, FOCUS); + cmd.setData(std::abs(rate), 1); + if (! sendAUXCommand(cmd)) + return false; + if (! readAUXResponse(cmd)) + return false; + return true; +}; + ///////////////////////////////////////////////////////////////////////////////////// /// ///////////////////////////////////////////////////////////////////////////////////// @@ -2564,6 +2806,9 @@ bool CelestronAUX::processResponse(AUXCommand &m) case AZM: EncoderNP[AXIS_AZ].setValue(m.getData()); break; + case FOCUS: + m_FocusPosition = m.getData(); + break; default: break; } @@ -2577,6 +2822,9 @@ bool CelestronAUX::processResponse(AUXCommand &m) case AZM: m_AxisStatus[AXIS_AZ] = (m.getData() == 0xff) ? STOPPED : SLEWING; break; + case FOCUS: + m_FocusStatus = (m.getData() == 0xff) ? STOPPED : SLEWING; + break; default: break; } @@ -2650,6 +2898,13 @@ bool CelestronAUX::processResponse(AUXCommand &m) } break; + case FOC_GET_HS_POSITIONS: + { + m_FocusLimitMin = (m.data()[0] << 24) | (m.data()[1] << 16) | (m.data()[2] << 8) | m.data()[3]; + m_FocusLimitMax = (m.data()[4] << 24) | (m.data()[5] << 16) | (m.data()[6] << 8) | m.data()[7]; + } + break; + case GET_VER: { uint8_t *verBuf = nullptr; @@ -2677,6 +2932,9 @@ bool CelestronAUX::processResponse(AUXCommand &m) case GPS: verBuf = m_GPSVersion; break; + case FOCUS: + verBuf = m_FocusVersion; + break; case APP: LOGF_DEBUG("Got echo of GET_VERSION from %s", m.moduleName(m.destination())); break; diff --git a/indi-celestronaux/celestronaux.h b/indi-celestronaux/celestronaux.h index 41c8a35d9..d3d226f5a 100644 --- a/indi-celestronaux/celestronaux.h +++ b/indi-celestronaux/celestronaux.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,7 @@ class CelestronAUX : public INDI::Telescope, public INDI::GuiderInterface, + public INDI::FocuserInterface, public INDI::AlignmentSubsystem::AlignmentSubsystemForDrivers { public: @@ -133,6 +135,10 @@ class CelestronAUX : virtual IPState GuideEast(uint32_t ms) override; virtual IPState GuideWest(uint32_t ms) override; + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override; + virtual IPState MoveAbsFocuser (uint32_t targetTicks) override; + virtual bool AbortFocuser () override; + //virtual bool HandleGetAutoguideRate(INDI_HO_AXIS axis, uint8_t rate); //virtual bool HandleSetAutoguideRate(INDI_EQ_AXIS axis); //virtual bool HandleGuidePulse(INDI_EQ_AXIS axis); @@ -217,6 +223,15 @@ class CelestronAUX : bool setCordWrapPosition(uint32_t steps); uint32_t getCordWrapPosition(); + ///////////////////////////////////////////////////////////////////////////////////// + /// Focus + ///////////////////////////////////////////////////////////////////////////////////// + bool getFocusLimits(); + bool getFocusPosition(); + bool getFocusStatus(); + bool focusTo(uint32_t steps); + bool focusByRate(int8_t rate); + private: ///////////////////////////////////////////////////////////////////////////////////// /// Misc @@ -317,12 +332,22 @@ class CelestronAUX : uint8_t m_BATVersion[4] {0}; uint8_t m_WiFiVersion[4] {0}; uint8_t m_GPSVersion[4] {0}; + uint8_t m_FocusVersion[4] {0}; // Coord Wrap bool m_CordWrapActive {false}; int32_t m_CordWrapPosition {0}; uint32_t m_RequestedCordwrapPos; + // Focus + bool m_FocusEnabled {false}; + uint32_t m_FocusTarget {0}; + uint32_t m_FocusPosition {0}; + uint32_t m_FocusLimitMax {0}; + uint32_t m_FocusLimitMin {0xffffffff}; + AxisStatus m_FocusStatus {STOPPED}; + + // Manual Slewing NSWE bool m_ManualMotionActive { false }; @@ -352,8 +377,8 @@ class CelestronAUX : /////////////////////////////////////////////////////////////////////////////// // Firmware - INDI::PropertyText FirmwareTP {8}; - enum {FW_MODEL, FW_HC, FW_MB, FW_AZM, FW_ALT, FW_WiFi, FW_BAT, FW_GPS}; + INDI::PropertyText FirmwareTP {9}; + enum {FW_MODEL, FW_HC, FW_MB, FW_AZM, FW_ALT, FW_WiFi, FW_BAT, FW_GPS, FW_FOCUS}; // Mount type //INDI::PropertySwitch MountTypeSP {3};