Instrument Neutral Distributed Interface INDI 2.2.5
onfocus.cpp
Go to the documentation of this file.
1/*
2 OnFocus Focuser
3 Copyright (C) 2018 Paul de Backer ([email protected])
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#include "onfocus.h"
22#include "indicom.h"
23
24#include <stdio.h>
25#include <termios.h>
26#include <string.h>
27#include <sys/time.h>
28#include <unistd.h>
29#include <math.h>
30#include <memory>
31
32#define ONFOCUS_TIMEOUT 4
33
34#define POLLMS_OVERRIDE 1500
35
36std::unique_ptr<OnFocus> onFocus(new OnFocus());
37
43
47
49{
51 // SetZero
52 IUFillSwitch(&SetZeroS[0], "SETZERO", "Set Current Position to 0", ISS_OFF);
53 IUFillSwitchVector(&SetZeroSP, SetZeroS, 1, getDeviceName(), "Zero Position", "", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0,
54 IPS_IDLE);
55 // Maximum Travel
56 IUFillNumber(&MaxPosN[0], "MAXPOS", "Maximum Out Position", "%8.0f", 1., 10000000., 0, 0);
57 IUFillNumberVector(&MaxPosNP, MaxPosN, 1, getDeviceName(), "FOCUS_MAXPOS", "Position", OPTIONS_TAB, IP_RW, 0, IPS_IDLE );
58
59
60 /* Relative and absolute movement */
61 FocusRelPosNP[0].setMin(0.);
62 FocusRelPosNP[0].setMax(200.);
63 FocusRelPosNP[0].setValue(0.);
64 FocusRelPosNP[0].setStep(10.);
65
66 FocusAbsPosNP[0].setMin(0.);
67 FocusAbsPosNP[0].setMax(10000000.);
68 FocusAbsPosNP[0].setValue(0.);
69 FocusAbsPosNP[0].setStep(500.);
70
72
73 return true;
74
75}
76
78{
80 if (isConnected())
81 {
82 defineProperty(&MaxPosNP);
83 defineProperty(&SetZeroSP);
84 GetFocusParams();
85 loadConfig(true);
86
87 DEBUG(INDI::Logger::DBG_SESSION, "OnFocus parameters updated, focuser ready for use.");
88 }
89 else
90 {
91 deleteProperty(MaxPosNP.name);
92 deleteProperty(SetZeroSP.name);
93 }
94
95 return true;
96
97}
98
100{
101 if (Ack())
102 {
103 DEBUG(INDI::Logger::DBG_SESSION, "OnFocus is online. Getting focus parameters...");
104 return true;
105 }
106 return false;
107}
108
110{
111 return "OnFocus";
112}
113
114bool OnFocus::Ack()
115{
116 int nbytes_written = 0, nbytes_read = 0, rc = -1;
117 char errstr[MAXRBUF];
118 char resp[16];
119 sleep(2);
120 tcflush(PortFD, TCIOFLUSH);
121
122 if ( (rc = tty_write(PortFD, ":IP#", 4, &nbytes_written)) != TTY_OK)
123 {
124 tty_error_msg(rc, errstr, MAXRBUF);
125 DEBUGF(INDI::Logger::DBG_ERROR, "Init error: %s.", errstr);
126 return false;
127 }
128 if ( (rc = tty_read(PortFD, resp, 9, ONFOCUS_TIMEOUT * 2, &nbytes_read)) != TTY_OK)
129 {
130 tty_error_msg(rc, errstr, MAXRBUF);
131 DEBUGF(INDI::Logger::DBG_ERROR, "Init error: %s.", errstr);
132 return false;
133 }
134 tcflush(PortFD, TCIOFLUSH);
135 resp[nbytes_read] = '\0';
136 if (!strcmp(resp, "On-Focus#"))
137 {
138 return true;
139 }
140 else
141 {
142 DEBUGF(INDI::Logger::DBG_ERROR, "Ack Response: %s", resp);
143 return false;
144 }
145}
146
147
148bool OnFocus::updatePosition()
149{
150 int nbytes_written = 0, nbytes_read = 0, rc = -1;
151 char errstr[MAXRBUF];
152 char resp[16];
153 int pos = -1;
154
155 tcflush(PortFD, TCIOFLUSH);
156
157 if ( (rc = tty_write(PortFD, ":GP#", 4, &nbytes_written)) != TTY_OK)
158 {
159 tty_error_msg(rc, errstr, MAXRBUF);
160 DEBUGF(INDI::Logger::DBG_ERROR, "updatePosition error: %s.", errstr);
161 return false;
162 }
163
164 if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
165 {
166 tty_error_msg(rc, errstr, MAXRBUF);
167 DEBUGF(INDI::Logger::DBG_ERROR, "updatePosition error: %s.", errstr);
168 return false;
169 }
170
171 tcflush(PortFD, TCIOFLUSH);
172
173 resp[nbytes_read] = '\0';
174
175 rc = sscanf(resp, "%d#", &pos);
176
177 if (rc > 0)
178 {
179 FocusAbsPosNP[0].setValue(pos);
181
182 }
183 else
184 {
185 DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: focuser position value (%s)", resp);
186 return false;
187 }
188
189 return true;
190}
191
192bool OnFocus::updateMaxPos()
193{
194 int nbytes_written = 0, nbytes_read = 0, rc = -1;
195 char errstr[MAXRBUF];
196 char resp[16];
197 long maxposition;
198
199 tcflush(PortFD, TCIOFLUSH);
200
201 if ( (rc = tty_write(PortFD, ":GM#", 4, &nbytes_written)) != TTY_OK)
202 {
203 tty_error_msg(rc, errstr, MAXRBUF);
204 DEBUGF(INDI::Logger::DBG_ERROR, "updateMaxPosition error: %s.", errstr);
205 return false;
206 }
207
208 if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
209 {
210 tty_error_msg(rc, errstr, MAXRBUF);
211 DEBUGF(INDI::Logger::DBG_ERROR, "updateMaxPosition error: %s.", errstr);
212 return false;
213 }
214
215 tcflush(PortFD, TCIOFLUSH);
216 resp[nbytes_read] = '\0';
217
218 rc = sscanf(resp, "%ld#", &maxposition);
219
220 if (rc > 0)
221 {
222
223 MaxPosN[0].value = maxposition;
224 FocusAbsPosNP[0].setMax(maxposition);
226 IDSetNumber(&MaxPosNP, NULL);
227 return true;
228 }
229
230 DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: focuser maxposition (%s)", resp);
231 return false;
232}
233
234bool OnFocus::isMoving()
235{
236 int nbytes_written = 0, nbytes_read = 0, rc = -1;
237 char errstr[MAXRBUF];
238 char resp[16];
239
240 tcflush(PortFD, TCIOFLUSH);
241
242 if ( (rc = tty_write(PortFD, ":IS#", 4, &nbytes_written)) != TTY_OK)
243 {
244 tty_error_msg(rc, errstr, MAXRBUF);
245 DEBUGF(INDI::Logger::DBG_ERROR, "isMoving error: %s.", errstr);
246 return false;
247 }
248
249 if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
250 {
251 tty_error_msg(rc, errstr, MAXRBUF);
252 DEBUGF(INDI::Logger::DBG_ERROR, "isMoving error: %s.", errstr);
253 return false;
254 }
255
256 tcflush(PortFD, TCIOFLUSH);
257
258 resp[nbytes_read] = '\0';
259 if (!strcmp(resp, "M#"))
260 return true;
261 else if (!strcmp(resp, "S#"))
262 return false;
263 else
264 {
265 DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: isMoving value (%s)", resp);
266 return false;
267 }
268
269}
270
271bool OnFocus::MoveMyFocuser(uint32_t position)
272{
273 int nbytes_written = 0, rc = -1;
274 char errstr[MAXRBUF];
275 char cmd[24];
276
277 snprintf(cmd, 24, ":MA%d#", position);
278
279 // Set Position
280 if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
281 {
282 tty_error_msg(rc, errstr, MAXRBUF);
283 DEBUGF(INDI::Logger::DBG_ERROR, "setPosition error: %s.", errstr);
284 return false;
285 }
286 return true;
287}
288
289void OnFocus::setZero()
290{
291 int nbytes_written = 0, rc = -1;
292 char errstr[MAXRBUF];
293 // Set Zero
294 if ( (rc = tty_write(PortFD, ":SZ#", 4, &nbytes_written)) != TTY_OK)
295 {
296 tty_error_msg(rc, errstr, MAXRBUF);
297 DEBUGF(INDI::Logger::DBG_ERROR, "set Zero error: %s.", errstr);
298 return;
299 }
300 updateMaxPos();
301 return;
302}
303
304
305bool OnFocus::setMaxPos(uint32_t maxPos)
306{
307 int nbytes_written = 0, rc = -1;
308 char errstr[MAXRBUF];
309 char cmd[24];
310
311 snprintf(cmd, 24, ":SM%d#", maxPos);
312
313 // Set Max Out
314 if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
315 {
316 tty_error_msg(rc, errstr, MAXRBUF);
317 DEBUGF(INDI::Logger::DBG_ERROR, "setPosition error: %s.", errstr);
318 return false;
319 }
320 updateMaxPos();
321 return true;
322}
323
324bool OnFocus::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
325{
326 if(strcmp(dev, getDeviceName()) == 0)
327 {
328 if (!strcmp(SetZeroSP.name, name))
329 {
330 setZero();
331 IUResetSwitch(&SetZeroSP);
332 SetZeroSP.s = IPS_OK;
333 IDSetSwitch(&SetZeroSP, NULL);
334 return true;
335 }
336
337 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
338 }
339 return false;
340}
341
342bool OnFocus::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
343{
344 if(strcmp(dev, getDeviceName()) == 0)
345 {
346 if (!strcmp (name, MaxPosNP.name))
347 {
348 if (values[0] < FocusAbsPosNP[0].getValue())
349 {
350 DEBUGF(INDI::Logger::DBG_ERROR, "Can't set max position lower than current absolute position ( %8.0f )",
351 FocusAbsPosNP[0].getValue());
352 return false;
353 }
354 IUUpdateNumber(&MaxPosNP, values, names, n);
355 FocusAbsPosNP[0].setMax(MaxPosN[0].value);
356 setMaxPos(MaxPosN[0].value);
357 MaxPosNP.s = IPS_OK;
358 return true;
359 }
360 }
361
362 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
363
364}
365
366void OnFocus::GetFocusParams ()
367{
368 updatePosition();
369 updateMaxPos();
370}
371
372
373IPState OnFocus::MoveAbsFocuser(uint32_t targetTicks)
374{
375 uint32_t targetPos = targetTicks;
376
377 bool rc = false;
378
379 rc = MoveMyFocuser(targetPos);
380
381 if (rc == false)
382 return IPS_ALERT;
383
385
386 return IPS_BUSY;
387}
388
390{
391 uint32_t newPosition = 0;
392 bool rc = false;
393
394 if (dir == FOCUS_INWARD)
395 newPosition = uint32_t(FocusAbsPosNP[0].getValue()) - ticks;
396 else
397 newPosition = uint32_t(FocusAbsPosNP[0].getValue()) + ticks;
398
399 rc = MoveMyFocuser(newPosition);
400
401 if (rc == false)
402 return IPS_ALERT;
403
404 FocusRelPosNP[0].setValue(ticks);
406
407 return IPS_BUSY;
408}
409
411{
412 if (isConnected() == false)
413 {
415 return;
416 }
417
418 bool rc = updatePosition();
419 if (rc)
420 {
421 if (fabs(lastPos - FocusAbsPosNP[0].getValue()) > 5)
422 {
424 lastPos = FocusAbsPosNP[0].getValue();
425 }
426 }
427
428
430 {
431 if (isMoving() == false)
432 {
437 lastPos = FocusAbsPosNP[0].getValue();
438 DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached requested position.");
439 }
440 }
442
443}
444
446{
447 int nbytes_written;
448 if (tty_write(PortFD, ":MH#", 4, &nbytes_written) == TTY_OK)
449 {
454 return true;
455 }
456 else
457 return false;
458}
459
460
bool isConnected() const
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
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
OnFocus()
Definition onfocus.cpp:38
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
Definition onfocus.cpp:77
virtual IPState MoveAbsFocuser(uint32_t ticks) override
MoveFocuser the focuser to an absolute position.
Definition onfocus.cpp:373
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition onfocus.cpp:445
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition onfocus.cpp:48
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...
Definition onfocus.cpp:342
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition onfocus.cpp:389
~OnFocus()
Definition onfocus.cpp:44
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
Definition onfocus.cpp:99
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...
Definition onfocus.cpp:324
const char * getDefaultName() override
Definition onfocus.cpp:109
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition onfocus.cpp:410
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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_1OFMANY
Definition indiapi.h:171
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:653
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
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
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
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition indilogger.h:56
#define DEBUGF(priority, msg,...)
Definition indilogger.h:57
#define getDeviceName
std::unique_ptr< OnFocus > onFocus(new OnFocus())
#define POLLMS_OVERRIDE
Definition onfocus.cpp:34
#define ONFOCUS_TIMEOUT
Definition onfocus.cpp:32
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369