Instrument Neutral Distributed Interface INDI  2.0.2
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 
32 static std::unique_ptr<HitecAstroDCFocuser> hitecastroDcFocuser(new HitecAstroDCFocuser());
33 
35 {
38  setVersion(0, 2);
39 }
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  IUFillNumber(&SlewSpeedN[0], "Steps/sec", "", "%.f", 1, 100, 0., 50);
106  IUFillNumberVector(&SlewSpeedNP, SlewSpeedN, 1, 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  FocusSpeedN[0].value = 100.;
114  FocusSpeedN[0].min = 1.;
115  FocusSpeedN[0].max = 100.;
116  FocusSpeedN[0].value = 100.;
117 
118  FocusRelPosN[0].min = 1;
119  FocusRelPosN[0].max = 50000;
120  FocusRelPosN[0].step = 1000;
121  FocusRelPosN[0].value = 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.name);
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 
171 bool 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 (strcmp(name, SlewSpeedNP.name) == 0)
183  {
184  if (values[0] > 100)
185  {
186  SlewSpeedNP.s = IPS_ALERT;
187  return false;
188  }
189  IUUpdateNumber(&SlewSpeedNP, values, names, n);
190  SlewSpeedNP.s = IPS_OK;
191  IDSetNumber(&SlewSpeedNP, nullptr);
192  return true;
193  }
194  }
195  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
196 }
197 
199 {
200  int rc, speed = (int)SlewSpeedN[0].value;
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.s = IPS_BUSY;
214  // IDSetNumber(&FocusRelPosNP, nullptr);
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)
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.s = 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.s = rval;
267  //IDSetNumber(&FocusRelPosNP, nullptr);
268 
269  return rval;
270 }
271 
272 IPState HitecAstroDCFocuser::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
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 
286  IDSetNumber(&FocusSpeedNP, nullptr);
287 
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 
328  FocusSpeedNP.s = rval;
329  IDSetNumber(&FocusSpeedNP, nullptr);
330 
331  m_Duration = duration;
332  m_State = SLEWING;
333 
334  return IPS_BUSY;
335 }
336 
338 {
340 
341  //IUSaveConfigNumber(fp, &MaxPositionNP);
342  IUSaveConfigNumber(fp, &SlewSpeedNP);
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
Process the client newNumber command.
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
Initilize properties initial state and value. The child class must implement this function.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
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
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
INumberVectorProperty FocusSpeedNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void setSupportedConnections(const uint8_t &value)
setConnection Set Focuser connection mode. Child class should call this in the constructor before Foc...
libusb_device * dev
Definition: indiusbdevice.h:40
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.
Definition: hid_libusb.c:1163
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
Definition: hid_libusb.c:1227
#define FUDGE_FACTOR_L
#define FUDGE_FACTOR_H
#define HID_TIMEOUT
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#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
char name[MAXINDINAME]
Definition: indiapi.h:323