Instrument Neutral Distributed Interface INDI 2.2.5
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.
35std::unique_ptr<FocusMaster> focusMaster(new FocusMaster());
36
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,
91
92 FocusAbsPosNP[0].setMin(SyncNP[0].setMin(0));
93 FocusAbsPosNP[0].setMax(SyncNP[0].getMax());
94 FocusAbsPosNP[0].setStep(SyncN[0].step);
95 FocusAbsPosNP[0].setValue(0);
96
97 FocusRelPosNP[0].setMax((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 2);
98 FocusRelPosNP[0].setStep(FocusRelPosNP[0].getMax() / 100.0);
99 FocusRelPosNP[0].setValue(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
132 {
133 float remaining = CalcTimeLeft(focusMoveStart, focusMoveRequest);
134
135 if (remaining <= 0)
136 {
138 FocusTimerNP[0].setValue(0);
139 AbortFocuser();
140 }
141 else
142 FocusTimerNP[0].setValue(remaining * 1000.0);
143
145 }
146
147#if 0
148 bool rc = getPosition(&currentTicks);
149
150 if (rc)
151 FocusAbsPosNP[0].setValue(currentTicks);
152
154 {
155 if (targetPosition == FocusAbsPosNP[0].getValue())
156 {
158 {
161 }
162
164 LOG_DEBUG("Focuser reached target position.");
165 }
166 }
167
169#endif
170
172}
173
174bool 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}
192bool 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
213IPState 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 = FocusAbsPosNP[0].getValue() + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
257
258 return MoveAbsFocuser(finalTicks);
259}
260
261bool 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
278bool FocusMaster::setPosition(uint32_t ticks)
279{
280 INDI_UNUSED(ticks);
281 return false;
282}
283
284bool 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 {
315 }
316 }
317
318 return rc;
319}
320
321bool FocusMaster::sync(uint32_t ticks)
322{
323 INDI_UNUSED(ticks);
324 return false;
325}
326
327float 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()
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
bool Disconnect()
Disconnect from device.
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
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
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
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
virtual bool AbortFocuser()
AbortFocuser all focus motion.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual IPState MoveAbsFocuser(uint32_t targetTicks)
MoveFocuser the focuser to an absolute position.
bool isConnected() const
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.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertySwitch FocusMotionSP
INDI::PropertyNumber FocusTimerNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
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 setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
#define MAX_FM_BUF
std::unique_ptr< FocusMaster > focusMaster(new FocusMaster())
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.
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
Definition hid_libusb.c:407
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ 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
@ ISR_ATMOST1
Definition indiapi.h:172
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:490
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition indidevapi.c:337
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
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:376
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:398
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:453
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#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 getDeviceName
#define POLLMS_OVERRIDE
Definition onfocus.cpp:34
#define currentTicks
Definition robofocus.cpp:38
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369