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