Instrument Neutral Distributed Interface INDI  2.0.2
focusmaster.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3 
4  Televue FocusMaster Driver.
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 "focusmaster.h"
22 
23 #include <cmath>
24 #include <cstring>
25 #include <memory>
26 #include <unistd.h>
27 
28 #define POLLMS_OVERRIDE 1000 /* 1000 ms */
29 #define FOCUSMASTER_TIMEOUT 1000 /* 1000 ms */
30 #define MAX_FM_BUF 16
31 
32 #define FOCUS_SETTINGS_TAB "Settings"
33 
34 // We declare an auto pointer to FocusMaster.
35 std::unique_ptr<FocusMaster> focusMaster(new FocusMaster());
36 
38 {
40  setConnection(CONNECTION_NONE);
41 }
42 
44 {
45  handle = hid_open(0x134A, 0x9030, nullptr);
46 
47  if (handle == nullptr)
48  {
49  LOG_ERROR("No FocusMaster focuser found.");
50  return false;
51  }
52  else
53  {
54  // N.B. Check here if we have the digital readout gadget.
55 
56  // if digital readout
57  //FI::SetCapability(GetFocuserCapability() | FOCUSER_CAN_REL_MOVE | FOCUSER_CAN_ABS_MOVE);
58 
60 
61  }
62 
63  return (handle != nullptr);
64 }
65 
67 {
68  hid_close(handle);
69  hid_exit();
70  return true;
71 }
72 
74 {
75  return (const char *)"FocusMaster";
76 }
77 
79 {
81 
82  // Sync to a particular position
83  IUFillNumber(&SyncN[0], "Ticks", "", "%.f", 0, 100000, 100., 0.);
84  IUFillNumberVector(&SyncNP, SyncN, 1, getDeviceName(), "Sync", "", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE);
85 
86  // Full Forward/Reverse Motion
87  IUFillSwitch(&FullMotionS[FOCUS_INWARD], "FULL_INWARD", "Full Inward", ISS_OFF);
88  IUFillSwitch(&FullMotionS[FOCUS_OUTWARD], "FULL_OUTWARD", "Full Outward", ISS_OFF);
89  IUFillSwitchVector(&FullMotionSP, FullMotionS, 2, getDeviceName(), "FULL_MOTION", "Full Motion", MAIN_CONTROL_TAB, IP_RW,
90  ISR_ATMOST1, 0, IPS_IDLE);
91 
92  FocusAbsPosN[0].min = SyncN[0].min = 0;
93  FocusAbsPosN[0].max = SyncN[0].max;
94  FocusAbsPosN[0].step = SyncN[0].step;
95  FocusAbsPosN[0].value = 0;
96 
97  FocusRelPosN[0].max = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
98  FocusRelPosN[0].step = FocusRelPosN[0].max / 100.0;
99  FocusRelPosN[0].value = 100;
100 
102 
103  return true;
104 }
105 
107 {
109 
110  if (isConnected())
111  {
112  defineProperty(&FullMotionSP);
113  //defineProperty(&SyncNP);
114  }
115  else
116  {
117  deleteProperty(FullMotionSP.name);
118  //deleteProperty(SyncNP.name);
119  }
120 
121  return true;
122 }
123 
125 {
126  if (!isConnected())
127  return;
128 
129  //uint32_t currentTicks = 0;
130 
131  if (FocusTimerNP.s == IPS_BUSY)
132  {
133  float remaining = CalcTimeLeft(focusMoveStart, focusMoveRequest);
134 
135  if (remaining <= 0)
136  {
138  FocusTimerN[0].value = 0;
139  AbortFocuser();
140  }
141  else
142  FocusTimerN[0].value = remaining * 1000.0;
143 
144  IDSetNumber(&FocusTimerNP, nullptr);
145  }
146 
147 #if 0
148  bool rc = getPosition(&currentTicks);
149 
150  if (rc)
151  FocusAbsPosN[0].value = currentTicks;
152 
154  {
155  if (targetPosition == FocusAbsPosN[0].value)
156  {
157  if (FocusRelPosNP.s == IPS_BUSY)
158  {
160  IDSetNumber(&FocusRelPosNP, nullptr);
161  }
162 
164  LOG_DEBUG("Focuser reached target position.");
165  }
166  }
167 
168  IDSetNumber(&FocusAbsPosNP, nullptr);
169 #endif
170 
172 }
173 
174 bool FocusMaster::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
175 {
176  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
177  {
178  // Full Motion
179  if (!strcmp(FullMotionSP.name, name))
180  {
181  IUUpdateSwitch(&FullMotionSP, states, names, n);
182  FocusDirection targetDirection = static_cast<FocusDirection>(IUFindOnSwitchIndex(&FullMotionSP));
183 
184  FullMotionSP.s = MoveFocuser(targetDirection, 0, 0);
185  return true;
186  }
187  }
188 
189  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
190 
191 }
192 bool FocusMaster::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
193 {
194  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
195  {
196  // Sync
197  if (strcmp(SyncNP.name, name) == 0)
198  {
199  IUUpdateNumber(&SyncNP, values, names, n);
200  if (!sync(SyncN[0].value))
201  SyncNP.s = IPS_ALERT;
202  else
203  SyncNP.s = IPS_OK;
204 
205  IDSetNumber(&SyncNP, nullptr);
206  return true;
207  }
208  }
209 
210  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
211 }
212 
213 IPState FocusMaster::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
214 {
215  INDI_UNUSED(speed);
216 
217  uint8_t command[MAX_FM_BUF] = {0};
218 
219  if (dir == FOCUS_INWARD)
220  {
221  command[0] = 0x31;
222  command[1] = 0x21;
223  }
224  else
225  {
226  command[0] = 0x32;
227  command[1] = 0x22;
228  }
229 
230  sendCommand(command);
231 
232  gettimeofday(&focusMoveStart, nullptr);
233  focusMoveRequest = duration / 1000.0;
234 
235  if (duration > 0 && duration <= POLLMS_OVERRIDE)
236  {
237  usleep(duration * 1000);
238  AbortFocuser();
239  return IPS_OK;
240  }
241 
242  return IPS_BUSY;
243 }
244 
246 {
247  INDI_UNUSED(targetTicks);
248 
250 
251  return IPS_BUSY;
252 }
253 
255 {
256  uint32_t finalTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
257 
258  return MoveAbsFocuser(finalTicks);
259 }
260 
261 bool FocusMaster::sendCommand(const uint8_t *command, char *response)
262 {
263  INDI_UNUSED(response);
264 
265  int rc = hid_write(handle, command, 2);
266 
267  LOGF_DEBUG("CMD <%#02X %#02X>", command[0], command[1]);
268 
269  if (rc < 0)
270  {
271  LOGF_ERROR("<%#02X %#02X>: Error writing to device %s", command[0], command[1], hid_error(handle));
272  return false;
273  }
274 
275  return true;
276 }
277 
278 bool FocusMaster::setPosition(uint32_t ticks)
279 {
280  INDI_UNUSED(ticks);
281  return false;
282 }
283 
284 bool FocusMaster::getPosition(uint32_t *ticks)
285 {
286  INDI_UNUSED(ticks);
287  return false;
288 }
289 
291 {
292  uint8_t command[MAX_FM_BUF] = {0};
293 
294  command[0] = 0x30;
295  command[1] = 0x30;
296 
297  LOG_DEBUG("Aborting Focuser...");
298 
299  bool rc = sendCommand(command);
300 
301  if (rc)
302  {
303  if (FullMotionSP.s == IPS_BUSY)
304  {
305  IUResetSwitch(&FullMotionSP);
306  FullMotionSP.s = IPS_IDLE;
307  IDSetSwitch(&FullMotionSP, nullptr);
308  }
309 
310  if (FocusMotionSP.s == IPS_BUSY)
311  {
314  IDSetSwitch(&FocusMotionSP, nullptr);
315  }
316  }
317 
318  return rc;
319 }
320 
321 bool FocusMaster::sync(uint32_t ticks)
322 {
323  INDI_UNUSED(ticks);
324  return false;
325 }
326 
327 float FocusMaster::CalcTimeLeft(timeval start, float req)
328 {
329  double timesince;
330  double timeleft;
331  struct timeval now
332  {
333  0, 0
334  };
335  gettimeofday(&now, nullptr);
336 
337  timesince = (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec / 1000);
338  timesince = timesince / 1000;
339  timeleft = req - timesince;
340  return timeleft;
341 }
const char * getDefaultName()
Definition: focusmaster.cpp:73
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: focusmaster.cpp:78
bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: focusmaster.cpp:43
bool Disconnect()
Disconnect from device.
Definition: focusmaster.cpp:66
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks)
MoveFocuser the focuser to an relative position.
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void TimerHit()
Callback function to be called once SetTimer duration elapses.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool AbortFocuser()
AbortFocuser all focus motion.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveAbsFocuser(uint32_t targetTicks)
MoveFocuser the focuser to an absolute position.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void addSimulationControl()
Add Simulation control to the driver.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
ISwitchVectorProperty FocusMotionSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
INumberVectorProperty FocusTimerNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
std::unique_ptr< FocusMaster > focusMaster(new FocusMaster())
#define MAX_FM_BUF
Definition: focusmaster.cpp:30
#define POLLMS_OVERRIDE
Definition: focusmaster.cpp:28
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_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
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
Definition: hid_libusb.c:407
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ 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
@ ISR_ATMOST1
Definition: indiapi.h:174
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
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
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 IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
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 currentTicks
Definition: robofocus.cpp:42
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371