Instrument Neutral Distributed Interface INDI 2.2.5
hitecastrodcfocuser.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2016 Andy Kirkham. All rights reserved.
3
4 HitecAstroDCFocuser Focuser
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9 .
10 This library 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 GNU
13 Library General Public License for more details.
14 .
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*******************************************************************************/
20
21#include "hitecastrodcfocuser.h"
22
23#include <cstring>
24#include <memory>
25
26#define HID_TIMEOUT 10000 /* 10s */
27#define FUDGE_FACTOR_H 1000
28#define FUDGE_FACTOR_L 885
29
30#define FOCUS_SETTINGS_TAB "Settings"
31
32static std::unique_ptr<HitecAstroDCFocuser> hitecastroDcFocuser(new HitecAstroDCFocuser());
33
40
42{
43 if (m_HIDHandle != nullptr)
44 {
45 hid_close(m_HIDHandle);
46 m_HIDHandle = nullptr;
47 }
48}
49
51{
52 if (hid_init() != 0)
53 {
54 LOG_ERROR("hid_init() failed.");
55 }
56
57 m_HIDHandle = hid_open(0x04D8, 0xFAC2, nullptr);
58
59 if (m_HIDHandle == nullptr)
60 m_HIDHandle = hid_open(0x04D8, 0xF53A, nullptr);
61
62 LOG_DEBUG(m_HIDHandle ? "HitecAstroDCFocuser opened." : "HitecAstroDCFocuser failed.");
63
64 if (m_HIDHandle != nullptr)
65 {
66 LOG_INFO("Experimental driver. Report issues to https://github.com/A-j-K/hitecastrodcfocuser/issues");
68 return true;
69 }
70
71 LOGF_ERROR("Failed to connect to focuser: %s", hid_error(m_HIDHandle));
72 return false;
73}
74
76{
77 if (m_HIDHandle != nullptr)
78 {
79 hid_close(m_HIDHandle);
80 m_HIDHandle = nullptr;
81 }
82
83 LOG_DEBUG("focuser is offline.");
84 return true;
85}
86
88{
89 return "HitecAstro DC";
90}
91
93{
95
96 //IDMessage(getDeviceName(), "HitecAstroDCFocuser::initProperties()");
97
99 //addSimulationControl();
100
101 // IUFillNumber(&MaxPositionN[0], "Steps", "", "%.f", 0, 500000, 0., 10000);
102 // IUFillNumberVector(&MaxPositionNP, MaxPositionN, 1, getDeviceName(), "MAX_POSITION", "Max position",
103 // FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
104
105 SlewSpeedNP[0].fill("Steps/sec", "", "%.f", 1, 100, 0., 50);
106 SlewSpeedNP.fill(getDeviceName(), "SLEW_SPEED", "Slew speed", MAIN_CONTROL_TAB,
107 IP_RW, 0, IPS_IDLE);
108
109 // IUFillSwitch(&ReverseDirectionS[0], "ENABLED", "Reverse direction", ISS_OFF);
110 // IUFillSwitchVector(&ReverseDirectionSP, ReverseDirectionS, 1, getDeviceName(), "REVERSE_DIRECTION",
111 // "Reverse direction", OPTIONS_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE);
112
113 FocusSpeedNP[0].setValue(100.);
114 FocusSpeedNP[0].setMin(1.);
115 FocusSpeedNP[0].setMax(100.);
116 FocusSpeedNP[0].setValue(100.);
117
118 FocusRelPosNP[0].setMin(1);
119 FocusRelPosNP[0].setMax(50000);
120 FocusRelPosNP[0].setStep(1000);
121 FocusRelPosNP[0].setValue(1000);
122
124
125 return true;
126}
127
129{
131
132 if (isConnected())
133 {
134 //defineProperty(&MaxPositionNP);
135 defineProperty(SlewSpeedNP);
136 //defineProperty(&ReverseDirectionSP);
137 }
138 else
139 {
140 //deleteProperty(MaxPositionNP.name);
141 deleteProperty(SlewSpeedNP);
142 //deleteProperty(ReverseDirectionSP.name);
143 }
144
145 return true;
146}
147
149{
150 if (m_State == SLEWING && m_Duration > 0)
151 {
152 --m_Duration;
153 if (m_Duration == 0)
154 {
155 int rc;
156 unsigned char command[8] = {0};
157 m_State = IDLE;
158 memset(command, 0, 8);
159 command[0] = m_StopChar;
160 rc = hid_write(m_HIDHandle, command, 8);
161 if (rc < 0)
162 {
163 LOGF_DEBUG("::MoveFocuser() fail (%s)", hid_error(m_HIDHandle));
164 }
165 hid_read_timeout(m_HIDHandle, command, 8, 1000);
166 }
167 }
168 SetTimer(1);
169}
170
171bool HitecAstroDCFocuser::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
172{
173 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
174 {
175 // if (strcmp(name, MaxPositionNP.name) == 0)
176 // {
177 // IUUpdateNumber(&MaxPositionNP, values, names, n);
178 // MaxPositionNP.s = IPS_OK;
179 // IDSetNumber(&MaxPositionNP, nullptr);
180 // return true;
181 // }
182 if (SlewSpeedNP.isNameMatch(name))
183 {
184 if (values[0] > 100)
185 {
186 SlewSpeedNP.setState(IPS_ALERT);
187 return false;
188 }
189 SlewSpeedNP.update(values, names, n);
190 SlewSpeedNP.setState(IPS_OK);
191 SlewSpeedNP.apply();
192 return true;
193 }
194 }
195 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
196}
197
199{
200 int rc, speed = (int)SlewSpeedNP[0].getValue();
201 // int32_t iticks = ticks;
202 unsigned char command[8] = {0};
203 IPState rval;
204
205 LOGF_DEBUG("::move() begin %d ticks at speed %d", ticks, speed);
206
207 if (m_HIDHandle == nullptr)
208 {
209 LOG_DEBUG("::move() bad handle");
210 return IPS_ALERT;
211 }
212
213 // FocusRelPosNP.setState(IPS_BUSY);
214 // FocusRelPosNP.apply();
215
216 // JM 2017-03-16: iticks is not used, FIXME.
217 // if (dir == FOCUS_INWARD)
218 // {
219 // iticks = ticks * -1;
220 // }
221
222 //if (ReverseDirectionS[0].s == ISS_ON)
223 if (FocusReverseSP[INDI_ENABLED].getState() == ISS_ON)
224 {
225 dir = dir == FOCUS_INWARD ? FOCUS_OUTWARD : FOCUS_INWARD;
226 }
227
228 if (speed > 100)
229 {
230 LOGF_DEBUG("::move() over speed %d, limiting to 100", ticks, speed);
231 speed = 100;
232 }
233
234 ticks *= FUDGE_FACTOR_H;
235 ticks /= FUDGE_FACTOR_L;
236
237 memset(command, 0, 8);
238 command[0] = dir == FOCUS_INWARD ? 0x50 : 0x52;
239 command[1] = (unsigned char)((ticks >> 8) & 0xFF);
240 command[2] = (unsigned char)(ticks & 0xFF);
241 command[3] = 0x03;
242 command[4] = (unsigned char)(speed & 0xFF);
243 command[5] = 0;
244 command[6] = 0;
245 command[7] = 0;
246
247 LOGF_DEBUG("==> TX %2.2x %2.2x%2.2x %2.2x %2.2x %2.2x%2.2x%2.2x", command[0], command[1],
248 command[2], command[3], command[4], command[5], command[6], command[7]);
249
250 rc = hid_write(m_HIDHandle, command, 8);
251 if (rc < 0)
252 {
253 LOGF_DEBUG("::MoveRelFocuser() fail (%s)", hid_error(m_HIDHandle));
254 return IPS_ALERT;
255 }
256
257 //FocusRelPosNP.setState(IPS_BUSY);
258
259 memset(command, 0, 8);
260 hid_read_timeout(m_HIDHandle, command, 8, HID_TIMEOUT);
261 LOGF_DEBUG("==> RX %2.2x %2.2x%2.2x %2.2x %2.2x %2.2x%2.2x%2.2x", command[0], command[1],
262 command[2], command[3], command[4], command[5], command[6], command[7]);
263
264 rval = command[1] == 0x21 ? IPS_OK : IPS_ALERT;
265
266 //FocusRelPosNP.setState(rval);
267 //FocusRelPosNP.apply();
268
269 return rval;
270}
271
273{
274 int rc;
275 unsigned char command[8] = {0};
276 IPState rval;
277
278 LOGF_DEBUG("::MoveFocuser(%d %d %d)", dir, speed, duration);
279
280 if (m_HIDHandle == nullptr)
281 {
282 return IPS_ALERT;
283 }
284
287
288 if (FocusReverseSP[INDI_ENABLED].getState() == ISS_ON)
289 {
290 dir = (dir == FOCUS_INWARD) ? FOCUS_OUTWARD : FOCUS_INWARD;
291 }
292
293 if (speed > 100)
294 {
295 LOGF_DEBUG("::MoveFocuser() over speed %d, limiting to 100", speed);
296 speed = 100;
297 }
298
299 m_StopChar = dir == FOCUS_INWARD ? 0xB0 : 0xBA;
300
301 memset(command, 0, 8);
302 command[0] = dir == FOCUS_INWARD ? 0x54 : 0x56;
303 command[1] = (unsigned char)((speed >> 8) & 0xFF);
304 command[2] = (unsigned char)(speed & 0xFF);
305 command[3] = 0x03;
306 command[4] = 0;
307 command[5] = 0;
308 command[6] = 0;
309 command[7] = 0;
310
311 LOGF_DEBUG("==> TX %2.2x %2.2x%2.2x %2.2x %2.2x %2.2x%2.2x%2.2x", command[0], command[1],
312 command[2], command[3], command[4], command[5], command[6], command[7]);
313
314 rc = hid_write(m_HIDHandle, command, 8);
315 if (rc < 0)
316 {
317 LOGF_DEBUG("::MoveFocuser() fail (%s)", hid_error(m_HIDHandle));
318 return IPS_ALERT;
319 }
320
321 memset(command, 0, 8);
322 hid_read_timeout(m_HIDHandle, command, 8, HID_TIMEOUT);
323 LOGF_DEBUG("==> RX %2.2x %2.2x%2.2x %2.2x %2.2x %2.2x%2.2x%2.2x", command[0], command[1],
324 command[2], command[3], command[4], command[5], command[6], command[7]);
325
326 rval = command[1] == 0x24 ? IPS_OK : IPS_ALERT;
327
330
331 m_Duration = duration;
332 m_State = SLEWING;
333
334 return IPS_BUSY;
335}
336
338{
340
341 //IUSaveConfigNumber(fp, &MaxPositionNP);
342 SlewSpeedNP.save(fp);
343 //IUSaveConfigSwitch(fp, &ReverseDirectionSP);
344
345 return true;
346}
virtual ~HitecAstroDCFocuser() override
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
bool Disconnect() override
Disconnect from device.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
const char * getDefaultName() override
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool saveConfigItems(FILE *fp) override
bool isConnected() const
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSpeedNP
virtual bool saveConfigItems(FILE *fp) override
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
void setSupportedConnections(const uint8_t &value)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
libusb_device * dev
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
Open a HID device using a Vendor ID (VID), Product ID (PID) and optionally a serial number.
Definition hid_libusb.c:612
int HID_API_EXPORT hid_init(void)
Initialize the HIDAPI library.
Definition hid_libusb.c:388
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
Definition hid_libusb.c:997
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
Write an Output report to a HID device.
Definition hid_libusb.c:929
void HID_API_EXPORT hid_close(hid_device *dev)
Close a HID device.
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
#define FUDGE_FACTOR_L
#define FUDGE_FACTOR_H
#define HID_TIMEOUT
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName