1 /*
2 * rotator_ascom.cpp
3 * PHD Guiding
4 *
5 * Created by Andy Galasso
6 * Copyright (c) 2015 Andy Galasso
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 #ifdef ROTATOR_ASCOM
38
39 #include <wx/msw/ole/oleutils.h>
40
41 struct AscomRotatorImpl
42 {
43 GITEntry m_gitEntry;
44 wxString m_choice;
45 wxString m_name;
46
47 bool Create(DispatchObj *obj, DispatchClass *cls);
48 };
49
RotatorAscom(const wxString & choice)50 RotatorAscom::RotatorAscom(const wxString& choice)
51 : m_impl(new AscomRotatorImpl())
52 {
53 m_impl->m_choice = m_impl->m_name = choice;
54 }
55
~RotatorAscom(void)56 RotatorAscom::~RotatorAscom(void)
57 {
58 delete m_impl;
59 }
60
displayName(const wxString & ascomName)61 static wxString displayName(const wxString& ascomName)
62 {
63 if (ascomName.Find(_T("ASCOM")) != wxNOT_FOUND)
64 return ascomName;
65 return ascomName + _T(" (ASCOM)");
66 }
67
68 // map descriptive name to progid
69 static std::map<wxString, wxString> s_progid;
70
EnumAscomRotators(void)71 wxArrayString RotatorAscom::EnumAscomRotators(void)
72 {
73 wxArrayString list;
74
75 try
76 {
77 DispatchObj profile;
78 if (!profile.Create(L"ASCOM.Utilities.Profile"))
79 throw ERROR_INFO("ASCOM Rotator: could not instantiate ASCOM profile class ASCOM.Utilities.Profile. Is ASCOM installed?");
80
81 Variant res;
82 if (!profile.InvokeMethod(&res, L"RegisteredDevices", L"Rotator"))
83 throw ERROR_INFO("ASCOM Rotator: could not query registered rotator devices: " + ExcepMsg(profile.Excep()));
84
85 DispatchClass ilist_class;
86 DispatchObj ilist(res.pdispVal, &ilist_class);
87
88 Variant vcnt;
89 if (!ilist.GetProp(&vcnt, L"Count"))
90 throw ERROR_INFO("ASCOM Rotator: could not query registered rotators: " + ExcepMsg(ilist.Excep()));
91
92 unsigned int const count = vcnt.intVal;
93 DispatchClass kvpair_class;
94
95 for (unsigned int i = 0; i < count; i++)
96 {
97 Variant kvpres;
98 if (ilist.GetProp(&kvpres, L"Item", i))
99 {
100 DispatchObj kvpair(kvpres.pdispVal, &kvpair_class);
101 Variant vkey, vval;
102 if (kvpair.GetProp(&vkey, L"Key") && kvpair.GetProp(&vval, L"Value"))
103 {
104 wxString ascomName = vval.bstrVal;
105 wxString displName = displayName(ascomName);
106 wxString progid = vkey.bstrVal;
107 s_progid[displName] = progid;
108 list.Add(displName);
109 }
110 }
111 }
112 }
113 catch (const wxString& msg)
114 {
115 POSSIBLY_UNUSED(msg);
116 }
117
118 return list;
119 }
120
Create(DispatchObj * obj,DispatchClass * cls)121 bool AscomRotatorImpl::Create(DispatchObj *obj, DispatchClass *cls)
122 {
123 IDispatch *idisp = m_gitEntry.Get();
124 if (idisp)
125 {
126 obj->Attach(idisp, cls);
127 return true;
128 }
129
130 Debug.Write(wxString::Format("Create ASCOM Rotator: choice '%s' progid %s\n", m_choice, s_progid[m_choice]));
131
132 wxBasicString progid(s_progid[m_choice]);
133
134 if (!obj->Create(progid))
135 {
136 Debug.AddLine("ASCOM Rotator: Could not get CLSID for rotator " + m_choice);
137 return false;
138 }
139
140 m_gitEntry.Register(*obj);
141 return true;
142 }
143
Connect(void)144 bool RotatorAscom::Connect(void)
145 {
146 DispatchClass driver_class;
147 DispatchObj driver(&driver_class);
148
149 // create the COM object
150 if (!m_impl->Create(&driver, &driver_class))
151 {
152 pFrame->Alert(_("Could not create ASCOM rotator object. See the debug log for more information."));
153 return true;
154 }
155
156 struct ConnectInBg : public ConnectRotatorInBg
157 {
158 AscomRotatorImpl *rotator;
159 ConnectInBg(AscomRotatorImpl *rotator_) : rotator(rotator_) { }
160 bool Entry()
161 {
162 GITObjRef dobj(rotator->m_gitEntry);
163 // ... set the Connected property to true....
164 if (!dobj.PutProp(L"Connected", true))
165 {
166 SetErrorMsg(ExcepMsg(dobj.Excep()));
167 return true;
168 }
169 return false;
170 }
171 };
172 ConnectInBg bg(m_impl);
173
174 if (bg.Run())
175 {
176 pFrame->Alert(_("ASCOM driver problem: Connect") + ":\n" + bg.GetErrorMsg());
177 return true;
178 }
179
180 Variant vname;
181 if (driver.GetProp(&vname, L"Name"))
182 {
183 m_impl->m_name = vname.bstrVal;
184 Debug.AddLine(wxString::Format("rotator name = %s", m_impl->m_name));
185 }
186
187 Rotator::Connect();
188
189 return false;
190 }
191
Disconnect(void)192 bool RotatorAscom::Disconnect(void)
193 {
194 if (!IsConnected())
195 {
196 Debug.AddLine("ASCOM rotator: attempt to disconnect when not connected");
197 return false;
198 }
199
200 GITObjRef rot(m_impl->m_gitEntry);
201
202 if (!rot.PutProp(L"Connected", false))
203 {
204 Debug.AddLine(ExcepMsg("ASCOM disconnect", rot.Excep()));
205 }
206
207 Rotator::Disconnect();
208 return false;
209 }
210
ShowPropertyDialog(void)211 void RotatorAscom::ShowPropertyDialog(void)
212 {
213 DispatchObj rot;
214
215 if (m_impl->Create(&rot, NULL))
216 {
217 Variant res;
218 if (!rot.InvokeMethod(&res, L"SetupDialog"))
219 {
220 pFrame->Alert(ExcepMsg(rot.Excep()));
221 }
222 }
223 }
224
Name(void) const225 wxString RotatorAscom::Name(void) const
226 {
227 return m_impl->m_name;
228 }
229
Position(void) const230 float RotatorAscom::Position(void) const
231 {
232 GITObjRef rot(m_impl->m_gitEntry);
233
234 Variant vRes;
235 if (!rot.GetProp(&vRes, L"Position"))
236 {
237 pFrame->Alert(ExcepMsg(_("ASCOM driver problem -- cannot get rotator position"), rot.Excep()));
238 return 0.f;
239 }
240
241 return vRes.fltVal;
242 }
243
244 #endif // ROTATOR_ASCOM
245