1 /*
2  *  testguide.cpp
3  *  PHD Guiding
4  *
5  *  Created by Craig Stark.
6  *  Copyright (c) 2006-2010 Craig Stark.
7  *  All rights reserved.
8  *
9  *  This source code is distributed under the following "BSD" license
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions are met:
12  *    Redistributions of source code must retain the above copyright notice,
13  *     this list of conditions and the following disclaimer.
14  *    Redistributions in binary form must reproduce the above copyright notice,
15  *     this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *    Neither the name of Craig Stark, Stark Labs nor the names of its
18  *     contributors may be used to endorse or promote products derived from
19  *     this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  *  POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include "phd.h"
36 
37 class TestGuideDialog : public wxDialog
38 {
39     wxButton *NButton1, *SButton1, *EButton1, *WButton1;
40     wxButton *NButton2, *SButton2, *EButton2, *WButton2;
41     wxSpinCtrlDouble *pulseDurationSpinCtrl;
42     wxChoice *ditherTypeChoice;
43     wxSpinCtrlDouble *ditherScaleSpinCtrl;
44     wxCheckBox *raOnlyCheckBox;
45 public:
46     TestGuideDialog();
47     ~TestGuideDialog();
48     wxSizer *InitMountControls();
49     void OnButton(wxCommandEvent& evt);
50     void OnReset(wxCommandEvent& evt);
51     void OnDitherScaleChange(wxSpinDoubleEvent& evt);
52     void OnRAOnlyChecked(wxCommandEvent& evt);
53     void OnDither(wxCommandEvent& evt);
54     void OnClose(wxCloseEvent& evt);
55     void OnAppStateNotify(wxCommandEvent& evt);
56     DECLARE_EVENT_TABLE()
57 };
58 
59 enum
60 {
61     ID_PULSEDURATION = 330001,
62     ID_RESET,
63     ID_DITHERTYPE,
64     ID_DITHERSCALE,
65     ID_RAONLY,
66     ID_DITHER,
67 };
68 
wxBEGIN_EVENT_TABLE(TestGuideDialog,wxDialog)69 wxBEGIN_EVENT_TABLE(TestGuideDialog, wxDialog)
70     EVT_BUTTON(MGUIDE1_UP,TestGuideDialog::OnButton)
71     EVT_BUTTON(MGUIDE1_DOWN,TestGuideDialog::OnButton)
72     EVT_BUTTON(MGUIDE1_RIGHT,TestGuideDialog::OnButton)
73     EVT_BUTTON(MGUIDE1_LEFT,TestGuideDialog::OnButton)
74     EVT_BUTTON(MGUIDE2_UP,TestGuideDialog::OnButton)
75     EVT_BUTTON(MGUIDE2_DOWN,TestGuideDialog::OnButton)
76     EVT_BUTTON(MGUIDE2_RIGHT,TestGuideDialog::OnButton)
77     EVT_BUTTON(MGUIDE2_LEFT,TestGuideDialog::OnButton)
78     EVT_BUTTON(ID_RESET, TestGuideDialog::OnReset)
79     EVT_CLOSE(TestGuideDialog::OnClose)
80     EVT_COMMAND(wxID_ANY, APPSTATE_NOTIFY_EVENT, TestGuideDialog::OnAppStateNotify)
81     EVT_SPINCTRLDOUBLE(ID_DITHERSCALE, TestGuideDialog::OnDitherScaleChange)
82     EVT_CHECKBOX(ID_RAONLY, TestGuideDialog::OnRAOnlyChecked)
83     EVT_BUTTON(ID_DITHER, TestGuideDialog::OnDither)
84 wxEND_EVENT_TABLE()
85 
86 wxSizer *TestGuideDialog::InitMountControls()
87 {
88     wxSizer *sz1 = new wxBoxSizer(wxHORIZONTAL);
89 
90     sz1->Add(new wxStaticText(this, wxID_ANY, _("Guide Pulse Duration (ms):")),
91         wxSizerFlags().Right().Border(wxRIGHT, 5).Align(wxALIGN_CENTER_VERTICAL));
92     pulseDurationSpinCtrl = pFrame->MakeSpinCtrlDouble(this, ID_PULSEDURATION, wxEmptyString, wxDefaultPosition,
93         wxSize(StringWidth(GetParent(), "00000"), -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT, 100.0, 5000.0, 100.0, 100.0);
94     pulseDurationSpinCtrl->SetDigits(0);
95     pulseDurationSpinCtrl->SetToolTip(_("Manual guide pulse duration (milliseconds)"));
96     Mount *mnt = TheScope();
97     int val = pConfig->Profile.GetInt("/ManualGuide/duration", mnt->CalibrationMoveSize());
98     pulseDurationSpinCtrl->SetValue((double) val);
99     sz1->Add(pulseDurationSpinCtrl, wxSizerFlags().Left().Border(wxRIGHT, 10).Align(wxALIGN_CENTER_VERTICAL));
100 
101     wxButton *btn = new wxButton(this, ID_RESET, _("Reset"));
102     sz1->Add(btn, wxSizerFlags().Left().Border(wxRIGHT, 10).Align(wxALIGN_CENTER_VERTICAL));
103     btn->SetToolTip(_("Reset the manual guide pulse duration to the default value. The default value is the calibration step size."));
104 
105     wxSizer *sz2 = new wxBoxSizer(wxHORIZONTAL);
106 
107     sz2->Add(new wxStaticText(this, wxID_ANY, _("Dither")), wxSizerFlags().Right().Border(wxRIGHT, 5).Align(wxALIGN_CENTER_VERTICAL));
108     wxArrayString choices;
109     choices.Add(_("MOVE1 (+/- 0.5)"));
110     choices.Add(_("MOVE2 (+/- 1.0)"));
111     choices.Add(_("MOVE3 (+/- 2.0)"));
112     choices.Add(_("MOVE4 (+/- 3.0)"));
113     choices.Add(_("MOVE5 (+/- 5.0)"));
114     ditherTypeChoice = new wxChoice(this, ID_DITHERTYPE, wxDefaultPosition, wxDefaultSize, choices);
115     ditherTypeChoice->Select(pConfig->Profile.GetInt("/ManualGuide/DitherType", 4) - 1);
116     ditherTypeChoice->SetToolTip(_("Select the dither amount type. Imaging applications have the option of sending each of these dither amounts to PHD."));
117     sz2->Add(ditherTypeChoice, wxSizerFlags().Left().Border(wxRIGHT, 10).Align(wxALIGN_CENTER_VERTICAL));
118 
119     sz2->Add(new wxStaticText(this, wxID_ANY, _("Scale")), wxSizerFlags().Right().Border(wxRIGHT, 5).Align(wxALIGN_CENTER_VERTICAL));
120     ditherScaleSpinCtrl = pFrame->MakeSpinCtrlDouble(this, ID_DITHERSCALE, wxEmptyString, wxDefaultPosition,
121         wxSize(StringWidth(GetParent(), "000.0"), -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT, 0.1, 100.0, 1.0, 1.0);
122     ditherScaleSpinCtrl->SetDigits(1);
123     ditherScaleSpinCtrl->SetValue(pFrame->GetDitherScaleFactor());
124     ditherScaleSpinCtrl->SetToolTip(_("Scale factor for dithering. The dither amount type is multiplied by this value to get the actual dither amount. Changing the value here affects both manual dithering and dithering from imaging applications connected to PHD."));
125     sz2->Add(ditherScaleSpinCtrl, wxSizerFlags().Left().Border(wxRIGHT, 10).Align(wxALIGN_CENTER_VERTICAL));
126 
127     raOnlyCheckBox = new wxCheckBox(this, ID_RAONLY, _("RA Only"));
128     sz2->Add(raOnlyCheckBox, wxSizerFlags().Left().Border(wxRIGHT, 10).Align(wxALIGN_CENTER_VERTICAL));
129     raOnlyCheckBox->SetValue(pFrame->GetDitherRaOnly());
130     raOnlyCheckBox->SetToolTip(_("Dither on RA axis only. Changing the value here affects both manual dithering and dithering from imaging applications connected to PHD."));
131 
132     btn = new wxButton(this, ID_DITHER, _("Dither"));
133     btn->SetToolTip(_("Move the guider lock position a random amount on each axis, up to the maximum value determined by the dither type and the dither scale factor."));
134     sz2->Add(btn, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
135 
136     wxSizer *sz3 = new wxBoxSizer(wxVERTICAL);
137     sz3->Add(sz1, wxSizerFlags().Border(wxALL, 10).Align(wxALIGN_CENTER_HORIZONTAL));
138     sz3->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxSize(1, -1)),
139         wxSizerFlags().Border(wxALL, 3).Align(wxALIGN_CENTER_VERTICAL).Expand());
140     sz3->Add(sz2, wxSizerFlags().Border(wxALL, 10));
141 
142     return sz3;
143 }
144 
TestGuideDialog()145 TestGuideDialog::TestGuideDialog() :
146     wxDialog(pFrame, wxID_ANY, _("Manual Guide"), wxPoint(-1,-1), wxSize(300,300))
147 {
148     wxBoxSizer *pOuterSizer = new wxBoxSizer(wxVERTICAL);
149     wxStaticBoxSizer *pWrapperSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Mount"));
150     wxGridSizer *sizer = new wxGridSizer(3,3,0,0);
151     static wxString AoLabels[] = {_("Up"), _("Down"), _("Right"), _("Left") };
152     static wxString ScopeLabels[] = {_("North"), _("South"), _("East"), _("West") };
153 
154     bool usingAo = pSecondaryMount && pSecondaryMount->IsConnected();
155 
156     wxString *pLabels;
157 
158     if (usingAo)
159     {
160         pLabels = AoLabels;
161         pWrapperSizer->GetStaticBox()->SetLabel(_("AO"));
162     }
163     else
164     {
165         pLabels = ScopeLabels;
166     }
167 
168     // Build the buttons for the primary mount
169 
170     NButton1 = new wxButton(this, MGUIDE1_UP, pLabels[0], wxPoint(-1,-1),wxSize(-1,-1));
171     SButton1 = new wxButton(this, MGUIDE1_DOWN, pLabels[1], wxPoint(-1,-1),wxSize(-1,-1));
172     EButton1 = new wxButton(this, MGUIDE1_RIGHT, pLabels[2], wxPoint(-1,-1),wxSize(-1,-1));
173     WButton1 = new wxButton(this, MGUIDE1_LEFT, pLabels[3], wxPoint(-1,-1),wxSize(-1,-1));
174 
175     sizer->AddStretchSpacer();
176     sizer->Add(NButton1,wxSizerFlags().Expand().Border(wxALL,6));
177     sizer->AddStretchSpacer();
178     sizer->Add(WButton1,wxSizerFlags().Expand().Border(wxALL,6));
179     sizer->AddStretchSpacer();
180     sizer->Add(EButton1,wxSizerFlags().Expand().Border(wxALL,6));
181     sizer->AddStretchSpacer();
182     sizer->Add(SButton1,wxSizerFlags().Expand().Border(wxALL,6));
183 
184     pWrapperSizer->Add(sizer, wxSizerFlags().Center());
185     if (!usingAo)
186     {
187         pWrapperSizer->Add(InitMountControls());
188     }
189     pOuterSizer->Add(pWrapperSizer,wxSizerFlags().Border(wxALL,3).Center().Expand());
190 
191     if (usingAo)
192     {
193         pWrapperSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Mount"));
194         sizer = new wxGridSizer(3,3,0,0);
195 
196         pLabels = ScopeLabels;
197 
198         NButton2 = new wxButton(this, MGUIDE2_UP, pLabels[0], wxPoint(-1,-1),wxSize(-1,-1));
199         SButton2 = new wxButton(this, MGUIDE2_DOWN, pLabels[1], wxPoint(-1,-1),wxSize(-1,-1));
200         EButton2 = new wxButton(this, MGUIDE2_RIGHT, pLabels[2], wxPoint(-1,-1),wxSize(-1,-1));
201         WButton2 = new wxButton(this, MGUIDE2_LEFT, pLabels[3], wxPoint(-1,-1),wxSize(-1,-1));
202 
203         sizer->AddStretchSpacer();
204         sizer->Add(NButton2,wxSizerFlags().Expand().Border(wxALL,6));
205         sizer->AddStretchSpacer();
206         sizer->Add(WButton2,wxSizerFlags().Expand().Border(wxALL,6));
207         sizer->AddStretchSpacer();
208         sizer->Add(EButton2,wxSizerFlags().Expand().Border(wxALL,6));
209         sizer->AddStretchSpacer();
210         sizer->Add(SButton2,wxSizerFlags().Expand().Border(wxALL,6));
211 
212         pWrapperSizer->Add(sizer, wxSizerFlags().Center());
213         pWrapperSizer->Add(InitMountControls());
214         pOuterSizer->Add(pWrapperSizer,wxSizerFlags().Border(wxALL,3).Center().Expand());
215     }
216 
217     pOuterSizer->AddSpacer(30);
218     pOuterSizer->SetSizeHints(this);
219     SetSizerAndFit(pOuterSizer);
220 }
221 
~TestGuideDialog(void)222 TestGuideDialog::~TestGuideDialog(void)
223 {
224     pFrame->pManualGuide = 0;
225 }
226 
OnClose(wxCloseEvent & evt)227 void TestGuideDialog::OnClose(wxCloseEvent& evt)
228 {
229     int val = (int) floor(pulseDurationSpinCtrl->GetValue());
230     pConfig->Profile.SetInt("/ManualGuide/duration", val);
231     pConfig->Profile.SetInt("/ManualGuide/DitherType", ditherTypeChoice->GetSelection() + 1);
232     Destroy();
233 }
234 
OnReset(wxCommandEvent & evt)235 void TestGuideDialog::OnReset(wxCommandEvent& evt)
236 {
237     Mount *scope = TheScope();
238     pulseDurationSpinCtrl->SetValue((double) scope->CalibrationMoveSize());
239 }
240 
OnAppStateNotify(wxCommandEvent & evt)241 void TestGuideDialog::OnAppStateNotify(wxCommandEvent& evt)
242 {
243     ditherScaleSpinCtrl->SetValue(pFrame->GetDitherScaleFactor());
244     raOnlyCheckBox->SetValue(pFrame->GetDitherRaOnly());
245 }
246 
OnDitherScaleChange(wxSpinDoubleEvent & evt)247 void TestGuideDialog::OnDitherScaleChange(wxSpinDoubleEvent& evt)
248 {
249     pFrame->SetDitherScaleFactor(ditherScaleSpinCtrl->GetValue());
250 }
251 
OnRAOnlyChecked(wxCommandEvent & evt)252 void TestGuideDialog::OnRAOnlyChecked(wxCommandEvent& evt)
253 {
254     pFrame->SetDitherRaOnly(raOnlyCheckBox->GetValue());
255 }
256 
OnDither(wxCommandEvent & evt)257 void TestGuideDialog::OnDither(wxCommandEvent& evt)
258 {
259     int ditherType = ditherTypeChoice->GetSelection() + 1;
260     wxString errMsg;
261     PhdController::DitherCompat(MyFrame::GetDitherAmount(ditherType), &errMsg);
262 }
263 
ManualMove(Mount * mount,GUIDE_DIRECTION dir,int dur)264 inline static void ManualMove(Mount *mount, GUIDE_DIRECTION dir, int dur)
265 {
266     if (mount && mount->IsConnected())
267     {
268         if (mount->IsStepGuider())
269         {
270             dur = 1;
271             Debug.Write(wxString::Format("Manual Guide: %s %d step(s)\n", mount->DirectionStr(dir), dur));
272         }
273         else
274             Debug.Write(wxString::Format("Manual Guide: %s %d ms\n", mount->DirectionStr(dir), dur));
275 
276         pFrame->ScheduleManualMove(mount, dir, dur);
277     }
278 }
279 
OnButton(wxCommandEvent & evt)280 void TestGuideDialog::OnButton(wxCommandEvent &evt)
281 {
282     int duration = (int) floor(pulseDurationSpinCtrl->GetValue());
283 
284     switch (evt.GetId())
285     {
286         case MGUIDE1_UP:
287             ManualMove(pMount, UP, duration);
288             break;
289         case MGUIDE1_DOWN:
290             ManualMove(pMount, DOWN, duration);
291             break;
292         case MGUIDE1_RIGHT:
293             ManualMove(pMount, RIGHT, duration);
294             break;
295         case MGUIDE1_LEFT:
296             ManualMove(pMount, LEFT, duration);
297             break;
298         case MGUIDE2_UP:
299             ManualMove(pSecondaryMount, UP, duration);
300             break;
301         case MGUIDE2_DOWN:
302             ManualMove(pSecondaryMount, DOWN, duration);
303             break;
304         case MGUIDE2_RIGHT:
305             ManualMove(pSecondaryMount, RIGHT, duration);
306             break;
307         case MGUIDE2_LEFT:
308             ManualMove(pSecondaryMount, LEFT, duration);
309             break;
310     }
311 }
312 
CreateManualGuideWindow()313 wxWindow *TestGuide::CreateManualGuideWindow()
314 {
315     return new TestGuideDialog();
316 }
317 
ManualGuideUpdateControls()318 void TestGuide::ManualGuideUpdateControls()
319 {
320     // notify the manual guide dialog to update its controls
321     if (pFrame->pManualGuide)
322     {
323         wxCommandEvent event(APPSTATE_NOTIFY_EVENT, pFrame->GetId());
324         event.SetEventObject(pFrame);
325         wxPostEvent(pFrame->pManualGuide, event);
326     }
327 }
328