Instrument Neutral Distributed Interface INDI  1.9.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, ISR_ATMOST1, 0, IPS_IDLE);
90 
91  FocusAbsPosN[0].min = SyncN[0].min = 0;
92  FocusAbsPosN[0].max = SyncN[0].max;
93  FocusAbsPosN[0].step = SyncN[0].step;
94  FocusAbsPosN[0].value = 0;
95 
96  FocusRelPosN[0].max = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
97  FocusRelPosN[0].step = FocusRelPosN[0].max / 100.0;
98  FocusRelPosN[0].value = 100;
99 
101 
102  return true;
103 }
104 
106 {
108 
109  if (isConnected())
110  {
111  defineProperty(&FullMotionSP);
112  //defineProperty(&SyncNP);
113  }
114  else
115  {
116  deleteProperty(FullMotionSP.name);
117  //deleteProperty(SyncNP.name);
118  }
119 
120  return true;
121 }
122 
124 {
125  if (!isConnected())
126  return;
127 
128  //uint32_t currentTicks = 0;
129 
130  if (FocusTimerNP.s == IPS_BUSY)
131  {
132  float remaining = CalcTimeLeft(focusMoveStart, focusMoveRequest);
133 
134  if (remaining <= 0)
135  {
137  FocusTimerN[0].value = 0;
138  AbortFocuser();
139  }
140  else
141  FocusTimerN[0].value = remaining * 1000.0;
142 
143  IDSetNumber(&FocusTimerNP, nullptr);
144  }
145 
146 #if 0
147  bool rc = getPosition(&currentTicks);
148 
149  if (rc)
150  FocusAbsPosN[0].value = currentTicks;
151 
153  {
154  if (targetPosition == FocusAbsPosN[0].value)
155  {
156  if (FocusRelPosNP.s == IPS_BUSY)
157  {
159  IDSetNumber(&FocusRelPosNP, nullptr);
160  }
161 
163  LOG_DEBUG("Focuser reached target position.");
164  }
165  }
166 
167  IDSetNumber(&FocusAbsPosNP, nullptr);
168 #endif
169 
171 }
172 
173 bool FocusMaster::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
174 {
175  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
176  {
177  // Full Motion
178  if (!strcmp(FullMotionSP.name, name))
179  {
180  IUUpdateSwitch(&FullMotionSP, states, names, n);
181  FocusDirection targetDirection = static_cast<FocusDirection>(IUFindOnSwitchIndex(&FullMotionSP));
182 
183  FullMotionSP.s = MoveFocuser(targetDirection, 0, 0);
184  return true;
185  }
186  }
187 
188  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
189 
190 }
191 bool FocusMaster::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
192 {
193  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
194  {
195  // Sync
196  if (strcmp(SyncNP.name, name) == 0)
197  {
198  IUUpdateNumber(&SyncNP, values, names, n);
199  if (!sync(SyncN[0].value))
200  SyncNP.s = IPS_ALERT;
201  else
202  SyncNP.s = IPS_OK;
203 
204  IDSetNumber(&SyncNP, nullptr);
205  return true;
206  }
207  }
208 
209  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
210 }
211 
212 IPState FocusMaster::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
213 {
214  INDI_UNUSED(speed);
215 
216  uint8_t command[MAX_FM_BUF] = {0};
217 
218  if (dir == FOCUS_INWARD)
219  {
220  command[0] = 0x31;
221  command[1] = 0x21;
222  }
223  else
224  {
225  command[0] = 0x32;
226  command[1] = 0x22;
227  }
228 
229  sendCommand(command);
230 
231  gettimeofday(&focusMoveStart, nullptr);
232  focusMoveRequest = duration / 1000.0;
233 
234  if (duration > 0 && duration <= POLLMS_OVERRIDE)
235  {
236  usleep(duration * 1000);
237  AbortFocuser();
238  return IPS_OK;
239  }
240 
241  return IPS_BUSY;
242 }
243 
245 {
246  INDI_UNUSED(targetTicks);
247 
249 
250  return IPS_BUSY;
251 }
252 
254 {
255  uint32_t finalTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
256 
257  return MoveAbsFocuser(finalTicks);
258 }
259 
260 bool FocusMaster::sendCommand(const uint8_t *command, char *response)
261 {
262  INDI_UNUSED(response);
263 
264  int rc = hid_write(handle, command, 2);
265 
266  LOGF_DEBUG("CMD <%#02X %#02X>", command[0], command[1]);
267 
268  if (rc < 0)
269  {
270  LOGF_ERROR("<%#02X %#02X>: Error writing to device %s", command[0], command[1], hid_error(handle));
271  return false;
272  }
273 
274  return true;
275 }
276 
277 bool FocusMaster::setPosition(uint32_t ticks)
278 {
279  INDI_UNUSED(ticks);
280  return false;
281 }
282 
283 bool FocusMaster::getPosition(uint32_t *ticks)
284 {
285  INDI_UNUSED(ticks);
286  return false;
287 }
288 
290 {
291  uint8_t command[MAX_FM_BUF] = {0};
292 
293  command[0] = 0x30;
294  command[1] = 0x30;
295 
296  LOG_DEBUG("Aborting Focuser...");
297 
298  bool rc = sendCommand(command);
299 
300  if (rc)
301  {
302  if (FullMotionSP.s == IPS_BUSY)
303  {
304  IUResetSwitch(&FullMotionSP);
305  FullMotionSP.s = IPS_IDLE;
306  IDSetSwitch(&FullMotionSP, nullptr);
307  }
308 
309  if (FocusMotionSP.s == IPS_BUSY)
310  {
313  IDSetSwitch(&FocusMotionSP, nullptr);
314  }
315  }
316 
317  return rc;
318 }
319 
320 bool FocusMaster::sync(uint32_t ticks)
321 {
322  INDI_UNUSED(ticks);
323  return false;
324 }
325 
326 float FocusMaster::CalcTimeLeft(timeval start, float req)
327 {
328  double timesince;
329  double timeleft;
330  struct timeval now { 0, 0 };
331  gettimeofday(&now, nullptr);
332 
333  timesince = (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec / 1000);
334  timesince = timesince / 1000;
335  timeleft = req - timesince;
336  return timeleft;
337 }
FocusMaster::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: focusmaster.cpp:191
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
FocusMaster::getDefaultName
const char * getDefaultName()
Definition: focusmaster.cpp:73
IPState
IPState
Property state.
Definition: indiapi.h:158
hid_write
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
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
IUFillNumber
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: indidriver.c:348
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
INDI::FocuserInterface::FocusTimerN
INumber FocusTimerN[1]
Definition: indifocuserinterface.h:279
hid_exit
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
Definition: hid_libusb.c:407
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
FocusMaster::Disconnect
bool Disconnect()
Disconnect from device.
Definition: focusmaster.cpp:66
POLLMS_OVERRIDE
#define POLLMS_OVERRIDE
Definition: focusmaster.cpp:28
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1421
MAX_FM_BUF
#define MAX_FM_BUF
Definition: focusmaster.cpp:30
FocusMaster::Connect
bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: focusmaster.cpp:43
FocusMaster::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks)
MoveFocuser the focuser to an relative position.
Definition: focusmaster.cpp:253
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::FocuserInterface::FocusTimerNP
INumberVectorProperty FocusTimerNP
Definition: indifocuserinterface.h:278
INDI::FocuserInterface::FOCUS_INWARD
@ FOCUS_INWARD
Definition: indifocuserinterface.h:68
IUFillSwitchVector
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: indidriver.c:412
IUFillNumberVector
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: indidriver.c:455
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::FocuserInterface::FocusMotionSP
ISwitchVectorProperty FocusMotionSP
Definition: indifocuserinterface.h:274
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
hid_error
const HID_API_EXPORT wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
Definition: hid_libusb.c:1227
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
INDI::Focuser::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indifocuser.cpp:120
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
FocusMaster::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: focusmaster.cpp:173
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::FocuserInterface::FocusRelPosNP
INumberVectorProperty FocusRelPosNP
Definition: indifocuserinterface.h:286
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
focusMaster
std::unique_ptr< FocusMaster > focusMaster(new FocusMaster())
LOG_DEBUG
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
FocusMaster::TimerHit
void TimerHit()
Callback function to be called once SetTimer duration elapses.
Definition: focusmaster.cpp:123
INDI::Focuser::CONNECTION_NONE
@ CONNECTION_NONE
Definition: indifocuser.h:54
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
FocusMaster::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: focusmaster.cpp:78
FocusMaster::FocusMaster
FocusMaster()
Definition: focusmaster.cpp:37
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
ISState
ISState
Switch state.
Definition: indiapi.h:148
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1403
INDI::DefaultDevice::addSimulationControl
void addSimulationControl()
Add Simulation control to the driver.
Definition: defaultdevice.cpp:646
hid_open
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
currentTicks
#define currentTicks
Definition: robofocus.cpp:42
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
FocusMaster::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks)
MoveFocuser the focuser to an absolute position.
Definition: focusmaster.cpp:244
FocusMaster::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: focusmaster.cpp:105
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
INDI::Focuser::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indifocuser.cpp:168
INDI::FocuserInterface::FocusAbsPosN
INumber FocusAbsPosN[1]
Definition: indifocuserinterface.h:283
focusmaster.h
hid_close
void HID_API_EXPORT hid_close(hid_device *dev)
Close a HID device.
Definition: hid_libusb.c:1163
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
IUFillSwitch
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: indidriver.c:320
FocusMaster::AbortFocuser
virtual bool AbortFocuser()
AbortFocuser all focus motion.
Definition: focusmaster.cpp:289
FocusMaster::MoveFocuser
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.
Definition: focusmaster.cpp:212
INDI::Focuser::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indifocuser.cpp:145
Pulsar2Commands::sync
bool sync(const int fd)
Definition: lx200pulsar2.cpp:1146
FocusMaster
Definition: focusmaster.h:26
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
INDI::FocuserInterface::FOCUS_OUTWARD
@ FOCUS_OUTWARD
Definition: indifocuserinterface.h:69