Skip to content

Commit 8bb2527

Browse files
committed
Create Alpaca client as copy of ASCOM client.
- removed all COM stuff - disabled any functionality - just compiles without function. - start point of developing further from Alpaca specs
1 parent 6a6bd14 commit 8bb2527

12 files changed

+1132
-0
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/*
2+
* Copyright (C) 2019 Gion Kunz <gion.kunz@gmail.com> (ASCOM)
3+
* Copyright (C) 2025 Georg Zotti (Alpaca port)
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18+
*/
19+
20+
#include <QDebug>
21+
22+
#include "AlpacaDevice.hpp"
23+
//#include <comdef.h>
24+
25+
AlpacaDevice::AlpacaDevice(QObject* parent, QString AlpacaDeviceId) : QObject(parent),
26+
alpacaDeviceNumber(AlpacaDeviceId.toLong())
27+
{}
28+
29+
bool AlpacaDevice::connect()
30+
{
31+
/*
32+
if (mConnected) return true;
33+
34+
BOOL initResult = OleInit(COINIT_APARTMENTTHREADED);
35+
HRESULT hResult = OleCreateInstance(reinterpret_cast<const wchar_t*>(mAlpacaDeviceId.toStdWString().c_str()), &pTelescopeDispatch);
36+
37+
if (!initResult || FAILED(hResult))
38+
{
39+
qWarning() << "Initialization failed for device: " << mAlpacaDeviceId;
40+
return false;
41+
}
42+
43+
VARIANT v1 = OleBoolToVariant(TRUE);
44+
45+
hResult = OlePropertyPut(pTelescopeDispatch, nullptr, const_cast<wchar_t*>(LConnected), 1, v1);
46+
47+
if (FAILED(hResult))
48+
{
49+
qWarning() << "Could not connect to device: " << mAlpacaDeviceId;
50+
return false;
51+
}
52+
53+
mConnected = true;
54+
return true;
55+
*/
56+
// TODO: PUT call?
57+
qWarning() << "AlpacaDevice::connect() not yet implemented";
58+
return true;
59+
}
60+
61+
bool AlpacaDevice::disconnect()
62+
{
63+
/*
64+
if (!mConnected) return true;
65+
66+
VARIANT v1 = OleBoolToVariant(FALSE);
67+
HRESULT hResult = OlePropertyPut(pTelescopeDispatch, nullptr, const_cast<wchar_t*>(LConnected), 1, v1);
68+
69+
if (FAILED(hResult))
70+
{
71+
qWarning() << "Could not disconnect device: " << mAlpacaDeviceId;
72+
return false;
73+
}
74+
75+
pTelescopeDispatch->Release();
76+
77+
mConnected = false;
78+
return true;
79+
*/
80+
// TODO: PUT call?
81+
qWarning() << "AlpacaDevice::disconnect() not yet implemented";
82+
return true;
83+
}
84+
85+
AlpacaDevice::AlpacaCoordinates AlpacaDevice::position() const
86+
{
87+
return mCoordinates;
88+
}
89+
90+
91+
void AlpacaDevice::slewToCoordinates(AlpacaDevice::AlpacaCoordinates coords)
92+
{
93+
/*
94+
if (!mConnected) return;
95+
96+
VARIANT v1 = OleDoubleToVariant(coords.RA);
97+
VARIANT v2 = OleDoubleToVariant(coords.DEC);
98+
99+
HRESULT hResult = OleMethodCall(pTelescopeDispatch, nullptr, const_cast<wchar_t*>(LSlewToCoordinatesAsync), 2, v1, v2);
100+
if (FAILED(hResult))
101+
{
102+
qDebug() << "Slew failed for device: " << mAlpacaDeviceId;
103+
}
104+
*/
105+
// TODO: PUT call
106+
qWarning() << "AlpacaDevice: slewToCoordinates() not yet implemented";
107+
}
108+
109+
void AlpacaDevice::syncToCoordinates(AlpacaCoordinates coords)
110+
{
111+
/*
112+
if (!mConnected) return;
113+
114+
VARIANT v1 = OleDoubleToVariant(coords.RA);
115+
VARIANT v2 = OleDoubleToVariant(coords.DEC);
116+
117+
HRESULT hResult = OleMethodCall(pTelescopeDispatch, nullptr, const_cast<wchar_t*>(LSyncToCoordinates), 2, v1, v2);
118+
if (FAILED(hResult))
119+
{
120+
qDebug() << "Could not sync to coordinates for device: " << mAlpacaDeviceId;
121+
}
122+
*/
123+
// TODO: PUT call
124+
qWarning() << "AlpacaDevice: syncToCoordinates() not yet implemented";
125+
}
126+
127+
void AlpacaDevice::abortSlew()
128+
{
129+
/*
130+
if (!mConnected) return;
131+
132+
HRESULT hResult = OleMethodCall(pTelescopeDispatch, nullptr, const_cast<wchar_t*>(LAbortSlew));
133+
if (FAILED(hResult))
134+
{
135+
qCritical() << "Could not abort slew for device: " << mAlpacaDeviceId;
136+
}
137+
*/
138+
// TODO: PUT call
139+
qWarning() << "AlpacaDevice: abortSlew() not yet implemented";
140+
}
141+
142+
bool AlpacaDevice::isDeviceConnected() const
143+
{
144+
/*
145+
if (!mConnected) return false;
146+
147+
VARIANT v1;
148+
HRESULT hResult = OlePropertyGet(pTelescopeDispatch, &v1, const_cast<wchar_t*>(LConnected));
149+
150+
if (FAILED(hResult))
151+
{
152+
qDebug() << "Could not get connected state for device: " << mAlpacaDeviceId;
153+
return false;
154+
}
155+
156+
return v1.boolVal == -1;
157+
*/
158+
// TODO: If it makes sense at all, GET call
159+
return true;
160+
}
161+
162+
bool AlpacaDevice::isParked() const
163+
{
164+
/*
165+
if (!mConnected) return true;
166+
167+
VARIANT v1;
168+
HRESULT hResult = OlePropertyGet(pTelescopeDispatch, &v1, const_cast<wchar_t*>(LAtPark));
169+
170+
if (FAILED(hResult))
171+
{
172+
qDebug() << "Could not get AtPark state for device: " << mAlpacaDeviceId;
173+
return false;
174+
}
175+
176+
return v1.boolVal == -1;
177+
*/
178+
// TODO: GET call
179+
return false;
180+
}
181+
182+
183+
AlpacaDevice::AlpacaEquatorialCoordinateType AlpacaDevice::getEquatorialCoordinateType()
184+
{
185+
/*
186+
if (!mConnected) return AlpacaDevice::AlpacaEquatorialCoordinateType::Other;
187+
188+
VARIANT v1;
189+
HRESULT hResult = OlePropertyGet(pTelescopeDispatch, &v1, const_cast<wchar_t*>(LEquatorialSystem));
190+
191+
if (FAILED(hResult))
192+
{
193+
qDebug() << "Could not get EquatorialCoordinateType for device: " << mAlpacaDeviceId;
194+
return AlpacaDevice::AlpacaEquatorialCoordinateType::Other;
195+
}
196+
197+
return static_cast<AlpacaDevice::AlpacaEquatorialCoordinateType>(v1.intVal);
198+
*/
199+
// TODO: GET call
200+
return AlpacaDevice::AlpacaEquatorialCoordinateType::Other;
201+
}
202+
203+
bool AlpacaDevice::doesRefraction()
204+
{
205+
/*
206+
if (!mConnected) return false;
207+
208+
VARIANT v1;
209+
HRESULT hResult = OlePropertyGet(pTelescopeDispatch, &v1, const_cast<wchar_t*>(LDoesRefraction));
210+
211+
if (FAILED(hResult))
212+
{
213+
qDebug() << "Could not get DoesRefraction for device: " << mAlpacaDeviceId;
214+
return false;
215+
}
216+
217+
return v1.boolVal == -1;
218+
*/
219+
// TODO: GET call
220+
return false;
221+
}
222+
223+
224+
AlpacaDevice::AlpacaCoordinates AlpacaDevice::getCoordinates()
225+
{
226+
AlpacaDevice::AlpacaCoordinates coords = {0.,0.};
227+
228+
/*
229+
if (!mConnected) return coords;
230+
231+
VARIANT v1, v2;
232+
HRESULT hResult;
233+
234+
hResult = OlePropertyGet(pTelescopeDispatch, &v1, const_cast<wchar_t*>(LRightAscension));
235+
if (FAILED(hResult)) qDebug() << "Could not get RightAscension for device: " << mAlpacaDeviceId;
236+
237+
hResult = OlePropertyGet(pTelescopeDispatch, &v2, const_cast<wchar_t*>(LDeclination));
238+
if (FAILED(hResult)) qDebug() << "Could not get Declination for device: " << mAlpacaDeviceId;
239+
240+
coords.RA = v1.dblVal;
241+
coords.DEC = v2.dblVal;
242+
*/
243+
244+
// TODO: Use some GET call
245+
return coords;
246+
}
247+
248+
QString AlpacaDevice::showDeviceChooser(QString previousDeviceId)
249+
{
250+
/*
251+
VARIANT v1, v2;
252+
HRESULT hResult;
253+
IDispatch* chooserDispatch;
254+
BOOL initResult = OleInit(COINIT_APARTMENTTHREADED);
255+
256+
if (!initResult) return previousDeviceId;
257+
hResult = OleCreateInstance(L"Alpaca.Utilities.Chooser", &chooserDispatch);
258+
259+
if (FAILED(hResult)) return previousDeviceId;
260+
261+
v1 = OleStringToVariant(const_cast<wchar_t*>(previousDeviceId.toStdWString().c_str()));
262+
263+
hResult = OleMethodCall(chooserDispatch, &v2, const_cast<wchar_t*>(LChoose), 1, v1);
264+
265+
if (FAILED(hResult)) return previousDeviceId;
266+
267+
QString selectedDevice = QString::fromStdWString(v2.bstrVal);
268+
269+
if (selectedDevice == "") return previousDeviceId;
270+
271+
return QString::fromStdWString(v2.bstrVal);
272+
*/
273+
return "NOT IMPLEMENTED YET";
274+
}
275+
276+
QString AlpacaDevice::getDeviceURL(QString &command)
277+
{
278+
return QString("http://%1:%2/api/v%3/%4/%5/%6").arg(alpacaHost, QString::number(alpacaPort), ProtocolVersion, DeviceType, QString::number(alpacaDeviceNumber), command);
279+
}
280+
281+
void AlpacaDevice::alpacaGET()
282+
{
283+
QString clientArgs=QString("clientid=%2&clienttransactionid=%2").arg(QString::number(clientId), QString::number(clientTransactionId));
284+
285+
}
286+
287+
const QString AlpacaDevice::LSlewToCoordinatesAsync = QStringLiteral("SlewToCoordinatesAsync");
288+
const QString AlpacaDevice::LSyncToCoordinates = QStringLiteral("SyncToCoordinates");
289+
const QString AlpacaDevice::LAbortSlew = QStringLiteral("AbortSlew");
290+
const QString AlpacaDevice::LConnected = QStringLiteral("Connected");
291+
const QString AlpacaDevice::LAtPark = QStringLiteral("AtPark");
292+
const QString AlpacaDevice::LEquatorialSystem = QStringLiteral("EquatorialSystem");
293+
const QString AlpacaDevice::LDoesRefraction = QStringLiteral("DoesRefraction");
294+
const QString AlpacaDevice::LRightAscension = QStringLiteral("RightAscension");
295+
const QString AlpacaDevice::LDeclination = QStringLiteral("Declination");
296+
const QString AlpacaDevice::LChoose = QStringLiteral("Choose");
297+
298+
const QString AlpacaDevice::ProtocolVersion = QStringLiteral("1");
299+
const QString AlpacaDevice::DeviceType = QStringLiteral("telescope");
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (C) 2019 Gion Kunz <gion.kunz@gmail.com> (ASCOM)
3+
* Copyright (C) 2025 Georg Zotti (Alpaca port)
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18+
*/
19+
20+
#ifndef ALPACA_DEVICE_HPP
21+
#define ALPACA_DEVICE_HPP
22+
23+
#include <QObject>
24+
#include <QStringList>
25+
26+
27+
//! Implementation of an AlpacaDevice that actually only can be an Alpaca telescope
28+
//! TODO Maybe rename to AlpacaTelescopeDevice?
29+
class AlpacaDevice final : public QObject
30+
{
31+
Q_OBJECT
32+
33+
public:
34+
struct AlpacaCoordinates
35+
{
36+
double RA = 0.0;
37+
double DEC = 0.0;
38+
};
39+
40+
enum AlpacaEquatorialCoordinateType
41+
{
42+
Other, Topocentric, J2000, J2050, B1950
43+
};
44+
45+
static QString showDeviceChooser(QString previousDeviceId = "");
46+
47+
AlpacaDevice(QObject* parent = nullptr, QString AlpacaDeviceId = nullptr);
48+
49+
bool isDeviceConnected() const; // Maybe not useful in Alpaca. isDeviceConfigured() or Active() may be useful.
50+
bool isParked() const;
51+
bool connect();
52+
bool disconnect();
53+
AlpacaCoordinates position() const;
54+
void slewToCoordinates(AlpacaCoordinates coords);
55+
void syncToCoordinates(AlpacaCoordinates coords);
56+
void abortSlew();
57+
AlpacaEquatorialCoordinateType getEquatorialCoordinateType();
58+
bool doesRefraction();
59+
AlpacaCoordinates getCoordinates();
60+
61+
signals:
62+
void deviceConnected();
63+
void deviceDisconnected();
64+
65+
private:
66+
//IDispatch* pTelescopeDispatch; // from OLE
67+
//bool mConnected = false; // No longer meaningful. RESTful, no state...
68+
QString alpacaHost; //! "mytelescope.net" or "127.0.0.1"
69+
int alpacaPort; //! port used for communication. Is returned via discovery protocol. 0 means invalid.
70+
uint32_t alpacaDeviceNumber; //! Only the telescope number. Get during discovery
71+
72+
uint32_t clientId; //! User configurable before first connection. Send as clientid in each command.
73+
uint32_t clientTransactionId; //! operation counter. send as clienttransactionid, raise per command given.
74+
75+
AlpacaCoordinates mCoordinates; //! TODO: No longer relevant, as coordinates are read on the fly, right?
76+
77+
//! Return the URL path part for this telescope, like /api/v1/telescope/0
78+
QString getDeviceURL(QString &command);
79+
80+
void alpacaGET();
81+
void alpacaPUT();
82+
83+
static const QString LSlewToCoordinatesAsync;
84+
static const QString LSyncToCoordinates;
85+
static const QString LAbortSlew;
86+
static const QString LConnected;
87+
static const QString LAtPark;
88+
static const QString LEquatorialSystem;
89+
static const QString LDoesRefraction;
90+
static const QString LRightAscension;
91+
static const QString LDeclination;
92+
static const QString LChoose;
93+
94+
static const QString ProtocolVersion;
95+
static const QString DeviceType;
96+
97+
};
98+
99+
#endif // ALPACA_DEVICE_HPP

0 commit comments

Comments
 (0)