// Define the repainting behaviour
void GuiderOneStar::OnPaint(wxPaintEvent& event)
{
    //wxAutoBufferedPaintDC dc(this);
    wxClientDC dc(this);
    wxMemoryDC memDC;

    try
    {
        if (PaintHelper(dc, memDC))
        {
            throw ERROR_INFO("PaintHelper failed");
        }
        // PaintHelper drew the image and any overlays
        // now decorate the image to show the selection

        // display bookmarks
        if (m_showBookmarks && m_bookmarks.size() > 0)
        {
            dc.SetPen(wxPen(wxColour(0,255,255),1,wxSOLID));
            dc.SetBrush(*wxTRANSPARENT_BRUSH);

            for (std::vector<wxRealPoint>::const_iterator it = m_bookmarks.begin();
                 it != m_bookmarks.end(); ++it)
            {
                wxPoint p((int)(it->x * m_scaleFactor), (int)(it->y * m_scaleFactor));
                dc.DrawCircle(p, 3);
                dc.DrawCircle(p, 6);
                dc.DrawCircle(p, 12);
            }
        }

        GUIDER_STATE state = GetState();
        bool FoundStar = m_star.WasFound();

        if (state == STATE_SELECTED)
        {
            if (FoundStar)
                dc.SetPen(wxPen(wxColour(100,255,90), 1, wxSOLID));  // Draw the box around the star
            else
                dc.SetPen(wxPen(wxColour(230,130,30), 1, wxDOT));
            DrawBox(dc, m_star, m_searchRegion, m_scaleFactor);
        }
        else if (state == STATE_CALIBRATING_PRIMARY || state == STATE_CALIBRATING_SECONDARY)
        {
            // in the calibration process
            dc.SetPen(wxPen(wxColour(32,196,32), 1, wxSOLID));  // Draw the box around the star
            DrawBox(dc, m_star, m_searchRegion, m_scaleFactor);
        }
        else if (state == STATE_CALIBRATED || state == STATE_GUIDING)
        {
            // locked and guiding
            if (FoundStar)
                dc.SetPen(wxPen(wxColour(32,196,32), 1, wxSOLID));  // Draw the box around the star
            else
                dc.SetPen(wxPen(wxColour(230,130,30), 1, wxDOT));
            DrawBox(dc, m_star, m_searchRegion, m_scaleFactor);
        }

        // Image logging
        if (state >= STATE_SELECTED && pFrame->IsImageLoggingEnabled() && pFrame->m_frameCounter != pFrame->m_loggedImageFrame)
        {
            // only log each image frame once
            pFrame->m_loggedImageFrame = pFrame->m_frameCounter;

            if (pFrame->GetLoggedImageFormat() == LIF_RAW_FITS) // Save star image as a FITS
            {
                SaveStarFITS();
            }
            else  // Save star image as a JPEG
            {
                double LockX = LockPosition().X;
                double LockY = LockPosition().Y;

                wxBitmap SubBmp(60,60,-1);
                wxMemoryDC tmpMdc;
                tmpMdc.SelectObject(SubBmp);
                memDC.SetPen(wxPen(wxColor(0,255,0),1,wxDOT));
                memDC.DrawLine(0, LockY * m_scaleFactor, XWinSize, LockY * m_scaleFactor);
                memDC.DrawLine(LockX*m_scaleFactor, 0, LockX*m_scaleFactor, YWinSize);
    #ifdef __APPLEX__
                tmpMdc.Blit(0,0,60,60,&memDC,ROUND(m_star.X*m_scaleFactor)-30,Displayed_Image->GetHeight() - ROUND(m_star.Y*m_scaleFactor)-30,wxCOPY,false);
    #else
                tmpMdc.Blit(0,0,60,60,&memDC,ROUND(m_star.X*m_scaleFactor)-30,ROUND(m_star.Y*m_scaleFactor)-30,wxCOPY,false);
    #endif
                //          tmpMdc.Blit(0,0,200,200,&Cdc,0,0,wxCOPY);

                wxString fname = Debug.GetLogDir() + PATHSEPSTR + "PHD_GuideStar" + wxDateTime::Now().Format(_T("_%j_%H%M%S")) + ".jpg";
                wxImage subImg = SubBmp.ConvertToImage();
                // subImg.Rescale(120, 120);  zoom up (not now)
                if (pFrame->GetLoggedImageFormat() == LIF_HI_Q_JPEG)
                {
                    // set high(ish) JPEG quality
                    subImg.SetOption(wxIMAGE_OPTION_QUALITY, 100);
                }
                subImg.SaveFile(fname, wxBITMAP_TYPE_JPEG);
                tmpMdc.SelectObject(wxNullBitmap);
            }
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
    }
}
bool GuiderOneStar::UpdateCurrentPosition(usImage *pImage, FrameDroppedInfo *errorInfo)
{
    if (!m_star.IsValid() && m_star.X == 0.0 && m_star.Y == 0.0)
    {
        Debug.AddLine("UpdateCurrentPosition: no star selected");
        errorInfo->starError = Star::STAR_ERROR;
        errorInfo->starMass = 0.0;
        errorInfo->starSNR = 0.0;
        errorInfo->status = _("No star selected");
        return true;
    }

    bool bError = false;

    try
    {
        Star newStar(m_star);

        if (!newStar.Find(pImage, m_searchRegion, pFrame->GetStarFindMode()))
        {
            errorInfo->starError = newStar.GetError();
            errorInfo->starMass = 0.0;
            errorInfo->starSNR = 0.0;
            errorInfo->status = StarStatusStr(newStar);
            m_star.SetError(newStar.GetError());
            throw ERROR_INFO("UpdateCurrentPosition():newStar not found");
        }

        // check to see if it seems like the star we just found was the
        // same as the original star.  We do this by comparing the
        // mass
        m_massChecker->SetExposure(pFrame->RequestedExposureDuration());
        double limits[3];
        if (m_massChangeThresholdEnabled &&
            m_massChecker->CheckMass(newStar.Mass, m_massChangeThreshold, limits))
        {
            m_star.SetError(Star::STAR_MASSCHANGE);
            errorInfo->starError = Star::STAR_MASSCHANGE;
            errorInfo->starMass = newStar.Mass;
            errorInfo->starSNR = newStar.SNR;
            errorInfo->status = StarStatusStr(m_star);
            pFrame->SetStatusText(wxString::Format(_("Mass: %.0f vs %.0f"), newStar.Mass, limits[1]), 1);
            Debug.Write(wxString::Format("UpdateGuideState(): star mass new=%.1f exp=%.1f thresh=%.0f%% range=(%.1f, %.1f)\n", newStar.Mass, limits[1], m_massChangeThreshold * 100, limits[0], limits[2]));
            m_massChecker->AppendData(newStar.Mass);
            throw THROW_INFO("massChangeThreshold error");
        }

        // update the star position, mass, etc.
        m_star = newStar;
        m_massChecker->AppendData(newStar.Mass);

        const PHD_Point& lockPos = LockPosition();
        if (lockPos.IsValid())
        {
            double distance = newStar.Distance(lockPos);
            UpdateCurrentDistance(distance);
        }

        pFrame->pProfile->UpdateData(pImage, m_star.X, m_star.Y);

        pFrame->AdjustAutoExposure(m_star.SNR);

        errorInfo->status.Printf(_T("m=%.0f SNR=%.1f"), m_star.Mass, m_star.SNR);
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;
        pFrame->ResetAutoExposure(); // use max exposure duration
    }

    return bError;
}
void GuiderOneStar::OnLClick(wxMouseEvent &mevent)
{
    try
    {
        if (mevent.GetModifiers() == wxMOD_CONTROL)
        {
            double const scaleFactor = ScaleFactor();
            wxRealPoint pt((double) mevent.m_x / scaleFactor,
                           (double) mevent.m_y / scaleFactor);
            ToggleBookmark(pt);
            m_showBookmarks = true;
            pFrame->bookmarks_menu->Check(MENU_BOOKMARKS_SHOW, GetBookmarksShown());
            Refresh();
            Update();
            return;
        }

        if (GetState() > STATE_SELECTED)
        {
            mevent.Skip();
            throw THROW_INFO("Skipping event because state > STATE_SELECTED");
        }

        if (mevent.GetModifiers() == wxMOD_SHIFT)
        {
            // Deselect guide star
            InvalidateCurrentPosition(true);
        }
        else
        {
            if ((mevent.m_x <= m_searchRegion) || (mevent.m_x + m_searchRegion >= XWinSize) || (mevent.m_y <= m_searchRegion) || (mevent.m_y + m_searchRegion >= YWinSize))
            {
                mevent.Skip();
                throw THROW_INFO("Skipping event because click outside of search region");
            }

            usImage *pImage = CurrentImage();

            if (pImage->NPixels == 0)
            {
                mevent.Skip();
                throw ERROR_INFO("Skipping event m_pCurrentImage->NPixels == 0");
            }

            double scaleFactor = ScaleFactor();
            double StarX = (double) mevent.m_x / scaleFactor;
            double StarY = (double) mevent.m_y / scaleFactor;

            SetCurrentPosition(pImage, PHD_Point(StarX, StarY));

            if (!m_star.IsValid())
            {
                pFrame->SetStatusText(wxString::Format(_("No star found")));
            }
            else
            {
                SetLockPosition(m_star);
                pFrame->SetStatusText(wxString::Format(_("Selected star at (%.1f, %.1f)"), m_star.X, m_star.Y), 1);
                pFrame->SetStatusText(wxString::Format(_T("m=%.0f SNR=%.1f"), m_star.Mass, m_star.SNR));
                EvtServer.NotifyStarSelected(CurrentPosition());
                SetState(STATE_SELECTED);
                pFrame->UpdateButtonsStatus();
                pFrame->pProfile->UpdateData(pImage, m_star.X, m_star.Y);
            }

            Refresh();
            Update();
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
    }
}
示例#4
0
bool Star::Find(const usImage *pImg, int searchRegion, int base_x, int base_y, FindMode mode)
{
    FindResult Result = STAR_OK;
    double newX = base_x;
    double newY = base_y;

    try
    {
        Debug.Write(wxString::Format("Star::Find(%d, %d, %d, %d, (%d,%d,%d,%d))\n", searchRegion, base_x, base_y, mode,
            pImg->Subframe.x, pImg->Subframe.y, pImg->Subframe.width, pImg->Subframe.height));

        if (base_x < 0 || base_y < 0)
        {
            throw ERROR_INFO("coordinates are invalid");
        }

        int minx, miny, maxx, maxy;

        if (pImg->Subframe.IsEmpty())
        {
            minx = miny = 0;
            maxx = pImg->Size.GetWidth() - 1;
            maxy = pImg->Size.GetHeight() - 1;
        }
        else
        {
            minx = pImg->Subframe.GetLeft();
            maxx = pImg->Subframe.GetRight();
            miny = pImg->Subframe.GetTop();
            maxy = pImg->Subframe.GetBottom();
        }

        // search region bounds
        int start_x = wxMax(base_x - searchRegion, minx);
        int end_x   = wxMin(base_x + searchRegion, maxx);
        int start_y = wxMax(base_y - searchRegion, miny);
        int end_y   = wxMin(base_y + searchRegion, maxy);

        const unsigned short *imgdata = pImg->ImageData;
        int rowsize = pImg->Size.GetWidth();

        int peak_x = 0, peak_y = 0;
        unsigned int peak_val = 0;
        unsigned short max3[3] = { 0, 0, 0 };

        if (mode == FIND_PEAK)
        {
            for (int y = start_y; y <= end_y; y++)
            {
                for (int x = start_x; x <= end_x; x++)
                {
                    unsigned short val = imgdata[y * rowsize + x];

                    if (val > peak_val)
                    {
                        peak_val = val;
                        peak_x = x;
                        peak_y = y;
                    }
                }
            }
        }
        else
        {
            // find the peak value within the search region using a smoothing function
            // also check for saturation

            for (int y = start_y + 1; y <= end_y - 1; y++)
            {
                for (int x = start_x + 1; x <= end_x - 1; x++)
                {
                    unsigned short p = imgdata[y * rowsize + x];
                    unsigned int val =
                        2 * (unsigned int) p +
                        imgdata[(y - 1) * rowsize + (x + 0)] +
                        imgdata[(y + 0) * rowsize + (x - 1)] +
                        imgdata[(y + 0) * rowsize + (x + 1)] +
                        imgdata[(y + 1) * rowsize + (x + 0)];

                    if (val > peak_val)
                    {
                        peak_val = val;
                        peak_x = x;
                        peak_y = y;
                    }

                    if (p > max3[0])
                        std::swap(p, max3[0]);
                    if (p > max3[1])
                        std::swap(p, max3[1]);
                    if (p > max3[2])
                        std::swap(p, max3[2]);
                }
            }
        }

        // meaure noise in the annulus with inner radius A and outer radius B
        int const A = 7;   // inner radius
        int const B = 12;  // outer radius
        int const A2 = A * A;
        int const B2 = B * B;

        // find the mean and stdev of the background

        double sum = 0.0;
        double a = 0.0;
        double q = 0.0;
        int n = 0;

        const unsigned short *row = imgdata + rowsize * start_y;
        for (int y = start_y; y <= end_y; y++, row += rowsize)
        {
            int dy = y - peak_y;
            int dy2 = dy * dy;
            for (int x = start_x; x <= end_x; x++)
            {
                int dx = x - peak_x;
                int r2 = dx * dx + dy2;

                // exclude points not in annulus
                if (r2 <= A2 || r2 > B2)
                    continue;

                double const val = (double) row[x];
                sum += val;
                ++n;
                double const k = (double) n;
                double const a0 = a;
                a += (val - a) / k;
                q += (val - a0) * (val - a);
            }
        }

        double const mean_bg = sum / (double) n;
        double const sigma_bg = sqrt(q / (double) (n - 1));

        double cx = 0.0;
        double cy = 0.0;
        double mass = 0.0;

        if (mode == FIND_PEAK)
        {
            mass = peak_val;
            n = 1;
        }
        else
        {
            unsigned short const thresh = (unsigned short)(mean_bg + 2.0 * sigma_bg);

            // find pixels over threshold within aperture; compute mass and centroid

            start_x = wxMax(peak_x - A, minx);
            end_x = wxMin(peak_x + A, maxx);
            start_y = wxMax(peak_y - A, miny);
            end_y = wxMin(peak_y + A, maxy);

            n = 0;

            row = imgdata + rowsize * start_y;
            for (int y = start_y; y <= end_y; y++, row += rowsize)
            {
                int dy = y - peak_y;
                int dy2 = dy * dy;
                if (dy2 > A2)
                    continue;

                for (int x = start_x; x <= end_x; x++)
                {
                    int dx = x - peak_x;

                    // exclude points outside aperture
                    if (dx * dx + dy2 > A2)
                        continue;

                    // exclude points below threshold
                    unsigned short val = row[x];
                    if (val < thresh)
                        continue;

                    double const d = (double) val - mean_bg;

                    cx += dx * d;
                    cy += dy * d;
                    mass += d;
                    ++n;
                }
            }
        }

        Mass = mass;
        SNR = n > 0 ? mass / (sigma_bg * n) : 0.0;

        double const LOW_SNR = 3.0;

        if (mass < 10.0)
            Result = STAR_LOWMASS;
        else if (SNR < LOW_SNR)
            Result = STAR_LOWSNR;
        else
        {
            newX = peak_x + cx / mass;
            newY = peak_y + cy / mass;

            // even at saturation, the max values may vary a bit due to noise
            // Call it saturated if the the top three values are within 32 parts per 65535 of max
            if ((unsigned int)(max3[0] - max3[2]) * 65535U < 32U * (unsigned int) max3[0])
                Result = STAR_SATURATED;
        }
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);

        if (Result == STAR_OK)
        {
            Result = STAR_ERROR;
        }
    }

    // update state
    SetXY(newX, newY);
    m_lastFindResult = Result;

    bool bReturn = WasFound(Result);

    if (!bReturn)
    {
        Mass = 0.0;
        SNR = 0.0;
    }

    Debug.AddLine(wxString::Format("Star::Find returns %d (%d), X=%.2f, Y=%.2f, Mass=%.f, SNR=%.1f",
        bReturn, Result, newX, newY, Mass, SNR));

    return bReturn;
}
bool GuiderOneStar::AutoSelect(void)
{
    bool bError = false;

    usImage *pImage = CurrentImage();

    try
    {
        if (!pImage || !pImage->ImageData)
        {
            throw ERROR_INFO("No Current Image");
        }

        // If mount is not calibrated, we need to chose a star a bit farther
        // from the egde to allow for the motion of the star during
        // calibration
        //
        int edgeAllowance = 0;
        if (pMount && pMount->IsConnected() && !pMount->IsCalibrated())
            edgeAllowance = wxMax(edgeAllowance, pMount->CalibrationTotDistance());
        if (pSecondaryMount && pSecondaryMount->IsConnected() && !pSecondaryMount->IsCalibrated())
            edgeAllowance = wxMax(edgeAllowance, pSecondaryMount->CalibrationTotDistance());

        Star newStar;
        if (!newStar.AutoFind(*pImage, edgeAllowance, m_searchRegion))
        {
            throw ERROR_INFO("Unable to AutoFind");
        }

        m_massChecker->Reset();

        if (!m_star.Find(pImage, m_searchRegion, newStar.X, newStar.Y, Star::FIND_CENTROID))
        {
            throw ERROR_INFO("Unable to find");
        }

        if (SetLockPosition(m_star))
        {
            throw ERROR_INFO("Unable to set Lock Position");
        }

        if (GetState() == STATE_SELECTING)
        {
            // immediately advance the state machine now, rather than waiting for
            // the next exposure to complete. Socket server clients are going to
            // try to start guiding after selecting the star, but guiding will fail
            // to start if state is still STATE_SELECTING
            Debug.AddLine("AutoSelect: state = %d, call UpdateGuideState", GetState());
            UpdateGuideState(NULL, false);
        }

        UpdateImageDisplay();
        pFrame->pProfile->UpdateData(pImage, m_star.X, m_star.Y);
    }
    catch (wxString Msg)
    {
        if (pImage && pImage->ImageData)
        {
            SaveAutoSelectFailedImg(pImage);
        }

        POSSIBLY_UNUSED(Msg);
        bError = true;
    }

    return bError;
}
示例#6
0
bool StepGuider::UpdateCalibrationState(const PHD_Point& currentLocation)
{
    bool bError = false;

    try
    {
        if (!m_calibrationStartingLocation.IsValid())
        {
            m_calibrationStartingLocation = currentLocation;
            Debug.AddLine(wxString::Format("Stepguider::UpdateCalibrationstate: starting location = %.2f,%.2f", currentLocation.X, currentLocation.Y));
        }

        wxString status0, status1;
        int stepsRemainingUp = MaxPosition(UP) - CurrentPosition(UP);
        int stepsRemainingDown = MaxPosition(DOWN) - CurrentPosition(DOWN);
        int stepsRemainingRight  = MaxPosition(RIGHT)  - CurrentPosition(RIGHT);
        int stepsRemainingLeft  = MaxPosition(LEFT)  - CurrentPosition(LEFT);

        stepsRemainingUp /= m_calibrationStepsPerIteration;
        stepsRemainingDown /= m_calibrationStepsPerIteration;
        stepsRemainingRight /= m_calibrationStepsPerIteration;
        stepsRemainingLeft /= m_calibrationStepsPerIteration;

        int stepsRemainingDownAndRight = wxMax(stepsRemainingDown, stepsRemainingRight);

        assert(stepsRemainingUp >= 0);
        assert(stepsRemainingDown >= 0);
        assert(stepsRemainingRight  >= 0);
        assert(stepsRemainingLeft  >= 0);
        assert(stepsRemainingDownAndRight    >= 0);


        bool moveUp = false;
        bool moveDown = false;
        bool moveRight  = false;
        bool moveLeft  = false;
        double x_dist;
        double y_dist;

        switch (m_calibrationState)
        {
            case CALIBRATION_STATE_GOTO_LOWER_RIGHT_CORNER:
                if (stepsRemainingDownAndRight > 0)
                {
                    status0.Printf(_("Init Calibration: %3d"), stepsRemainingDownAndRight);
                    moveDown = stepsRemainingDown > 0;
                    moveRight  = stepsRemainingRight > 0;
                    break;
                }
                Debug.AddLine(wxString::Format("Falling through to state AVERAGE_STARTING_LOCATION, position=(%.2f, %.2f)",
                                                currentLocation.X, currentLocation.Y));
                m_calibrationAverageSamples = 0;
                m_calibrationAveragedLocation.SetXY(0.0, 0.0);
                m_calibrationState = CALIBRATION_STATE_AVERAGE_STARTING_LOCATION;
                // fall through
            case CALIBRATION_STATE_AVERAGE_STARTING_LOCATION:
                m_calibrationAverageSamples++;
                m_calibrationAveragedLocation += currentLocation;
                status0.Printf(_("Averaging: %3d"), m_samplesToAverage - m_calibrationAverageSamples + 1);
                if (m_calibrationAverageSamples < m_samplesToAverage )
                {
                    break;
                }
                m_calibrationAveragedLocation /= m_calibrationAverageSamples;
                m_calibrationStartingLocation = m_calibrationAveragedLocation;
                m_calibrationIterations = 0;
                Debug.AddLine(wxString::Format("Falling through to state GO_LEFT, startinglocation=(%.2f, %.2f)",
                                                m_calibrationStartingLocation.X, m_calibrationStartingLocation.Y));
                m_calibrationState = CALIBRATION_STATE_GO_LEFT;
                // fall through
            case CALIBRATION_STATE_GO_LEFT:
                if (stepsRemainingLeft > 0)
                {
                    status0.Printf(_("Left Calibration: %3d"), stepsRemainingLeft);
                    m_calibrationIterations++;
                    moveLeft  = true;
                    x_dist = m_calibrationStartingLocation.dX(currentLocation);
                    y_dist = m_calibrationStartingLocation.dY(currentLocation);
                    GuideLog.CalibrationStep(this, "Left", stepsRemainingLeft,
                        x_dist,  y_dist,
                        currentLocation, m_calibrationStartingLocation.Distance(currentLocation));
                    m_calibrationDetails.raSteps.push_back(wxRealPoint(x_dist, y_dist));            // Just put "left" in "ra" steps
                    break;
                }
                Debug.AddLine(wxString::Format("Falling through to state AVERAGE_CENTER_LOCATION, position=(%.2f, %.2f)",
                                                currentLocation.X, currentLocation.Y));
                m_calibrationAverageSamples = 0;
                m_calibrationAveragedLocation.SetXY(0.0, 0.0);
                m_calibrationState = CALIBRATION_STATE_AVERAGE_CENTER_LOCATION;
                // fall through
            case CALIBRATION_STATE_AVERAGE_CENTER_LOCATION:
                m_calibrationAverageSamples++;
                m_calibrationAveragedLocation += currentLocation;
                status0.Printf(_("Averaging: %3d"), m_samplesToAverage -m_calibrationAverageSamples+1);
                if (m_calibrationAverageSamples < m_samplesToAverage )
                {
                    break;
                }
                m_calibrationAveragedLocation /= m_calibrationAverageSamples;
                m_calibration.xAngle = m_calibrationStartingLocation.Angle(m_calibrationAveragedLocation);
                m_calibration.xRate  = m_calibrationStartingLocation.Distance(m_calibrationAveragedLocation) /
                                                     (m_calibrationIterations * m_calibrationStepsPerIteration);
                status1.Printf(_("angle=%.1f rate=%.2f"), m_calibration.xAngle * 180. / M_PI, m_calibration.xRate);
                GuideLog.CalibrationDirectComplete(this, "Left", m_calibration.xAngle, m_calibration.xRate);
                Debug.AddLine(wxString::Format("LEFT calibration completes with angle=%.1f rate=%.2f", m_calibration.xAngle * 180. / M_PI, m_calibration.xRate));
                Debug.AddLine(wxString::Format("distance=%.2f iterations=%d",  m_calibrationStartingLocation.Distance(m_calibrationAveragedLocation), m_calibrationIterations));
                m_calibrationStartingLocation = m_calibrationAveragedLocation;
                m_calibrationIterations = 0;
                m_calibrationState = CALIBRATION_STATE_GO_UP;
                Debug.AddLine(wxString::Format("Falling through to state GO_UP, startinglocation=(%.2f, %.2f)",
                                                m_calibrationStartingLocation.X, m_calibrationStartingLocation.Y));
                // fall through
            case CALIBRATION_STATE_GO_UP:
                if (stepsRemainingUp > 0)
                {
                    status0.Printf(_("up Calibration: %3d"), stepsRemainingUp);
                    m_calibrationIterations++;
                    moveUp = true;
                    x_dist = m_calibrationStartingLocation.dX(currentLocation);
                    y_dist = m_calibrationStartingLocation.dY(currentLocation);
                    GuideLog.CalibrationStep(this, "Up", stepsRemainingLeft,
                        x_dist,  y_dist,
                        currentLocation, m_calibrationStartingLocation.Distance(currentLocation));
                    m_calibrationDetails.decSteps.push_back(wxRealPoint(x_dist, y_dist));                   // Just put "up" in "dec" steps
                    break;
                }
                Debug.AddLine(wxString::Format("Falling through to state AVERAGE_ENDING_LOCATION, position=(%.2f, %.2f)",
                                                currentLocation.X, currentLocation.Y));
                m_calibrationAverageSamples = 0;
                m_calibrationAveragedLocation.SetXY(0.0, 0.0);
                m_calibrationState = CALIBRATION_STATE_AVERAGE_ENDING_LOCATION;
                // fall through
            case CALIBRATION_STATE_AVERAGE_ENDING_LOCATION:
                m_calibrationAverageSamples++;
                m_calibrationAveragedLocation += currentLocation;
                status0.Printf(_("Averaging: %3d"), m_samplesToAverage -m_calibrationAverageSamples+1);
                if (m_calibrationAverageSamples < m_samplesToAverage )
                {
                    break;
                }
                m_calibrationAveragedLocation /= m_calibrationAverageSamples;
                m_calibration.yAngle = m_calibrationAveragedLocation.Angle(m_calibrationStartingLocation);
                m_calibration.yRate  = m_calibrationStartingLocation.Distance(m_calibrationAveragedLocation) /
                                                     (m_calibrationIterations * m_calibrationStepsPerIteration);
                status1.Printf(_("angle=%.1f rate=%.2f"), m_calibration.yAngle * 180. / M_PI, m_calibration.yRate);
                GuideLog.CalibrationDirectComplete(this, "Up", m_calibration.yAngle, m_calibration.yRate);
                Debug.AddLine(wxString::Format("UP calibration completes with angle=%.1f rate=%.2f", m_calibration.yAngle * 180. / M_PI, m_calibration.yRate));
                Debug.AddLine(wxString::Format("distance=%.2f iterations=%d",  m_calibrationStartingLocation.Distance(m_calibrationAveragedLocation), m_calibrationIterations));
                m_calibrationStartingLocation = m_calibrationAveragedLocation;
                m_calibrationState = CALIBRATION_STATE_RECENTER;
                Debug.AddLine(wxString::Format("Falling through to state RECENTER, position=(%.2f, %.2f)",
                                                currentLocation.X, currentLocation.Y));
                // fall through
            case CALIBRATION_STATE_RECENTER:
                status0.Printf(_("Finish Calibration: %3d"), stepsRemainingDownAndRight/2);
                moveRight = (CurrentPosition(LEFT) >= m_calibrationStepsPerIteration);
                moveDown = (CurrentPosition(UP) >= m_calibrationStepsPerIteration);
                if (moveRight || moveDown)
                {
                    Debug.AddLine(wxString::Format("CurrentPosition(LEFT)=%d CurrentPosition(UP)=%d", CurrentPosition(LEFT), CurrentPosition(UP)));
                    break;
                }
                m_calibrationState = CALIBRATION_STATE_COMPLETE;
                Debug.AddLine(wxString::Format("Falling through to state COMPLETE, position=(%.2f, %.2f)",
                                                currentLocation.X, currentLocation.Y));
                // fall through
            case CALIBRATION_STATE_COMPLETE:
                m_calibration.declination = 0.;
                m_calibration.pierSide = PIER_SIDE_UNKNOWN;
                m_calibration.rotatorAngle = Rotator::RotatorPosition();
                SetCalibration(m_calibration);
                SetCalibrationDetails(m_calibrationDetails, m_calibration.xAngle, m_calibration.yAngle);
                status1 = _T("calibration complete");
                GuideLog.CalibrationComplete(this);
                Debug.AddLine("Calibration Complete");
                break;
            default:
                assert(false);
                break;
        }

        if (moveUp)
        {
            assert(!moveDown);
            pFrame->ScheduleCalibrationMove(this, UP, m_calibrationStepsPerIteration);
        }

        if (moveDown)
        {
            assert(!moveUp);
            pFrame->ScheduleCalibrationMove(this, DOWN, m_calibrationStepsPerIteration);
        }

        if (moveRight)
        {
            assert(!moveLeft);
            pFrame->ScheduleCalibrationMove(this, RIGHT, m_calibrationStepsPerIteration);
        }

        if (moveLeft)
        {
            assert(!moveRight);
            pFrame->ScheduleCalibrationMove(this, LEFT, m_calibrationStepsPerIteration);
        }

        if (m_calibrationState != CALIBRATION_STATE_COMPLETE)
        {
            if (status1.IsEmpty())
            {
                double dX = m_calibrationStartingLocation.dX(currentLocation);
                double dY = m_calibrationStartingLocation.dY(currentLocation);
                double dist = m_calibrationStartingLocation.Distance(currentLocation);
                status1.Printf(_T("dx=%4.1f dy=%4.1f dist=%4.1f"), dX, dY, dist);
            }
        }

        if (!status0.IsEmpty())
        {
            pFrame->SetStatusText(status0, 0);
        }

        if (!status1.IsEmpty())
        {
            pFrame->SetStatusText(status1, 1);
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;

        ClearCalibration();
    }

    return bError;
}
示例#7
0
Mount::MOVE_RESULT StepGuider::Move(const PHD_Point& cameraVectorEndpoint, bool normalMove)
{
    MOVE_RESULT result = MOVE_OK;

    try
    {
        MOVE_RESULT mountResult = Mount::Move(cameraVectorEndpoint, normalMove);
        if (mountResult != MOVE_OK)
            Debug.AddLine("StepGuider::Move: Mount::Move failed!");

        if (!m_guidingEnabled)
        {
            throw THROW_INFO("Guiding disabled");
        }

        // keep a moving average of the AO position
        if (m_avgOffset.IsValid())
        {
            static double const alpha = .33; // moderately high weighting for latest sample
            m_avgOffset.X += alpha * (m_xOffset - m_avgOffset.X);
            m_avgOffset.Y += alpha * (m_yOffset - m_avgOffset.Y);
        }
        else
        {
            m_avgOffset.SetXY((double) m_xOffset, (double) m_yOffset);
        }

        pFrame->pStepGuiderGraph->AppendData(m_xOffset, m_yOffset, m_avgOffset);

        // consider bumping the secondary mount if this is a normal move
        if (normalMove && pSecondaryMount && pSecondaryMount->IsConnected())
        {
            int absX = abs(CurrentPosition(RIGHT));
            int absY = abs(CurrentPosition(UP));
            bool isOutside = absX > m_xBumpPos1 || absY > m_yBumpPos1;
            bool forceStartBump = false;
            if (m_forceStartBump)
            {
                Debug.Write("stepguider::Move: will start forced bump\n");
                forceStartBump = true;
                m_forceStartBump = false;
            }

            // if the current bump has not brought us in, increase the bump size
            if (isOutside && m_bumpInProgress)
            {
                if (absX > m_xBumpPos2 || absY > m_yBumpPos2)
                {
                    Debug.AddLine("FAR outside bump range, increase bump weight %.2f => %.2f", m_bumpStepWeight, m_bumpStepWeight + 1.0);
                    m_bumpStepWeight += 1.0;
                }
                else
                {
                    Debug.AddLine("outside bump range, increase bump weight %.2f => %.2f", m_bumpStepWeight, m_bumpStepWeight + 1./6.);
                    m_bumpStepWeight += 1./6.;
                }
            }

            // if we are back inside, decrease the bump weight
            if (!isOutside && m_bumpStepWeight > 1.0)
            {
                double prior = m_bumpStepWeight;
                m_bumpStepWeight *= 0.5;
                if (m_bumpStepWeight < 1.0)
                    m_bumpStepWeight = 1.0;
                Debug.AddLine("back inside bump range: decrease bump weight %.2f => %.2f", prior, m_bumpStepWeight);
            }

            if (m_bumpInProgress && !m_bumpTimeoutAlertSent)
            {
                long now = ::wxGetUTCTime();
                if (now - m_bumpStartTime > BumpWarnTime)
                {
                    pFrame->Alert(_("A mount \"bump\" was needed to bring the AO back to its center position,\n"
                        "but the bump did not complete in a reasonable amount of time.\n"
                        "You probably need to increase the AO Bump Step setting."), wxICON_INFORMATION);
                    m_bumpTimeoutAlertSent = true;
                }
            }

            if ((isOutside || forceStartBump) && !m_bumpInProgress)
            {
                // start a new bump
                m_bumpInProgress = true;
                m_bumpStartTime = ::wxGetUTCTime();
                m_bumpTimeoutAlertSent = false;

                Debug.AddLine("starting a new bump");
            }

            // stop the bump if we are "close enough" to the center position
            if ((!isOutside || forceStartBump) && m_bumpInProgress)
            {
                int minDist = m_bumpCenterTolerance;
                if (m_avgOffset.X * m_avgOffset.X + m_avgOffset.Y * m_avgOffset.Y <= minDist * minDist)
                {
                    Debug.AddLine("Stop bumping, close enough to center -- clearing m_bumpInProgress");
                    m_bumpInProgress = false;
                    pFrame->pStepGuiderGraph->ShowBump(PHD_Point());
                }
            }
        }

        if (m_bumpInProgress && pSecondaryMount->IsBusy())
            Debug.AddLine("secondary mount is busy, cannot bump");

        // if we have a bump in progress and the secondary mount is not moving,
        // schedule another move
        if (m_bumpInProgress && !pSecondaryMount->IsBusy())
        {
            // compute incremental bump based on average position
            PHD_Point vectorEndpoint(xRate() * -m_avgOffset.X, yRate() * -m_avgOffset.Y);

            // we have to transform our notion of where we are (which is in "AO Coordinates")
            // into "Camera Coordinates" so we can bump the secondary mount to put us closer
            // to the center of the AO

            PHD_Point bumpVec;

            if (TransformMountCoordinatesToCameraCoordinates(vectorEndpoint, bumpVec))
            {
                throw ERROR_INFO("MountToCamera failed");
            }

            Debug.AddLine("incremental bump (%.3f, %.3f) isValid = %d", bumpVec.X, bumpVec.Y, bumpVec.IsValid());

            double maxBumpPixelsX = m_calibration.xRate * m_bumpMaxStepsPerCycle * m_bumpStepWeight;
            double maxBumpPixelsY = m_calibration.yRate * m_bumpMaxStepsPerCycle * m_bumpStepWeight;
            double len = bumpVec.Distance();
            double xBumpSize = bumpVec.X * maxBumpPixelsX / len;
            double yBumpSize = bumpVec.Y * maxBumpPixelsY / len;

            PHD_Point thisBump(xBumpSize, yBumpSize);

            // display the current bump vector on the stepguider graph
            {
                PHD_Point tcur;
                TransformCameraCoordinatesToMountCoordinates(thisBump, tcur);
                tcur.X /= xRate();
                tcur.Y /= yRate();
                pFrame->pStepGuiderGraph->ShowBump(tcur);
            }

            Debug.AddLine("Scheduling Mount bump of (%.3f, %.3f)", thisBump.X, thisBump.Y);

            pFrame->ScheduleSecondaryMove(pSecondaryMount, thisBump, false);
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        result = MOVE_ERROR;
    }

    return result;
}
示例#8
0
bool usImage::Save(const wxString& fname, const wxString& hdrNote) const
{
    bool bError = false;

    try
    {
        long fsize[3] = {
            (long)Size.GetWidth(),
            (long)Size.GetHeight(),
            0L,
        };
        long fpixel[3] = { 1, 1, 1 };

        fitsfile *fptr;  // FITS file pointer
        int status = 0;  // CFITSIO status value MUST be initialized to zero!

        PHD_fits_create_file(&fptr, fname, true, &status);
        fits_create_img(fptr, USHORT_IMG, 2, fsize, &status);

        FITSHdrWriter hdr(fptr, &status);

        float exposure = (float) ImgExpDur / 1000.0;
        hdr.write("EXPOSURE", exposure, "Exposure time in seconds");

        if (ImgStackCnt > 1)
            hdr.write("STACKCNT", (unsigned int) ImgStackCnt, "Stacked frame count");

        if (!hdrNote.IsEmpty())
            hdr.write("USERNOTE", static_cast<const char *>(hdrNote), 0);

        time_t now = wxDateTime::GetTimeNow();
        struct tm *timestruct = gmtime(&now);
        char buf[100];
        sprintf(buf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", timestruct->tm_year + 1900, timestruct->tm_mon + 1, timestruct->tm_mday, timestruct->tm_hour, timestruct->tm_min, timestruct->tm_sec);
        hdr.write("DATE", buf, "Time FITS file was created");

        hdr.write("DATE-OBS", GetImgStartTime().c_str(), "Time image was captured");
        hdr.write("CREATOR", wxString(APPNAME _T(" ") FULLVER).c_str(), "Capture software");
        if (pCamera)
        {
            hdr.write("INSTRUME", pCamera->Name.c_str(), "Instrument name");
            unsigned int b = pCamera->Binning;
            hdr.write("XBINNING", b, "Camera X Bin");
            hdr.write("YBINNING", b, "Camera Y Bin");
            hdr.write("CCDXBIN", b, "Camera X Bin");
            hdr.write("CCDYBIN", b, "Camera Y Bin");
            float sz = b * pCamera->PixelSize;
            hdr.write("XPIXSZ", sz, "pixel size in microns (with binning)");
            hdr.write("YPIXSZ", sz, "pixel size in microns (with binning)");
        }

        if (pPointingSource)
        {
            double ra, dec, st;
            pPointingSource->GetCoordinates(&ra, &dec, &st);
            hdr.write("RA", (float) (ra * 360.0 / 24.0), "Object Right Ascension in degrees");
            hdr.write("DEC", (float) dec, "Object Declination in degrees");

            {
                int h = (int) ra;
                ra -= h;
                ra *= 60.0;
                int m = (int) ra;
                ra -= m;
                ra *= 60.0;
                hdr.write("OBJCTRA", wxString::Format("%02d %02d %06.3f", h, m, ra).c_str(), "Object Right Ascension in hms");
            }

            {
                int sign = dec < 0.0 ? -1 : +1;
                dec *= sign;
                int d = (int) dec;
                dec -= d;
                dec *= 60.0;
                int m = (int) dec;
                dec -= m;
                dec *= 60.0;
                hdr.write("OBJCTDEC", wxString::Format("%c%d %02d %06.3f", sign < 0 ? '-' : '+', d, m, dec).c_str(), "Object Declination in dms");
            }
        }

        float sc = (float) pFrame->GetCameraPixelScale();
        hdr.write("SCALE", sc, "Image scale (arcsec / pixel)");
        hdr.write("PIXSCALE", sc, "Image scale (arcsec / pixel)");

        fits_write_pix(fptr, TUSHORT, fpixel, NPixels, ImageData, &status);

        PHD_fits_close_file(fptr);

        bError = status ? true : false;
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;
    }

    return bError;
}
示例#9
0
bool usImage::Load(const wxString& fname)
{
    bool bError = false;

    try
    {
        if (!wxFileExists(fname))
        {
            pFrame->Alert(_("File does not exist - cannot load ") + fname);
            throw ERROR_INFO("File does not exist");
        }

        int status = 0;  // CFITSIO status value MUST be initialized to zero!
        fitsfile *fptr;  // FITS file pointer
        if (!PHD_fits_open_diskfile(&fptr, fname, READONLY, &status))
        {
            int hdutype;
            if (fits_get_hdu_type(fptr, &hdutype, &status) || hdutype != IMAGE_HDU)
            {
                pFrame->Alert(_("FITS file is not of an image: ") + fname);
                throw ERROR_INFO("Fits file is not an image");
            }

            // Get HDUs and size
            int naxis = 0;
            fits_get_img_dim(fptr, &naxis, &status);
            long fsize[3];
            fits_get_img_size(fptr, 2, fsize, &status);
            int nhdus = 0;
            fits_get_num_hdus(fptr, &nhdus, &status);
            if ((nhdus != 1) || (naxis != 2)) {
                pFrame->Alert(_("Unsupported type or read error loading FITS file ") + fname);
                throw ERROR_INFO("unsupported type");
            }
            if (Init((int) fsize[0], (int) fsize[1]))
            {
                pFrame->Alert(_("Memory allocation error loading FITS file ") + fname);
                throw ERROR_INFO("Memory Allocation failure");
            }
            long fpixel[3] = { 1, 1, 1 };
            if (fits_read_pix(fptr, TUSHORT, fpixel, (int)(fsize[0] * fsize[1]), NULL, ImageData, NULL, &status)) { // Read image
                pFrame->Alert(_("Error reading data from FITS file ") + fname);
                throw ERROR_INFO("Error reading");
            }

            char *key = const_cast<char *>("EXPOSURE");
            float exposure;
            status = 0;
            fits_read_key(fptr, TFLOAT, key, &exposure, NULL, &status);
            if (status == 0)
                ImgExpDur = (int) (exposure * 1000.0);

            key = const_cast<char *>("STACKCNT");
            int stackcnt;
            status = 0;
            fits_read_key(fptr, TINT, key, &stackcnt, NULL, &status);
            if (status == 0)
                ImgStackCnt = (int) stackcnt;

            PHD_fits_close_file(fptr);
        }
        else
        {
            pFrame->Alert(_("Error opening FITS file ") + fname);
            throw ERROR_INFO("error opening file");
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;
    }

    return bError;
}
示例#10
0
bool Camera_WDMClass::Connect(const wxString& camId)
{
    bool bError = false;

    try
    {
        m_deviceNumber = pConfig->Profile.GetInt("/camera/WDM/deviceNumber", -1);
        m_deviceMode = pConfig->Profile.GetInt("/camera/WDM/deviceMode", -1);

        if (m_deviceNumber == -1 || m_deviceMode == -1)
            if (SelectDeviceAndMode())
                throw ERROR_INFO("SelectDeviceAndMode failed");

        // Setup VidCap library
        m_pVidCap = CVPlatform::GetPlatform()->AcquireVideoCapture();

        // Init the library
        if (CVFAILED(m_pVidCap->Init()))
        {
            wxMessageBox(_T("Error initializing WDM services"),_("Error"),wxOK | wxICON_ERROR);
            throw ERROR_INFO("CVFAILED(VidCap->Init())");
        }

        // Connect to camera
        if (CVSUCCESS(m_pVidCap->Connect(m_deviceNumber)))
        {
            int devNameLen = 0;

            // find the length of the name
            m_pVidCap->GetDeviceName(NULL, devNameLen);
            ++devNameLen;

            // now get the name
            char *devName = new char[devNameLen];
            m_pVidCap->GetDeviceName(devName, devNameLen);

            Name = wxString::Format("%s", devName);

            delete[] devName;
        }
        else
        {
            wxMessageBox(wxString::Format("Error connecting to WDM device #%d", m_deviceNumber), _("Error"), wxOK | wxICON_ERROR);
            throw ERROR_INFO("Error connecting to WDM device");
        }

        if (CVFAILED(m_pVidCap->SetMode(m_deviceMode)))
        {
            wxMessageBox(wxString::Format("Error activating video mode %d", m_deviceMode), _("Error"), wxOK | wxICON_ERROR);
            throw ERROR_INFO("setmode() failed");
        }

        // get the x and y size
        CVVidCapture::VIDCAP_MODE modeInfo;
        if (CVFAILED(m_pVidCap->GetCurrentMode(modeInfo)))
        {
            wxMessageBox(wxString::Format("Error probing video mode %d", m_deviceMode),_("Error"),wxOK | wxICON_ERROR);
            throw ERROR_INFO("GetCurrentMode() failed");
        }

        FullSize = wxSize(modeInfo.XRes, modeInfo.YRes);

        // Start the stream
        m_captureMode = NOT_CAPTURING; // Make sure we don't start saving yet

        if (CVFAILED(m_pVidCap->StartImageCap(CVImage::CVIMAGE_GREY, CaptureCallback, this)))
        {
            wxMessageBox(_T("Failed to start image capture!"),_("Error"),wxOK | wxICON_ERROR);
            throw ERROR_INFO("StartImageCap() failed");
        }

        pFrame->StatusMsg(wxString::Format("%d x %d mode activated", modeInfo.XRes, modeInfo.YRes));

        Connected = true;
    }
    catch (const wxString& msg)
    {
        POSSIBLY_UNUSED(msg);
        bError = true;

        if (m_pVidCap)
        {
            m_pVidCap->Uninit();
            CVPlatform::GetPlatform()->Release(m_pVidCap);

            m_pVidCap = NULL;
        }
    }

    return bError;
}
示例#11
0
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_canPulseGuide)
        {
            // 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 != VARIANT_TRUE)
            {
                Debug.AddLine("Tried to guide mount that has no PulseGuide support");
                // This will trigger a nice alert the next time through Guide
                m_canPulseGuide = 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;

            if (!WorkerThread::InterruptRequested())
            {
                pFrame->Alert(_("PulseGuide command to mount has failed - guiding is likely to be ineffective."));
            }
        }
    }

    if (result == MOVE_STOP_GUIDING)
    {
        if (pConfig->Global.GetBoolean(SlewWarningEnabledKey(), true))
        {
            pFrame->Alert(_("Guiding stopped: the scope started slewing."), 
                _("Don't show\nthis again"), SuppressSlewAlert, 0);
        }
    }

    return result;
}
示例#12
0
bool Camera_WDMClass::SelectDeviceAndMode()
{
    bool error = false;
    CVVidCapture *vidCap = 0;
    bool inited = false;
    bool connected = false;

    try
    {
        vidCap = CVPlatform::GetPlatform()->AcquireVideoCapture();

        // Init the library
        if (CVFAILED(vidCap->Init()))
        {
            wxMessageBox(_T("Error initializing WDM services"),_("Error"), wxOK | wxICON_ERROR);
            throw ERROR_INFO("CVFAILED(VidCap->Init())");
        }
        inited = true;

        // Enumerate devices
        int nDevices;
        if (CVFAILED(vidCap->GetNumDevices(nDevices)))
        {
            wxMessageBox(_T("Error detecting WDM devices"), _("Error"), wxOK | wxICON_ERROR);
            throw ERROR_INFO("CVFAILED(m_pVidCap->GetNumDevices(nDevices))");
        }

        int deviceNumber;

        if (nDevices == 0)
        {
            deviceNumber = 0;
        }
        else
        {
            wxArrayString devices;

            for (int i = 0; i < nDevices; i++)
            {
                CVVidCapture::VIDCAP_DEVICE devInfo;
                if (CVSUCCESS(vidCap->GetDeviceInfo(i, devInfo)))
                {
                    devices.Add(wxString::Format("%d: %s", i, devInfo.DeviceString));
                }
                else
                {
                    devices.Add(wxString::Format("%d: Not available"),i);
                }
            }

            deviceNumber = wxGetSingleChoiceIndex(_("Select WDM camera"), _("Camera choice"), devices);

            if (deviceNumber == -1)
            {
                throw ERROR_INFO("deviceNumber == -1");
            }
        }

        // Connect to camera
        if (!CVSUCCESS(vidCap->Connect(deviceNumber)))
        {
            wxMessageBox(wxString::Format("Error connecting to WDM device #%d", deviceNumber), _("Error"), wxOK | wxICON_ERROR);
            throw ERROR_INFO("Error connecting to WDM device");
        }
        connected = true;

        int numModes = 0;
        vidCap->GetNumSupportedModes(numModes);

        wxArrayString modeNames;

        for (int curmode = 0; curmode < numModes; curmode++)
        {
            CVVidCapture::VIDCAP_MODE modeInfo;
            if (CVSUCCESS(vidCap->GetModeInfo(curmode, modeInfo)))
            {
                modeNames.Add(wxString::Format("%dx%d (%s)", modeInfo.XRes, modeInfo.YRes,
                    vidCap->GetFormatModeName(modeInfo.InputFormat)));
            }
        }

        // Let user choose mode
        int deviceMode = wxGetSingleChoiceIndex(_("Select camera mode"), _("Camera mode"), modeNames);

        if (deviceMode == -1)
        {
            // canceled
            throw ERROR_INFO("user did not choose a mode");
        }

        m_deviceNumber = deviceNumber;
        m_deviceMode = deviceMode;

        pConfig->Profile.SetInt("/camera/WDM/deviceNumber", m_deviceNumber);
        pConfig->Profile.SetInt("/camera/WDM/deviceMode", m_deviceMode);
    }
    catch (const wxString& msg)
    {
        POSSIBLY_UNUSED(msg);
        error = true;
    }

    if (vidCap)
    {
        if (connected)
            vidCap->Disconnect();
        if (inited)
            vidCap->Uninit();
        CVPlatform::GetPlatform()->Release(vidCap);
    }

    return error;
}
示例#13
0
void MyFrame::GuideButtonClick(bool interactive)
{
    try
    {
        if (pMount == NULL)
        {
            // no mount selected -- should never happen
            throw ERROR_INFO("pMount == NULL");
        }

        if (!pMount->IsConnected())
        {
            throw ERROR_INFO("Unable to guide with no scope Connected");
        }

        if (!pCamera || !pCamera->Connected)
        {
            throw ERROR_INFO("Unable to guide with no camera Connected");
        }

        if (pGuider->GetState() < STATE_SELECTED)
        {
            wxMessageBox(_T("Please select a guide star before attempting to guide"));
            throw ERROR_INFO("Unable to guide with state < STATE_SELECTED");
        }

        ValidateDarksLoaded();

        if (wxGetKeyState(WXK_SHIFT))
        {
            bool recalibrate = true;
            if (pMount->IsCalibrated() || (pSecondaryMount && pSecondaryMount->IsCalibrated()))
            {
                recalibrate = ConfirmDialog::Confirm(_("Are you sure you want force recalibration?"),
                    "/force_recalibration_ok", _("Force Recalibration"));
            }
            if (recalibrate)
            {
                pMount->ClearCalibration();
                if (pSecondaryMount)
                    pSecondaryMount->ClearCalibration();
            }
        }

        if (interactive && pPointingSource && pPointingSource->IsConnected() && pPointingSource->CanReportPosition())
        {
            bool proceed = true;
            bool error = pPointingSource->PreparePositionInteractive();

            if (!error && fabs(pPointingSource->GetDeclination()) > Scope::DEC_COMP_LIMIT && !TheScope()->IsCalibrated() )
            {
                proceed = ConfirmDialog::Confirm(
                    _("Calibration this far from the celestial equator will be error-prone.  For best results, calibrate at a declination of -20 to +20."),
                    "/highdec_calibration_ok", _("Confirm Calibration at Large Declination")
                    );
            }
            if (error || !proceed)
                return;
        }

        StartGuiding();
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);
        pGuider->Reset(false);
    }
}
示例#14
0
GuideCamera *GuideCamera::Factory(const wxString& choice)
{
    GuideCamera *pReturn = NULL;

    try
    {
        if (choice.IsEmpty())
        {
            throw ERROR_INFO("CameraFactory called with choice.IsEmpty()");
        }

        Debug.AddLine(wxString::Format("CameraFactory(%s)", choice));

        if (false) // so else ifs can follow
        {
        }
#if defined (ASCOM_LATECAMERA)
        // do ascom first since it includes many choices, some of which match other choices below (like Simulator)
        else if (choice.Find(_T("ASCOM")) != wxNOT_FOUND) {
            pReturn = new Camera_ASCOMLateClass(choice);
        }
#endif
        else if (choice.Find(_("None")) + 1) {
        }
        else if (choice.Find(_T("Simulator")) + 1) {
            pReturn = new Camera_SimClass();
        }
#if defined (SAC42)
        else if (choice.Find(_T("SAC4-2")) + 1) {
            pReturn = new Camera_SAC42Class();
        }
#endif
#if defined (ATIK16)
        else if (choice.Find(_T("Atik 16 series")) + 1) {
            Camera_Atik16Class *pNewGuideCamera = new Camera_Atik16Class();
            pNewGuideCamera->HSModel = false;
            if (choice.Find(_T("color")))
                pNewGuideCamera->Color = true;
            else
                pNewGuideCamera->Color = false;
            pReturn = pNewGuideCamera;
        }
#endif
#if defined (ATIK_GEN3)
        else if (choice.Find(_T("Atik Gen3")) + 1) {
            Camera_Atik16Class *pNewGuideCamera = new Camera_Atik16Class();
            pNewGuideCamera->HSModel = true;
            if (choice.Find(_T("color")))
                pNewGuideCamera->Color = true;
            else
                pNewGuideCamera->Color = false;
            pReturn = pNewGuideCamera;
        }
#endif
#if defined (QGUIDE)
        else if (choice.Find(_T("CCD Labs Q-Guider")) + 1) {
            pReturn = new Camera_QGuiderClass();
            pReturn->Name = _T("Q-Guider");
        }
        else if (choice.Find(_T("MagZero MZ-5")) + 1) {
            pReturn = new Camera_QGuiderClass();
            pReturn->Name = _T("MagZero MZ-5");
        }
#endif
#if defined (QHY_CAMERA)
        else if (choice.Find(_T("QHY Camera")) != wxNOT_FOUND) {
            pReturn = new Camera_QHY();
        }
#endif
#if defined(ALTAIR)
		else if (choice.Find(_T("Altair Camera")) + 1)
		{
			pReturn = new Camera_Altair();
		}
#endif
#if defined(ZWO_ASI)
        else if (choice.Find(_T("ZWO ASI Camera")) + 1)
        {
            pReturn = new Camera_ZWO();
        }
#endif
#if defined (CAM_QHY5) // must come afer other QHY 5's since this pattern would match them
        else if (choice.Find(_T("QHY 5")) + 1) {
            pReturn = new Camera_QHY5Class();
        }
#endif
#if defined (OPENSSAG)
        else if (choice.Find(_T("Orion StarShoot Autoguider")) + 1) {
            pReturn = new Camera_OpenSSAGClass();
        }
#endif
#if defined (KWIQGUIDER)
        else if (choice.Find(_T("KWIQGuider")) + 1) {
            pReturn = new Camera_KWIQGuiderClass();
        }
#endif
#if defined (SSAG)
        else if (choice.Find(_T("StarShoot Autoguider")) + 1) {
            pReturn = new Camera_SSAGClass();
        }
#endif
#if defined (SSPIAG)
        else if (choice.Find(_T("StarShoot Planetary Imager & Autoguider")) + 1) {
            pReturn = new Camera_SSPIAGClass();
        }
#endif
#if defined (ORION_DSCI)
        else if (choice.Find(_T("Orion StarShoot DSCI")) + 1) {
            pReturn = new Camera_StarShootDSCIClass();
        }
#endif
#if defined (OPENCV_CAMERA)
        else if (choice.Find(_T("OpenCV webcam")) + 1) {
            int dev = 0;
            if (choice.Find(_T("2")) + 1)
            {
                dev = 1;
            }
            pReturn = new Camera_OpenCVClass(dev);
        }
#endif
#if defined (WDM_CAMERA)
        else if (choice.Find(_T("Windows WDM")) + 1) {
            pReturn = new Camera_WDMClass();
        }
#endif
#if defined (VFW_CAMERA)
        else if (choice.Find(_T("Windows VFW")) + 1) {
            pReturn = new Camera_VFWClass();
        }
#endif
#if defined (LE_SERIAL_CAMERA)
        else if (choice.Find(_T("Long exposure Serial webcam")) + 1) {
            pReturn = new Camera_LESerialWebcamClass();
        }
#endif
#if defined (LE_PARALLEL_CAMERA)
        else if (choice.Find( _T("Long exposure Parallel webcam")) + 1) {
            pReturn = new Camera_LEParallelWebcamClass();
        }
#endif
#if defined (LE_LXUSB_CAMERA)
        else if (choice.Find( _T("Long exposure LXUSB webcam")) + 1) {
            pReturn = new Camera_LELxUsbWebcamClass();
        }
#endif
#if defined (MEADE_DSI)
        else if (choice.Find(_T("Meade DSI I, II, or III")) + 1) {
            pReturn = new Camera_DSIClass();
        }
#endif
#if defined (STARFISH)
        else if (choice.Find(_T("Fishcamp Starfish")) + 1) {
            pReturn = new Camera_StarfishClass();
        }
#endif
#if defined (SXV)
        else if (choice.Find(_T("Starlight Xpress SXV")) + 1) {
            pReturn = new Camera_SXVClass();
        }
#endif
#if defined (OS_PL130)
        else if (choice.Find(_T("Opticstar PL-130M")) + 1) {
            Camera_OSPL130.Color=false;
            Camera_OSPL130.Name=_T("Opticstar PL-130M");
            pReturn = new Camera_OSPL130Class();
        }
        else if (choice.Find(_T("Opticstar PL-130C")) + 1) {
            Camera_OSPL130.Color=true;
            Camera_OSPL130.Name=_T("Opticstar PL-130C");
            pReturn = new Camera_OSPL130Class();
        }
#endif
#if defined (NEB_SBIG)
        else if (choice.Find(_T("Nebulosity")) + 1) {
            pReturn = new Camera_NebSBIGClass();
        }
#endif
#if defined (SBIGROTATOR_CAMERA)
        // must go above SBIG
        else if (choice.Find(_T("SBIG Rotator")) + 1) {
            pReturn = new Camera_SBIGRotatorClass();
        }
#endif
#if defined (SBIG)
        else if (choice.Find(_T("SBIG")) + 1) {
            pReturn = new Camera_SBIGClass();
        }
#endif
#if defined (FIREWIRE)
        else if (choice.Find(_T("The Imaging Source (DCAM Firewire)")) + 1) {
            pReturn = new Camera_FirewireClass();
        }
#endif
#if defined (INOVA_PLC)
        else if (choice.Find(_T("i-Nova PLC-M")) + 1) {
            pReturn = new Camera_INovaPLCClass();
        }
#endif
#if defined (INDI_CAMERA)
        else if (choice.Find(_T("INDI Camera")) + 1) {
            pReturn = new Camera_INDIClass();
        }
#endif
#if defined (V4L_CAMERA)
        else if (choice.Find(_T("V4L(2) Camera")) + 1) {
            // There is at least ONE V4L(2) device ... let's find out exactly
            DeviceInfo *deviceInfo = NULL;

            if (1 == Camera_VIDEODEVICE.NumberOfDevices()) {
                deviceInfo = Camera_VIDEODEVICE.GetDeviceAtIndex(0);

                Camera_VIDEODEVICE.SetDevice(deviceInfo->getDeviceName());
                Camera_VIDEODEVICE.SetVendor(deviceInfo->getVendorId());
                Camera_VIDEODEVICE.SetModel(deviceInfo->getModelId());

                Camera_VIDEODEVICE.Name = deviceInfo->getProduct();
            } else {
                wxArrayString choices;
                int choice = 0;

                if (-1 != (choice = wxGetSinglechoiceIndex(_("Select your camera"), _T("V4L(2) devices"), Camera_VIDEODEVICE.GetProductArray(choices)))) {
                    deviceInfo = Camera_VIDEODEVICE.GetDeviceAtIndex(choice);

                    Camera_VIDEODEVICE.SetDevice(deviceInfo->getDeviceName());
                    Camera_VIDEODEVICE.SetVendor(deviceInfo->getVendorId());
                    Camera_VIDEODEVICE.SetModel(deviceInfo->getModelId());

                    Camera_VIDEODEVICE.Name = deviceInfo->getProduct();
                } else {
                    throw ERROR_INFO("Camerafactory invalid V4L choice");
                }
            }

            pReturn = new Camera_VIDEODEVICEClass();
        }
#endif
        else {
            throw ERROR_INFO("CameraFactory: Unknown camera choice");
        }
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);
        if (pReturn)
        {
            delete pReturn;
            pReturn = NULL;
        }
    }

    return pReturn;
}
示例#15
0
/*
 * OnExposeComplete is the dispatch routine that is called when an image has been taken
 * by the background thread.
 *
 * It:
 * - causes the image to be redrawn by calling pGuider->UpateImageDisplay()
 * - calls the routine to update the guider state (which may do nothing)
 * - calls any other appropriate state update routine depending upon the current state
 * - updates button state based on appropriate state variables
 * - schedules another exposure if CaptureActive is stil true
 *
 */
void MyFrame::OnExposeComplete(usImage *pNewFrame, bool err)
{
    try
    {
        Debug.Write("Processing an image\n");

        m_exposurePending = false;

        if (pGuider->GetPauseType() == PAUSE_FULL)
        {
            delete pNewFrame;
            Debug.Write("guider is paused, ignoring frame, not scheduling exposure\n");
            return;
        }

        if (err)
        {
            Debug.Write("OnExposeComplete(): Capture Error reported\n");

            delete pNewFrame;

            StopCapturing();
            if (pGuider->IsCalibratingOrGuiding())
            {
                pGuider->StopGuiding();
                pGuider->UpdateImageDisplay();
            }
            pGuider->Reset(false);
            CaptureActive = m_continueCapturing;
            UpdateButtonsStatus();
            PhdController::AbortController("Error reported capturing image");
            SetStatusText(_("Stopped."));

            // some camera drivers disconnect the camera on error
            if (!pCamera->Connected)
                SetStatusText(wxEmptyString, 2);

            throw ERROR_INFO("Error reported capturing image");
        }
        ++m_frameCounter;

        if (m_rawImageMode && !m_rawImageModeWarningDone)
        {
            WarnRawImageMode();
            m_rawImageModeWarningDone = true;
        }

        // check for dark frame compatibility in case the frame size changed (binning changed)
        if (pCamera->DarkFrameSize() != m_prevDarkFrameSize)
        {
            CheckDarkFrameGeometry();
        }

        pGuider->UpdateGuideState(pNewFrame, !m_continueCapturing);
        pNewFrame = NULL; // the guider owns it now

        PhdController::UpdateControllerState();

        Debug.Write(wxString::Format("OnExposeCompete: CaptureActive=%d m_continueCapturing=%d\n",
            CaptureActive, m_continueCapturing));

        CaptureActive = m_continueCapturing;

        if (CaptureActive)
        {
            ScheduleExposure();
        }
        else
        {
            FinishStop();
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        UpdateButtonsStatus();
    }
}
示例#16
0
bool WorkerThread::HandleExpose(MyFrame::EXPOSE_REQUEST *req)
{
    bool bError = false;

    try
    {
        if (WorkerThread::MilliSleep(m_pFrame->GetTimeLapse(), INT_ANY))
        {
            throw ERROR_INFO("Time lapse interrupted");
        }

        if (pCamera->HasNonGuiCapture())
        {
            Debug.Write(wxString::Format("Handling exposure in thread, d=%d o=%x r=(%d,%d,%d,%d)\n", req->exposureDuration,
                                         req->options, req->subframe.x, req->subframe.y, req->subframe.width, req->subframe.height));

            if (GuideCamera::Capture(pCamera, req->exposureDuration, *req->pImage, req->options, req->subframe))
            {
                throw ERROR_INFO("Capture failed");
            }
        }
        else
        {
            Debug.Write(wxString::Format("Handling exposure in myFrame, d=%d o=%x r=(%d,%d,%d,%d)\n", req->exposureDuration,
                                         req->options, req->subframe.x, req->subframe.y, req->subframe.width, req->subframe.height));

            wxSemaphore semaphore;
            req->pSemaphore = &semaphore;

            wxCommandEvent evt(REQUEST_EXPOSURE_EVENT, GetId());
            evt.SetClientData(req);
            wxQueueEvent(m_pFrame, evt.Clone());

            // wait for the request to complete
            req->pSemaphore->Wait();

            bError = req->error;
            req->pSemaphore = NULL;
        }

        Debug.AddLine("Exposure complete");

        if (!bError)
        {
            switch (m_pFrame->GetNoiseReductionMethod())
            {
                case NR_NONE:
                    break;
                case NR_2x2MEAN:
                    QuickLRecon(*req->pImage);
                    break;
                case NR_3x3MEDIAN:
                    Median3(*req->pImage);
                    break;
            }

            req->pImage->CalcStats();
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;
    }

    return  bError;
}
示例#17
0
bool StepGuider::MoveToCenter()
{
    bool bError = false;

    try
    {
        int positionUpDown = CurrentPosition(UP);

        if (positionUpDown > 0)
        {
            MoveResultInfo result;
            Move(DOWN, positionUpDown, true, &result);
            if (result.amountMoved != positionUpDown)
            {
                throw ERROR_INFO("MoveToCenter() failed to step DOWN");
            }
        }
        else if (positionUpDown < 0)
        {
            positionUpDown = -positionUpDown;

            MoveResultInfo result;
            Move(UP, positionUpDown, true, &result);
            if (result.amountMoved != positionUpDown)
            {
                throw ERROR_INFO("MoveToCenter() failed to step UP");
            }
        }

        int positionLeftRight = CurrentPosition(LEFT);

        if (positionLeftRight > 0)
        {
            MoveResultInfo result;
            Move(RIGHT, positionLeftRight, true, &result);
            if (result.amountMoved != positionLeftRight)
            {
                throw ERROR_INFO("MoveToCenter() failed to step RIGHT");
            }
        }
        else if (positionLeftRight < 0)
        {
            positionLeftRight = -positionLeftRight;

            MoveResultInfo result;
            Move(LEFT, positionLeftRight, true, &result);
            if (result.amountMoved != positionLeftRight)
            {
                throw ERROR_INFO("MoveToCenter() failed to step LEFT");
            }
        }

        assert(m_xOffset == 0);
        assert(m_yOffset == 0);
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        bError = true;
    }

    return bError;
}
示例#18
0
Mount::MOVE_RESULT WorkerThread::HandleMove(MyFrame::PHD_MOVE_REQUEST *pArgs)
{
    Mount::MOVE_RESULT result = Mount::MOVE_OK;

    try
    {
        if (pArgs->pMount->HasNonGuiMove())
        {
            Debug.AddLine(wxString::Format("Handling move in thread for %s dir=%d",
                    pArgs->pMount->GetMountClassName(),
                    pArgs->direction));

            if (pArgs->calibrationMove)
            {
                Debug.AddLine("calibration move");

                result = pArgs->pMount->CalibrationMove(pArgs->direction, pArgs->duration);
                if (result != Mount::MOVE_OK)
                {
                    throw ERROR_INFO("CalibrationMove failed");
                }
            }
            else
            {
                Debug.AddLine(wxString::Format("endpoint = (%.2f, %.2f)",
                    pArgs->vectorEndpoint.X, pArgs->vectorEndpoint.Y));

                result = pArgs->pMount->Move(pArgs->vectorEndpoint, pArgs->moveType);
                if (result != Mount::MOVE_OK)
                {
                    throw ERROR_INFO("Move failed");
                }
            }
        }
        else
        {
            // we don't have a non-gui guide function, so we send this to the
            // main frame routine that handles guides requests

            Debug.AddLine("Sending move to myFrame");

            wxSemaphore semaphore;
            pArgs->pSemaphore = &semaphore;

            wxCommandEvent evt(REQUEST_MOUNT_MOVE_EVENT, GetId());
            evt.SetClientData(pArgs);
            wxQueueEvent(m_pFrame, evt.Clone());

            // wait for the request to complete
            pArgs->pSemaphore->Wait();

            pArgs->pSemaphore = NULL;
            result = pArgs->moveResult;

            if (result != Mount::MOVE_OK)
            {
                throw ERROR_INFO("myFrame handled move failed");
            }
        }
    }
    catch (wxString Msg)
    {
        POSSIBLY_UNUSED(Msg);
        if (result == Mount::MOVE_OK)
            result = Mount::MOVE_ERROR;
    }

    Debug.AddLine(wxString::Format("move complete, result=%d", result));

    return result;
}
示例#19
0
Mount::MOVE_RESULT StepGuider::Move(GUIDE_DIRECTION direction, int steps, bool normalMove, MoveResultInfo *moveResult)
{
    MOVE_RESULT result = MOVE_OK;
    bool limitReached = false;

    try
    {
        Debug.AddLine(wxString::Format("Move(%d, %d, %d)", direction, steps, normalMove));

        // Compute the required guide steps
        if (!m_guidingEnabled)
        {
            throw THROW_INFO("Guiding disabled");
        }

        // Acutally do the guide
        assert(steps >= 0);

        if (steps > 0)
        {
            int yDirection = 0;
            int xDirection = 0;

            switch (direction)
            {
                case UP:
                    yDirection = 1;
                    break;
                case DOWN:
                    yDirection = -1;
                    break;
                case RIGHT:
                    xDirection = 1;
                    break;
                case LEFT:
                    xDirection = -1;
                    break;
                default:
                    throw ERROR_INFO("StepGuider::Move(): invalid direction");
                    break;
            }

            assert(yDirection == 0 || xDirection == 0);
            assert(yDirection != 0 || xDirection != 0);

            Debug.AddLine(wxString::Format("stepping direction=%d steps=%d xDirection=%d yDirection=%d", direction, steps, xDirection, yDirection));

            if (WouldHitLimit(direction, steps))
            {
                int new_steps = MaxPosition(direction) - 1 - CurrentPosition(direction);
                Debug.AddLine(wxString::Format("StepGuider step would hit limit: truncate move direction=%d steps=%d => %d", direction, steps, new_steps));
                steps = new_steps;
                limitReached = true;
            }

            if (steps > 0)
            {
                if (Step(direction, steps))
                {
                    throw ERROR_INFO("step failed");
                }

                m_xOffset += xDirection * steps;
                m_yOffset += yDirection * steps;

                Debug.AddLine(wxString::Format("stepped: xOffset=%d yOffset=%d", m_xOffset, m_yOffset));
            }
        }
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);
        steps = 0;
        result = MOVE_ERROR;
    }

    if (moveResult)
    {
        moveResult->amountMoved = steps;
        moveResult->limited = limitReached;
    }

    return result;
}
double GuideAlgorithmResistSwitch::result(double input)
{
    double dReturn = input;

    m_history.Add(input);
    m_history.RemoveAt(0);

    try
    {
        if (fabs(input) < m_minMove)
        {
            throw THROW_INFO("input < m_minMove");
        }

        if (m_fastSwitchEnabled)
        {
            double thresh = 3.0 * m_minMove;
            if (sign(input) != m_currentSide && fabs(input) > thresh)
            {
                Debug.Write(wxString::Format("resist switch: large excursion: input %.2f thresh %.2f direction from %d to %d\n", input, thresh, m_currentSide, sign(input)));
                // force switch
                m_currentSide = 0;
                unsigned int i;
                for (i = 0; i < HISTORY_SIZE - 3; i++)
                    m_history[i] = 0.0;
                for (; i < HISTORY_SIZE; i++)
                    m_history[i] = input;
            }
        }

        int decHistory = 0;

        for (unsigned int i = 0; i < m_history.GetCount(); i++)
        {
            if (fabs(m_history[i]) > m_minMove)
            {
                decHistory += sign(m_history[i]);
            }
        }

        if (m_currentSide == 0 || sign(m_currentSide) == -sign(decHistory))
        {
            if (abs(decHistory) < 3)
            {
                throw THROW_INFO("not compelling enough");
            }

            double oldest = 0.0;
            double newest = 0.0;

            for (int i = 0; i < 3; i++)
            {
                oldest += m_history[i];
                newest += m_history[m_history.GetCount() - (i + 1)];
            }

            if (fabs(newest) <= fabs(oldest))
            {
                throw THROW_INFO("Not getting worse");
            }

            Debug.Write(wxString::Format("switching direction from %d to %d - decHistory=%d oldest=%.2f newest=%.2f\n", m_currentSide, sign(decHistory), decHistory, oldest, newest));

            m_currentSide = sign(decHistory);
        }

        if (m_currentSide != sign(input))
        {
            throw THROW_INFO("must have overshot -- vetoing move");
        }
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);
        dReturn = 0.0;
    }

    Debug.Write(wxString::Format("GuideAlgorithmResistSwitch::Result() returns %.2f from input %.2f\n", dReturn, input));

    return dReturn * m_aggression;
}
示例#21
0
文件: scope_ascom.cpp 项目: rwg0/phd2
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;
}
示例#22
0
文件: star.cpp 项目: AndresPozo/phd2
bool Star::Find(const usImage *pImg, int searchRegion, int base_x, int base_y, FindMode mode)
{
    FindResult Result = STAR_OK;
    double newX = base_x;
    double newY = base_y;

    try
    {
        Debug.Write(wxString::Format("Star::Find(%d, %d, %d, %d, (%d,%d,%d,%d))\n", searchRegion, base_x, base_y, mode,
            pImg->Subframe.x, pImg->Subframe.y, pImg->Subframe.width, pImg->Subframe.height));

        if (base_x < 0 || base_y < 0)
        {
            throw ERROR_INFO("coordinates are invalid");
        }

        int minx, miny, maxx, maxy;

        if (pImg->Subframe.IsEmpty())
        {
            minx = miny = 0;
            maxx = pImg->Size.GetWidth() - 1;
            maxy = pImg->Size.GetHeight() - 1;
        }
        else
        {
            minx = pImg->Subframe.GetLeft();
            maxx = pImg->Subframe.GetRight();
            miny = pImg->Subframe.GetTop();
            maxy = pImg->Subframe.GetBottom();
        }

        // search region bounds
        int start_x = wxMax(base_x - searchRegion, minx);
        int end_x   = wxMin(base_x + searchRegion, maxx);
        int start_y = wxMax(base_y - searchRegion, miny);
        int end_y   = wxMin(base_y + searchRegion, maxy);

        const unsigned short *imgdata = pImg->ImageData;
        int rowsize = pImg->Size.GetWidth();

        int peak_x = 0, peak_y = 0;
        unsigned int peak_val = 0;
        unsigned short max3[3] = { 0, 0, 0 };

        if (mode == FIND_PEAK)
        {
            for (int y = start_y; y <= end_y; y++)
            {
                for (int x = start_x; x <= end_x; x++)
                {
                    unsigned short val = imgdata[y * rowsize + x];

                    if (val > peak_val)
                    {
                        peak_val = val;
                        peak_x = x;
                        peak_y = y;
                    }
                }
            }

            PeakVal = peak_val;
        }
        else
        {
            // find the peak value within the search region using a smoothing function
            // also check for saturation

            for (int y = start_y + 1; y <= end_y - 1; y++)
            {
                for (int x = start_x + 1; x <= end_x - 1; x++)
                {
                    unsigned short p = imgdata[y * rowsize + x];
                    unsigned int val =
                        4 * (unsigned int) p +
                        imgdata[(y - 1) * rowsize + (x - 1)] +
                        imgdata[(y - 1) * rowsize + (x + 1)] +
                        imgdata[(y + 1) * rowsize + (x - 1)] +
                        imgdata[(y + 1) * rowsize + (x + 1)] +
                        2 * imgdata[(y - 1) * rowsize + (x + 0)] +
                        2 * imgdata[(y + 0) * rowsize + (x - 1)] +
                        2 * imgdata[(y + 0) * rowsize + (x + 1)] +
                        2 * imgdata[(y + 1) * rowsize + (x + 0)];

                    if (val > peak_val)
                    {
                        peak_val = val;
                        peak_x = x;
                        peak_y = y;
                    }

                    if (p > max3[0])
                        std::swap(p, max3[0]);
                    if (p > max3[1])
                        std::swap(p, max3[1]);
                    if (p > max3[2])
                        std::swap(p, max3[2]);
                }
            }

            PeakVal = max3[0];   // raw peak val
            peak_val /= 16; // smoothed peak value
        }

        // meaure noise in the annulus with inner radius A and outer radius B
        int const A = 7;   // inner radius
        int const B = 12;  // outer radius
        int const A2 = A * A;
        int const B2 = B * B;

        // center window around peak value
        start_x = wxMax(peak_x - B, minx);
        end_x = wxMin(peak_x + B, maxx);
        start_y = wxMax(peak_y - B, miny);
        end_y = wxMin(peak_y + B, maxy);

        // find the mean and stdev of the background

        double sum = 0.0;
        double a = 0.0;
        double q = 0.0;
        unsigned int nbg = 0;

        const unsigned short *row = imgdata + rowsize * start_y;
        for (int y = start_y; y <= end_y; y++, row += rowsize)
        {
            int dy = y - peak_y;
            int dy2 = dy * dy;
            for (int x = start_x; x <= end_x; x++)
            {
                int dx = x - peak_x;
                int r2 = dx * dx + dy2;

                // exclude points not in annulus
                if (r2 <= A2 || r2 > B2)
                    continue;

                double const val = (double) row[x];
                sum += val;
                ++nbg;
                double const k = (double) nbg;
                double const a0 = a;
                a += (val - a) / k;
                q += (val - a0) * (val - a);
            }
        }

        double const mean_bg = sum / (double) nbg;
        double const sigma2_bg = q / (double) (nbg - 1);
        double const sigma_bg = sqrt(sigma2_bg);
        unsigned short thresh;

        double cx = 0.0;
        double cy = 0.0;
        double mass = 0.0;
        unsigned int n;

        std::vector<R2M> hfrvec;

        if (mode == FIND_PEAK)
        {
            mass = peak_val;
            n = 1;
            thresh = 0;
        }
        else
        {
            thresh = (unsigned short)(mean_bg + 3.0 * sigma_bg + 0.5);

            // find pixels over threshold within aperture; compute mass and centroid

            start_x = wxMax(peak_x - A, minx);
            end_x = wxMin(peak_x + A, maxx);
            start_y = wxMax(peak_y - A, miny);
            end_y = wxMin(peak_y + A, maxy);

            n = 0;

            row = imgdata + rowsize * start_y;
            for (int y = start_y; y <= end_y; y++, row += rowsize)
            {
                int dy = y - peak_y;
                int dy2 = dy * dy;
                if (dy2 > A2)
                    continue;

                for (int x = start_x; x <= end_x; x++)
                {
                    int dx = x - peak_x;

                    // exclude points outside aperture
                    if (dx * dx + dy2 > A2)
                        continue;

                    // exclude points below threshold
                    unsigned short val = row[x];
                    if (val < thresh)
                        continue;

                    double const d = (double) val - mean_bg;

                    cx += dx * d;
                    cy += dy * d;
                    mass += d;
                    ++n;

                    hfrvec.push_back(R2M(x, y, d));
                }
            }
        }

        Mass = mass;

        // SNR estimate from: Measuring the Signal-to-Noise Ratio S/N of the CCD Image of a Star or Nebula, J.H.Simonetti, 2004 January 8
        //     http://www.phys.vt.edu/~jhs/phys3154/snr20040108.pdf
        double const gain = .5; // electrons per ADU, nominal
        SNR = n > 0 ? mass / sqrt(mass / gain + sigma2_bg * (double) n * (1.0 + 1.0 / (double) nbg)) : 0.0;

        double const LOW_SNR = 3.0;

        // a few scattered pixels over threshold can give a false positive
        // avoid this by requiring the smoothed peak value to be above the threshold
        if (peak_val <= thresh && SNR >= LOW_SNR)
        {
            Debug.Write(wxString::Format("Star::Find false star n=%u nbg=%u bg=%.1f sigma=%.1f thresh=%u peak=%u\n", n, nbg, mean_bg, sigma_bg, thresh, peak_val));
            SNR = LOW_SNR - 0.1;
        }

        if (mass < 10.0)
            Result = STAR_LOWMASS;
        else if (SNR < LOW_SNR)
            Result = STAR_LOWSNR;
        else
        {
            newX = peak_x + cx / mass;
            newY = peak_y + cy / mass;

            HFD = 2.0 * hfr(hfrvec, newX, newY, mass);

            // even at saturation, the max values may vary a bit due to noise
            // Call it saturated if the the top three values are within 32 parts per 65535 of max for 16-bit cameras,
            // or within 1 part per 191 for 8-bit cameras
            unsigned int d = (unsigned int) (max3[0] - max3[2]);
            unsigned int mx = (unsigned int) max3[0];

            // remove pedestal
            if (mx >= pImg->Pedestal)
                mx -= pImg->Pedestal;
            else
                mx = 0; // unlikely

            if (pImg->BitsPerPixel < 12)
            {
                if (d * 191U < 1U * mx)
                    Result = STAR_SATURATED;
            }
            else
            {
                if (d * 65535U < 32U * mx)
                    Result = STAR_SATURATED;
            }
        }
    }
    catch (const wxString& Msg)
    {
        POSSIBLY_UNUSED(Msg);

        if (Result == STAR_OK)
        {
            Result = STAR_ERROR;
        }
    }

    // update state
    SetXY(newX, newY);
    m_lastFindResult = Result;

    bool wasFound = WasFound(Result);

    if (!IsValid() || Result == STAR_ERROR)
    {
        Mass = 0.0;
        SNR = 0.0;
        HFD = 0.0;
    }

    Debug.Write(wxString::Format("Star::Find returns %d (%d), X=%.2f, Y=%.2f, Mass=%.f, SNR=%.1f, Peak=%hu HFD=%.1f\n",
        wasFound, Result, newX, newY, Mass, SNR, PeakVal, HFD));

    return wasFound;
}