bool ScopeASCOM::GetCoordinates(double *ra, double *dec, double *siderealTime) { bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get coordinates when not connected"); } if (!m_bCanGetCoordinates) { throw THROW_INFO("ASCOM Scope: not capable of getting coordinates"); } GITObjRef scope(m_gitEntry); Variant vRA; if (!scope.GetProp(&vRA, dispid_rightascension)) { throw ERROR_INFO("ASCOM Scope: get right ascension failed: " + ExcepMsg(scope.Excep())); } Variant vDec; if (!scope.GetProp(&vDec, dispid_declination)) { throw ERROR_INFO("ASCOM Scope: get declination failed: " + ExcepMsg(scope.Excep())); } Variant vST; if (!scope.GetProp(&vST, dispid_siderealtime)) { throw ERROR_INFO("ASCOM Scope: get sidereal time failed: " + ExcepMsg(scope.Excep())); } *ra = vRA.dblVal; *dec = vDec.dblVal; *siderealTime = vST.dblVal; } catch (wxString Msg) { bError = true; POSSIBLY_UNUSED(Msg); } return bError; }
bool ScopeASCOM::IsGuiding(DispatchObj *scope) { bool bReturn = true; try { if (!m_bCanCheckPulseGuiding) { // Assume all is good - best we can do as this is really a fail-safe check. If we can't call this property (lame driver) guides will have to // enforce the wait. But, enough don't support this that we can't throw an error. throw ERROR_INFO("ASCOM Scope: IsGuiding - !m_bCanCheckPulseGuiding"); } // First, check to see if already moving Variant vRes; if (!scope->GetProp(&vRes, dispid_ispulseguiding)) { pFrame->Alert(_("ASCOM driver failed checking IsPulseGuiding")); throw ERROR_INFO("ASCOM Scope: IsGuiding - IsPulseGuiding failed: " + ExcepMsg(scope->Excep())); } bReturn = vRes.boolVal == VARIANT_TRUE; } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); bReturn = false; } Debug.AddLine("IsGuiding returns %d", bReturn); return bReturn; }
// Return RA and Dec guide rates in native ASCOM units, degrees/sec. // Convention is to return true on an error bool ScopeASCOM::GetGuideRates(double *pRAGuideRate, double *pDecGuideRate) { bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get guide rates when not connected"); } if (!m_bCanGetGuideRates) { throw THROW_INFO("ASCOM Scope: not capable of getting guide rates"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_decguiderate)) { throw ERROR_INFO("ASCOM Scope: GuideRateDec() failed: " + ExcepMsg(scope.Excep())); } *pDecGuideRate = vRes.dblVal; if (!scope.GetProp(&vRes, dispid_raguiderate)) { throw ERROR_INFO("ASCOM Scope: GuideRateRA() failed: " + ExcepMsg(scope.Excep())); } *pRAGuideRate = vRes.dblVal; } catch (wxString Msg) { bError = true; POSSIBLY_UNUSED(Msg); } Debug.AddLine("ScopeASCOM::GetGuideRates() returns %u %.4f %.4f", bError, bError ? 0.0 : *pDecGuideRate, bError ? 0.0 : *pRAGuideRate); return bError; }
bool Entry() { GITObjRef scope(sa->m_gitEntry); // ... set the Connected property to true.... if (!scope.PutProp(sa->dispid_connected, true)) { SetErrorMsg(ExcepMsg(scope.Excep())); return true; } return false; }
bool Entry() { GITObjRef dobj(cam->m_gitEntry); // ... set the Connected property to true.... if (!dobj.PutProp(L"Connected", true)) { SetErrorMsg(ExcepMsg(dobj.Excep())); return true; } return false; }
bool ScopeASCOM::GetSiteLatLong(double *latitude, double *longitude) { if (dispid_sitelatitude == DISPID_UNKNOWN || dispid_sitelongitude == DISPID_UNKNOWN) return true; bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get site latitude/longitude when not connected"); } GITObjRef scope(m_gitEntry); Variant vLat; if (!scope.GetProp(&vLat, dispid_sitelatitude)) { throw ERROR_INFO("ASCOM Scope: get site latitude failed: " + ExcepMsg(scope.Excep())); } Variant vLong; if (!scope.GetProp(&vLong, dispid_sitelongitude)) { throw ERROR_INFO("ASCOM Scope: get site longitude failed: " + ExcepMsg(scope.Excep())); } *latitude = vLat.dblVal; *longitude = vLong.dblVal; } catch (wxString Msg) { bError = true; POSSIBLY_UNUSED(Msg); } return bError; }
void Camera_ASCOMLateClass::ShowPropertyDialog(void) { DispatchObj camera; if (Create(&camera, NULL)) { Variant res; if (!camera.InvokeMethod(&res, L"SetupDialog")) { pFrame->Alert(ExcepMsg(camera.Excep())); } } }
static bool ChooseASCOMScope(BSTR *res) { DispatchObj chooser; if (!chooser.Create(L"DriverHelper.Chooser")) { Debug.AddLine("Chooser instantiate failed: " + ExcepMsg(chooser.Excep())); wxMessageBox(_("Failed to find the ASCOM Chooser. Make sure it is installed"), _("Error"), wxOK | wxICON_ERROR); return false; } if (!chooser.PutProp(L"DeviceType", L"Telescope")) { Debug.AddLine("Chooser put prop failed: " + ExcepMsg(chooser.Excep())); wxMessageBox(_("Failed to set the Chooser's type to Telescope. Something is wrong with ASCOM"), _("Error"), wxOK | wxICON_ERROR); return false; } // Look in Registry to see if there is a default wxString wx_ProgID = pConfig->Global.GetString("/scope/ascom/ScopeID", _T("")); BSTR bstr_ProgID = wxBasicString(wx_ProgID).Get(); Variant vchoice; if (!chooser.InvokeMethod(&vchoice, L"Choose", bstr_ProgID)) { wxMessageBox(_("Failed to run the Telescope Chooser. Something is wrong with ASCOM"), _("Error"), wxOK | wxICON_ERROR); return false; } if (SysStringLen(vchoice.bstrVal) == 0) return false; // use hit cancel // Save name of scope pConfig->Global.SetString("/scope/ascom/ScopeID", vchoice.bstrVal); *res = vchoice.bstrVal; return true; }
bool Camera_ASCOMLateClass::Disconnect() { if (!Connected) { Debug.AddLine("ASCOM camera: attempt to disconnect when not connected"); return false; } { // scope GITObjRef cam(m_gitEntry); if (!cam.PutProp(L"Connected", false)) { Debug.AddLine(ExcepMsg("ASCOM disconnect", cam.Excep())); pFrame->Alert(ExcepMsg(_("ASCOM driver problem -- cannot disconnect"), cam.Excep())); return true; } } // scope m_gitEntry.Unregister(); Connected = false; return false; }
bool ScopeASCOM::IsSlewing(DispatchObj *scope) { Variant vRes; if (!scope->GetProp(&vRes, dispid_isslewing)) { Debug.AddLine("ScopeASCOM::IsSlewing failed: " + ExcepMsg(scope->Excep())); pFrame->Alert(_("ASCOM driver failed checking Slewing")); return false; } bool result = vRes.boolVal == VARIANT_TRUE; Debug.AddLine("IsSlewing returns %d", result); return result; }
static bool ASCOM_IsMoving(IDispatch *cam) { DISPPARAMS dispParms; dispParms.cArgs = 0; dispParms.rgvarg = NULL; dispParms.cNamedArgs = 0; dispParms.rgdispidNamedArgs = NULL; HRESULT hr; EXCEPINFO excep; Variant vRes; if (FAILED(hr = cam->Invoke(dispid_ispulseguiding, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParms, &vRes, &excep, NULL))) { LogExcep(hr, "invoke ispulseguiding", excep); pFrame->Alert(ExcepMsg(_("ASCOM driver failed checking IsPulseGuiding. See the debug log for more information."), excep)); return false; } return vRes.boolVal == VARIANT_TRUE; }
PierSide ScopeASCOM::SideOfPier(void) { PierSide pierSide = PIER_SIDE_UNKNOWN; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get side of pier when not connected"); } if (dispid_sideofpier == DISPID_UNKNOWN) { throw THROW_INFO("ASCOM Scope: not capable of getting side of pier"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_sideofpier)) { throw ERROR_INFO("ASCOM Scope: SideOfPier failed: " + ExcepMsg(scope.Excep())); } switch (vRes.intVal) { case 0: pierSide = PIER_SIDE_EAST; break; case 1: pierSide = PIER_SIDE_WEST; break; } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); } Debug.AddLine("ScopeASCOM::SideOfPier() returns %d", pierSide); return pierSide; }
// Special purpose function to return the guiding declination (radians) - either the actual scope position or the // default values defined in mount.cpp. Doesn't throw exceptions to callers. double ScopeASCOM::GetGuidingDeclination(void) { double dReturn = Scope::GetDefGuidingDeclination(); try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get Declination when not connected to mount"); } if (!m_bCanGetCoordinates) { throw THROW_INFO("!m_bCanGetCoordinates"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_declination)) { throw ERROR_INFO("GetDeclination() fails: " + ExcepMsg(scope.Excep())); } dReturn = radians(vRes.dblVal); } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); m_bCanGetCoordinates = false; } Debug.AddLine("ScopeASCOM::GetDeclination() returns %.1f", degrees(dReturn)); return dReturn; }
bool ScopeASCOM::Connect(void) { bool bError = false; try { Debug.AddLine("Connecting"); if (IsConnected()) { wxMessageBox("Scope already connected",_("Error")); throw ERROR_INFO("ASCOM Scope: Connected - Already Connected"); } DispatchObj pScopeDriver; if (!Create(pScopeDriver)) { wxMessageBox(_T("Could not establish instance of ") + m_choice, _("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not establish ASCOM Scope instance"); } // --- get the dispatch IDs we need ... // ... get the dispatch ID for the Connected property ... if (!pScopeDriver.GetDispatchId(&dispid_connected, L"Connected")) { wxMessageBox(_T("ASCOM driver problem -- cannot connect"),_("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not get the dispatch id for the Connected property"); } // ... get the dispatch ID for the "IsPulseGuiding" property .... m_bCanCheckPulseGuiding = true; if (!pScopeDriver.GetDispatchId(&dispid_ispulseguiding, L"IsPulseGuiding")) { m_bCanCheckPulseGuiding = false; Debug.AddLine("cannot get dispid_ispulseguiding"); // don't fail if we can't get the status on this - can live without it as it's really a safety net for us } // ... get the dispatch ID for the "Slewing" property .... if (!pScopeDriver.GetDispatchId(&dispid_isslewing, L"Slewing")) { wxMessageBox(_T("ASCOM driver missing the Slewing property"),_("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not get the dispatch id for the Slewing property"); } // ... get the dispatch ID for the "PulseGuide" property .... if (!pScopeDriver.GetDispatchId(&dispid_pulseguide, L"PulseGuide")) { wxMessageBox(_T("ASCOM driver missing the PulseGuide property"),_("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not get the dispatch id for the PulseGuide property"); } // ... get the dispatch ID for the "Declination" property .... m_bCanGetCoordinates = true; if (!pScopeDriver.GetDispatchId(&dispid_declination, L"Declination")) { m_bCanGetCoordinates = false; Debug.AddLine("cannot get dispid_declination"); } else if (!pScopeDriver.GetDispatchId(&dispid_rightascension, L"RightAscension")) { Debug.AddLine("cannot get dispid_rightascension"); m_bCanGetCoordinates = false; } else if (!pScopeDriver.GetDispatchId(&dispid_siderealtime, L"SiderealTime")) { Debug.AddLine("cannot get dispid_siderealtime"); m_bCanGetCoordinates = false; } if (!pScopeDriver.GetDispatchId(&dispid_sitelatitude, L"SiteLatitude")) { Debug.AddLine("cannot get dispid_sitelatitude"); } if (!pScopeDriver.GetDispatchId(&dispid_sitelongitude, L"SiteLongitude")) { Debug.AddLine("cannot get dispid_sitelongitude"); } m_bCanSlew = true; if (!pScopeDriver.GetDispatchId(&dispid_slewtocoordinates, L"SlewToCoordinates")) { m_bCanSlew = false; Debug.AddLine("cannot get dispid_slewtocoordinates"); } // ... get the dispatch IDs for the two guide rate properties - if we can't get them, no sweat, doesn't matter for actual guiding // Used for things like calibration sanity checking, backlash clearing, etc. m_bCanGetGuideRates = true; // Likely case, required for any ASCOM driver at V2 or later if (!pScopeDriver.GetDispatchId(&dispid_decguiderate, L"GuideRateDeclination")) { Debug.AddLine("cannot get dispid_decguiderate"); m_bCanGetGuideRates = false; // don't throw if we can't get this one } else if (!pScopeDriver.GetDispatchId(&dispid_raguiderate, L"GuideRateRightAscension")) { Debug.AddLine("cannot get dispid_raguiderate"); m_bCanGetGuideRates = false; // don't throw if we can't get this one } if (!pScopeDriver.GetDispatchId(&dispid_sideofpier, L"SideOfPier")) { Debug.AddLine("cannot get dispid_sideofpier"); dispid_sideofpier = DISPID_UNKNOWN; } if (!pScopeDriver.GetDispatchId(&dispid_abortslew, L"AbortSlew")) { Debug.AddLine("cannot get dispid_abortslew"); dispid_abortslew = DISPID_UNKNOWN; } struct ConnectInBg : public ConnectMountInBg { ScopeASCOM *sa; ConnectInBg(ScopeASCOM *sa_) : sa(sa_) { } bool Entry() { GITObjRef scope(sa->m_gitEntry); // ... set the Connected property to true.... if (!scope.PutProp(sa->dispid_connected, true)) { SetErrorMsg(ExcepMsg(scope.Excep())); return true; } return false; } }; ConnectInBg bg(this); // set the Connected property to true in a background thread if (bg.Run()) { wxMessageBox(_T("ASCOM driver problem during connection: ") + bg.GetErrorMsg(), _("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not set Connected property to true"); } // get the scope name Variant vRes; if (!pScopeDriver.GetProp(&vRes, L"Name")) { wxMessageBox(_T("ASCOM driver problem getting Name property"), _("Error"), wxOK | wxICON_ERROR); throw ERROR_INFO("ASCOM Scope: Could not get the scope name: " + ExcepMsg(pScopeDriver.Excep())); } m_Name = vRes.bstrVal; Debug.AddLine("Scope reports its name as " + m_Name); m_abortSlewWhenGuidingStuck = false; if (m_Name == _T("Gemini Telescope .NET")) { // Gemini2 firmware (2013 Oct 13 version, perhaps others) has been found to contain a // bug where a pulse guide command can fail to complete, with the Guiding property // returning true forever. The firmware developer suggests that PHD2 should issue an // AbortSlew when this condition is detected. Debug.AddLine("ASCOM scope: enabling stuck guide pulse workaround"); m_abortSlewWhenGuidingStuck = true; } // see if we can pulse guide m_bCanPulseGuide = true; if (!pScopeDriver.GetProp(&vRes, L"CanPulseGuide") || !vRes.boolVal) { Debug.AddLine("Connecting to ASCOM scope that does not support PulseGuide"); m_bCanPulseGuide = false; } // see if we can slew if (m_bCanSlew) { if (!pScopeDriver.GetProp(&vRes, L"CanSlew")) { Debug.AddLine("ASCOM scope got error invoking CanSlew: " + ExcepMsg(pScopeDriver.Excep())); m_bCanSlew = false; } else if (!vRes.boolVal) { Debug.AddLine("ASCOM scope reports CanSlew = false"); m_bCanSlew = false; } } pFrame->SetStatusText(Name()+_(" connected")); Scope::Connect(); Debug.AddLine("Connect success"); } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); bError = true; } return bError; }
wxArrayString ScopeASCOM::EnumAscomScopes() { wxArrayString list; try { DispatchObj profile; if (!profile.Create(L"ASCOM.Utilities.Profile")) throw ERROR_INFO("ASCOM Scope: could not instantiate ASCOM profile class ASCOM.Utilities.Profile. Is ASCOM installed?"); Variant res; if (!profile.InvokeMethod(&res, L"RegisteredDevices", L"Telescope")) throw ERROR_INFO("ASCOM Scope: could not query registered telescope devices: " + ExcepMsg(profile.Excep())); DispatchClass ilist_class; DispatchObj ilist(res.pdispVal, &ilist_class); Variant vcnt; if (!ilist.GetProp(&vcnt, L"Count")) throw ERROR_INFO("ASCOM Scope: could not query registered telescopes: " + ExcepMsg(ilist.Excep())); // if we made it this far ASCOM is installed and apprears sane, so add the chooser list.Add(_T("ASCOM Telescope Chooser")); unsigned int const count = vcnt.intVal; DispatchClass kvpair_class; for (unsigned int i = 0; i < count; i++) { Variant kvpres; if (ilist.GetProp(&kvpres, L"Item", i)) { DispatchObj kvpair(kvpres.pdispVal, &kvpair_class); Variant vkey, vval; if (kvpair.GetProp(&vkey, L"Key") && kvpair.GetProp(&vval, L"Value")) { wxString ascomName = vval.bstrVal; wxString displName = displayName(ascomName); wxString progid = vkey.bstrVal; s_progid[displName] = progid; list.Add(displName); } } } } catch (const wxString& msg) { POSSIBLY_UNUSED(msg); } return list; }
inline static void LogExcep(HRESULT hr, const wxString& prefix, const EXCEPINFO& excep) { Debug.AddLine(wxString::Format("%s: [%x] %s", prefix, hr, _com_error(hr).ErrorMessage())); if (hr == DISP_E_EXCEPTION) Debug.AddLine(ExcepMsg(prefix, excep)); }
bool Camera_ASCOMLateClass::Capture(int duration, usImage& img, int options, const wxRect& subframeArg) { bool retval = false; bool takeSubframe = UseSubframes; wxRect subframe(subframeArg); if (subframe.width <= 0 || subframe.height <= 0) { takeSubframe = false; } bool binning_changed = false; if (Binning != m_curBin) { FullSize = wxSize(m_maxSize.x / Binning, m_maxSize.y / Binning); binning_changed = true; } // Program the size if (!takeSubframe) { subframe = wxRect(0, 0, FullSize.GetWidth(), FullSize.GetHeight()); } if (img.Init(FullSize)) { pFrame->Alert(_("Cannot allocate memory to download image from camera")); return true; } GITObjRef cam(m_gitEntry); EXCEPINFO excep; if (binning_changed) { if (ASCOM_SetBin(cam.IDisp(), Binning, &excep)) { pFrame->Alert(_("The ASCOM camera failed to set binning. See the debug log for more information.")); return true; } m_curBin = Binning; } if (subframe != m_roi) { ASCOM_SetROI(cam.IDisp(), subframe, &excep); m_roi = subframe; } bool takeDark = HasShutter && ShutterClosed; // Start the exposure if (ASCOM_StartExposure(cam.IDisp(), (double)duration / 1000.0, takeDark, &excep)) { Debug.AddLine(ExcepMsg("ASCOM_StartExposure failed", excep)); pFrame->Alert(ExcepMsg(_("ASCOM error -- Cannot start exposure with given parameters"), excep)); return true; } CameraWatchdog watchdog(duration, GetTimeoutMs()); if (duration > 100) { // wait until near end of exposure if (WorkerThread::MilliSleep(duration - 100, WorkerThread::INT_ANY) && (WorkerThread::TerminateRequested() || AbortExposure())) { return true; } } while (true) // wait for image to finish and d/l { wxMilliSleep(20); bool ready; EXCEPINFO excep; if (ASCOM_ImageReady(cam.IDisp(), &ready, &excep)) { Debug.AddLine(ExcepMsg("ASCOM_ImageReady failed", excep)); pFrame->Alert(ExcepMsg(_("Exception thrown polling camera"), excep)); return true; } if (ready) break; if (WorkerThread::InterruptRequested() && (WorkerThread::TerminateRequested() || AbortExposure())) { return true; } if (watchdog.Expired()) { DisconnectWithAlert(CAPT_FAIL_TIMEOUT); return true; } } // Get the image if (ASCOM_Image(cam.IDisp(), img, takeSubframe, subframe, &excep)) { Debug.AddLine(ExcepMsg(_T("ASCOM_Image failed"), excep)); pFrame->Alert(ExcepMsg(_("Error reading image"), excep)); return true; } if (options & CAPTURE_SUBTRACT_DARK) SubtractDark(img); if (Color && Binning == 1 && (options & CAPTURE_RECON)) QuickLRecon(img); return false; }
bool ScopeASCOM::Disconnect(void) { bool bError = false; try { Debug.AddLine("Disconnecting"); if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: attempt to disconnect when not connected"); } // Setting the Connected property to false will cause the scope to be disconnected for all // ASCOM clients that are connected to the scope, and we do not want this! bool const disconnectAscomDriver = false; if (disconnectAscomDriver) { GITObjRef scope(m_gitEntry); // Set the Connected property to false if (!scope.PutProp(dispid_connected, false)) { pFrame->Alert(_("ASCOM driver problem during disconnect")); throw ERROR_INFO("ASCOM Scope: Could not set Connected property to false: " + ExcepMsg(scope.Excep())); } } m_gitEntry.Unregister(); Debug.AddLine("Disconnected Successfully"); } catch (const wxString& Msg) { POSSIBLY_UNUSED(Msg); bError = true; } Scope::Disconnect(); return bError; }
wxString ExcepMsg(const wxString& prefix, const EXCEPINFO& excep) { return prefix + ":\n" + ExcepMsg(excep); }
Mount::MOVE_RESULT ScopeASCOM::Guide(GUIDE_DIRECTION direction, int duration) { MOVE_RESULT result = MOVE_OK; try { Debug.AddLine("Guiding Dir = %d, Dur = %d", direction, duration); if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: attempt to guide when not connected"); } if (!m_bCanPulseGuide) { // Could happen if move command is issued on the Aux mount or CanPulseGuide property got changed on the fly pFrame->Alert(_("ASCOM driver does not support PulseGuide")); throw ERROR_INFO("ASCOM scope: guide command issued but PulseGuide not supported"); } GITObjRef scope(m_gitEntry); // First, check to see if already moving CheckSlewing(&scope, &result); if (IsGuiding(&scope)) { Debug.AddLine("Entered PulseGuideScope while moving"); int i; for (i = 0; i < 20; i++) { wxMilliSleep(50); CheckSlewing(&scope, &result); if (!IsGuiding(&scope)) break; Debug.AddLine("Still moving"); } if (i == 20) { Debug.AddLine("Still moving after 1s - aborting"); throw ERROR_INFO("ASCOM Scope: scope is still moving after 1 second"); } else { Debug.AddLine("Movement stopped - continuing"); } } // Do the move VARIANTARG rgvarg[2]; rgvarg[1].vt = VT_I2; rgvarg[1].iVal = direction; rgvarg[0].vt = VT_I4; rgvarg[0].lVal = (long) duration; DISPPARAMS dispParms; dispParms.cArgs = 2; dispParms.rgvarg = rgvarg; dispParms.cNamedArgs = 0; dispParms.rgdispidNamedArgs = NULL; wxStopWatch swatch; HRESULT hr; EXCEPINFO excep; Variant vRes; if (FAILED(hr = scope.IDisp()->Invoke(dispid_pulseguide, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParms, &vRes, &excep, NULL))) { Debug.AddLine(wxString::Format("pulseguide: [%x] %s", hr, _com_error(hr).ErrorMessage())); // Make sure nothing got by us and the mount can really handle pulse guide - HIGHLY unlikely if (scope.GetProp(&vRes, L"CanPulseGuide") && !vRes.boolVal) { Debug.AddLine("Tried to guide mount that has no PulseGuide support"); // This will trigger a nice alert the next time through Guide m_bCanPulseGuide = false; } throw ERROR_INFO("ASCOM Scope: pulseguide command failed: " + ExcepMsg(excep)); } long elapsed = swatch.Time(); if (elapsed < (long)duration) { unsigned long rem = (unsigned long)((long)duration - elapsed); Debug.AddLine("PulseGuide returned control before completion, sleep %lu", rem + 10); if (WorkerThread::MilliSleep(rem + 10)) throw ERROR_INFO("ASCOM Scope: thread terminate requested"); } if (IsGuiding(&scope)) { Debug.AddLine("scope still moving after pulse duration time elapsed"); // try waiting a little longer. If scope does not stop moving after 1 second, try doing AbortSlew // if it still does not stop after 2 seconds, bail out with an error enum { GRACE_PERIOD_MS = 1000, TIMEOUT_MS = GRACE_PERIOD_MS + 1000, }; bool timeoutExceeded = false; bool didAbortSlew = false; while (true) { ::wxMilliSleep(20); if (WorkerThread::InterruptRequested()) throw ERROR_INFO("ASCOM Scope: thread interrupt requested"); CheckSlewing(&scope, &result); if (!IsGuiding(&scope)) { Debug.AddLine("scope move finished after %ld + %ld ms", (long)duration, swatch.Time() - (long)duration); break; } long now = swatch.Time(); if (!didAbortSlew && now > duration + GRACE_PERIOD_MS && m_abortSlewWhenGuidingStuck) { Debug.AddLine("scope still moving after %ld + %ld ms, try aborting slew", (long)duration, now - (long)duration); AbortSlew(&scope); didAbortSlew = true; continue; } if (now > duration + TIMEOUT_MS) { timeoutExceeded = true; break; } } if (timeoutExceeded && IsGuiding(&scope)) { throw ERROR_INFO("timeout exceeded waiting for guiding pulse to complete"); } } } catch (const wxString& msg) { POSSIBLY_UNUSED(msg); if (result == MOVE_OK) { result = MOVE_ERROR; pFrame->Alert(_("PulseGuide command to mount has failed - guiding is likely to be ineffective.")); } } if (result == MOVE_STOP_GUIDING) { pFrame->Alert(_("Guiding stopped: the scope started slewing.")); } return result; }
bool ScopeASCOM::Disconnect(void) { bool bError = false; try { Debug.AddLine("Disconnecting"); if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: attempt to disconnect when not connected"); } GITObjRef scope(m_gitEntry); // ... set the Connected property to false.... if (!scope.PutProp(dispid_connected, false)) { pFrame->Alert(_("ASCOM driver problem during disconnect")); throw ERROR_INFO("ASCOM Scope: Could not set Connected property to false: " + ExcepMsg(scope.Excep())); } Debug.AddLine("Disconnected Successfully"); } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); bError = true; } Scope::Disconnect(); return bError; }
bool Camera_ASCOMLateClass::Connect(const wxString& camId) { DispatchClass driver_class; DispatchObj driver(&driver_class); // create the COM object if (!Create(&driver, &driver_class)) { pFrame->Alert(_("Could not create ASCOM camera object. See the debug log for more information.")); return true; } struct ConnectInBg : public ConnectCameraInBg { Camera_ASCOMLateClass *cam; ConnectInBg(Camera_ASCOMLateClass *cam_) : cam(cam_) { } bool Entry() { GITObjRef dobj(cam->m_gitEntry); // ... set the Connected property to true.... if (!dobj.PutProp(L"Connected", true)) { SetErrorMsg(ExcepMsg(dobj.Excep())); return true; } return false; } }; ConnectInBg bg(this); if (bg.Run()) { pFrame->Alert(_("ASCOM driver problem: Connect") + ":\n" + bg.GetErrorMsg()); return true; } Variant vname; if (driver.GetProp(&vname, L"Name")) { Name = vname.bstrVal; Debug.AddLine(wxString::Format("setting camera Name = %s", Name)); } // See if we have an onboard guider output Variant vRes; if (!driver.GetProp(&vRes, L"CanPulseGuide")) { Debug.AddLine(ExcepMsg("CanPulseGuide", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the CanPulseGuide property. Please report this error to your ASCOM driver provider.")); return true; } m_hasGuideOutput = ((vRes.boolVal != VARIANT_FALSE) ? true : false); if (!driver.GetProp(&vRes, L"CanAbortExposure")) { Debug.AddLine(ExcepMsg("CanAbortExposure", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the CanAbortExposure property. Please report this error to your ASCOM driver provider.")); return true; } m_canAbortExposure = vRes.boolVal != VARIANT_FALSE ? true : false; if (!driver.GetProp(&vRes, L"CanStopExposure")) { Debug.AddLine(ExcepMsg("CanStopExposure", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the CanStopExposure property. Please report this error to your ASCOM driver provider.")); return true; } m_canStopExposure = vRes.boolVal != VARIANT_FALSE ? true : false; // Check if we have a shutter if (driver.GetProp(&vRes, L"HasShutter")) { HasShutter = ((vRes.boolVal != VARIANT_FALSE) ? true : false); } // Get the image size of a full frame if (!driver.GetProp(&vRes, L"CameraXSize")) { Debug.AddLine(ExcepMsg("CameraXSize", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the CameraXSize property. Please report this error to your ASCOM driver provider.")); return true; } m_maxSize.SetWidth((int) vRes.lVal); if (!driver.GetProp(&vRes, L"CameraYSize")) { Debug.AddLine(ExcepMsg("CameraYSize", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the CameraYSize property. Please report this error to your ASCOM driver provider.")); return true; } m_maxSize.SetHeight((int) vRes.lVal); if (!driver.GetProp(&vRes, L"MaxADU")) { Debug.AddLine(ExcepMsg("MaxADU", driver.Excep())); m_bitsPerPixel = 16; // assume 16 BPP } else { m_bitsPerPixel = vRes.intVal <= 255 ? 8 : 16; } // Get the interface version of the driver DriverVersion = 1; if (driver.GetProp(&vRes, L"InterfaceVersion")) { DriverVersion = vRes.iVal; } if (DriverVersion > 1 && // We can check the color sensor status of the cam driver.GetProp(&vRes, L"SensorType") && vRes.iVal > 1) { Color = true; } // Get pixel size in micons if (!driver.GetProp(&vRes, L"PixelSizeX")) { Debug.AddLine(ExcepMsg("PixelSizeX", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the PixelSizeX property. Please report this error to your ASCOM driver provider.")); return true; } PixelSize = (double) vRes.dblVal; if (!driver.GetProp(&vRes, L"PixelSizeY")) { Debug.AddLine(ExcepMsg("PixelSizeY", driver.Excep())); pFrame->Alert(_("ASCOM driver missing the PixelSizeY property. Please report this error to your ASCOM driver provider.")); return true; } if ((double) vRes.dblVal > PixelSize) PixelSize = (double) vRes.dblVal; short maxBinX = 1, maxBinY = 1; if (driver.GetProp(&vRes, L"MaxBinX")) maxBinX = vRes.iVal; if (driver.GetProp(&vRes, L"MaxBinY")) maxBinY = vRes.iVal; MaxBinning = wxMin(maxBinX, maxBinY); Debug.AddLine("ASCOM camera: MaxBinning is %hu", MaxBinning); if (Binning > MaxBinning) Binning = MaxBinning; m_curBin = Binning; // Get the dispids we'll need for more routine things if (!GetDispid(&dispid_setxbin, driver, L"BinX")) return true; if (!GetDispid(&dispid_setybin, driver, L"BinY")) return true; if (!GetDispid(&dispid_startx, driver, L"StartX")) return true; if (!GetDispid(&dispid_starty, driver, L"StartY")) return true; if (!GetDispid(&dispid_numx, driver, L"NumX")) return true; if (!GetDispid(&dispid_numy, driver, L"NumY")) return true; if (!GetDispid(&dispid_imageready, driver, L"ImageReady")) return true; if (!GetDispid(&dispid_imagearray, driver, L"ImageArray")) return true; if (!GetDispid(&dispid_startexposure, driver, L"StartExposure")) return true; if (!GetDispid(&dispid_abortexposure, driver, L"AbortExposure")) return true; if (!GetDispid(&dispid_stopexposure, driver, L"StopExposure")) return true; if (!GetDispid(&dispid_pulseguide, driver, L"PulseGuide")) return true; if (!GetDispid(&dispid_ispulseguiding, driver, L"IsPulseGuiding")) return true; // Program some defaults -- full size and binning EXCEPINFO excep; if (ASCOM_SetBin(driver.IDisp(), Binning, &excep)) { // only make this error fatal if the camera supports binning > 1 if (MaxBinning > 1) { pFrame->Alert(_("The ASCOM camera failed to set binning. See the debug log for more information.")); return true; } } FullSize = wxSize(m_maxSize.x / Binning, m_maxSize.y / Binning); m_roi = FullSize; ASCOM_SetROI(driver.IDisp(), FullSize, &excep); Connected = true; return false; }