Instrument Neutral Distributed Interface INDI  1.9.5
onfocus.cpp
Go to the documentation of this file.
1 /*
2  OnFocus Focuser
3  Copyright (C) 2018 Paul de Backer (74.0632@gmail.com)
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 
36 std::unique_ptr<OnFocus> onFocus(new OnFocus());
37 
39 {
41  lastPos = 0;
42 }
43 
45 {
46 }
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, IPS_IDLE);
54  // Maximum Travel
55  IUFillNumber(&MaxPosN[0], "MAXPOS", "Maximum Out Position", "%8.0f", 1., 10000000., 0, 0);
56  IUFillNumberVector(&MaxPosNP, MaxPosN, 1, getDeviceName(), "FOCUS_MAXPOS", "Position", OPTIONS_TAB, IP_RW, 0, IPS_IDLE );
57 
58 
59  /* Relative and absolute movement */
60  FocusRelPosN[0].min = 0.;
61  FocusRelPosN[0].max = 200.;
62  FocusRelPosN[0].value = 0.;
63  FocusRelPosN[0].step = 10.;
64 
65  FocusAbsPosN[0].min = 0.;
66  FocusAbsPosN[0].max = 10000000.;
67  FocusAbsPosN[0].value = 0.;
68  FocusAbsPosN[0].step = 500.;
69 
71 
72  return true;
73 
74 }
75 
77 {
79  if (isConnected())
80  {
81  defineProperty(&MaxPosNP);
82  defineProperty(&SetZeroSP);
83  GetFocusParams();
84  loadConfig(true);
85 
86  DEBUG(INDI::Logger::DBG_SESSION, "OnFocus parameters updated, focuser ready for use.");
87  }
88  else
89  {
90  deleteProperty(MaxPosNP.name);
91  deleteProperty(SetZeroSP.name);
92  }
93 
94  return true;
95 
96 }
97 
99 {
100  if (Ack())
101  {
102  DEBUG(INDI::Logger::DBG_SESSION, "OnFocus is online. Getting focus parameters...");
103  return true;
104  }
105  return false;
106 }
107 
109 {
110  return "OnFocus";
111 }
112 
113 bool OnFocus::Ack()
114 {
115  int nbytes_written=0, nbytes_read=0, rc=-1;
116  char errstr[MAXRBUF];
117  char resp[16];
118  sleep(2);
119  tcflush(PortFD, TCIOFLUSH);
120 
121  if ( (rc = tty_write(PortFD, ":IP#", 4, &nbytes_written)) != TTY_OK)
122  {
123  tty_error_msg(rc, errstr, MAXRBUF);
124  DEBUGF(INDI::Logger::DBG_ERROR, "Init error: %s.", errstr);
125  return false;
126  }
127  if ( (rc = tty_read(PortFD, resp, 9, ONFOCUS_TIMEOUT * 2, &nbytes_read)) != TTY_OK)
128  {
129  tty_error_msg(rc, errstr, MAXRBUF);
130  DEBUGF(INDI::Logger::DBG_ERROR, "Init error: %s.", errstr);
131  return false;
132  }
133  tcflush(PortFD, TCIOFLUSH);
134  resp[nbytes_read]='\0';
135  if (!strcmp(resp, "On-Focus#"))
136  {
137  return true;
138  }
139  else
140  {
141  DEBUGF(INDI::Logger::DBG_ERROR, "Ack Response: %s", resp);
142  return false;
143  }
144 }
145 
146 
147 bool OnFocus::updatePosition()
148 {
149  int nbytes_written=0, nbytes_read=0, rc=-1;
150  char errstr[MAXRBUF];
151  char resp[16];
152  int pos=-1;
153 
154  tcflush(PortFD, TCIOFLUSH);
155 
156  if ( (rc = tty_write(PortFD, ":GP#", 4, &nbytes_written)) != TTY_OK)
157  {
158  tty_error_msg(rc, errstr, MAXRBUF);
159  DEBUGF(INDI::Logger::DBG_ERROR, "updatePosition error: %s.", errstr);
160  return false;
161  }
162 
163  if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
164  {
165  tty_error_msg(rc, errstr, MAXRBUF);
166  DEBUGF(INDI::Logger::DBG_ERROR, "updatePosition error: %s.", errstr);
167  return false;
168  }
169 
170  tcflush(PortFD, TCIOFLUSH);
171 
172  resp[nbytes_read]='\0';
173 
174  rc = sscanf(resp, "%d#", &pos);
175 
176  if (rc > 0)
177  {
178  FocusAbsPosN[0].value = pos;
179  IDSetNumber(&FocusAbsPosNP, NULL);
180 
181  }
182  else
183  {
184  DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: focuser position value (%s)", resp);
185  return false;
186  }
187 
188  return true;
189 }
190 
191 bool OnFocus::updateMaxPos()
192 {
193  int nbytes_written=0, nbytes_read=0, rc=-1;
194  char errstr[MAXRBUF];
195  char resp[16];
196  long maxposition;
197 
198  tcflush(PortFD, TCIOFLUSH);
199 
200  if ( (rc = tty_write(PortFD, ":GM#", 4, &nbytes_written)) != TTY_OK)
201  {
202  tty_error_msg(rc, errstr, MAXRBUF);
203  DEBUGF(INDI::Logger::DBG_ERROR, "updateMaxPosition error: %s.", errstr);
204  return false;
205  }
206 
207  if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
208  {
209  tty_error_msg(rc, errstr, MAXRBUF);
210  DEBUGF(INDI::Logger::DBG_ERROR, "updateMaxPosition error: %s.", errstr);
211  return false;
212  }
213 
214  tcflush(PortFD, TCIOFLUSH);
215  resp[nbytes_read]='\0';
216 
217  rc = sscanf(resp, "%ld#", &maxposition);
218 
219  if (rc > 0)
220  {
221 
222  MaxPosN[0].value = maxposition;
223  FocusAbsPosN[0].max = maxposition;
224  IDSetNumber(&FocusAbsPosNP, NULL);
225  IDSetNumber(&MaxPosNP, NULL);
226  return true;
227  }
228 
229  DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: focuser maxposition (%s)", resp);
230  return false;
231 }
232 
233 bool OnFocus::isMoving()
234 {
235  int nbytes_written=0, nbytes_read=0, rc=-1;
236  char errstr[MAXRBUF];
237  char resp[16];
238 
239  tcflush(PortFD, TCIOFLUSH);
240 
241  if ( (rc = tty_write(PortFD, ":IS#", 4, &nbytes_written)) != TTY_OK)
242  {
243  tty_error_msg(rc, errstr, MAXRBUF);
244  DEBUGF(INDI::Logger::DBG_ERROR, "isMoving error: %s.", errstr);
245  return false;
246  }
247 
248  if ( (rc = tty_read_section(PortFD, resp, '#', ONFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
249  {
250  tty_error_msg(rc, errstr, MAXRBUF);
251  DEBUGF(INDI::Logger::DBG_ERROR, "isMoving error: %s.", errstr);
252  return false;
253  }
254 
255  tcflush(PortFD, TCIOFLUSH);
256 
257  resp[nbytes_read]='\0';
258  if (!strcmp(resp, "M#"))
259  return true;
260  else if (!strcmp(resp, "S#"))
261  return false;
262  else
263  {
264  DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: isMoving value (%s)", resp);
265  return false;
266  }
267 
268 }
269 
270 bool OnFocus::MoveMyFocuser(uint32_t position)
271 {
272  int nbytes_written=0, rc=-1;
273  char errstr[MAXRBUF];
274  char cmd[24];
275 
276  snprintf(cmd, 24, ":MA%d#", position);
277 
278  // Set Position
279  if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
280  {
281  tty_error_msg(rc, errstr, MAXRBUF);
282  DEBUGF(INDI::Logger::DBG_ERROR, "setPosition error: %s.", errstr);
283  return false;
284  }
285  return true;
286 }
287 
288 void OnFocus::setZero()
289 {
290  int nbytes_written=0, rc=-1;
291  char errstr[MAXRBUF];
292  // Set Zero
293  if ( (rc = tty_write(PortFD, ":SZ#" , 4, &nbytes_written)) != TTY_OK)
294  {
295  tty_error_msg(rc, errstr, MAXRBUF);
296  DEBUGF(INDI::Logger::DBG_ERROR, "set Zero error: %s.", errstr);
297  return;
298  }
299  updateMaxPos();
300  return;
301 }
302 
303 
304 bool OnFocus::setMaxPos(uint32_t maxPos)
305 {
306  int nbytes_written=0, rc=-1;
307  char errstr[MAXRBUF];
308  char cmd[24];
309 
310  snprintf(cmd, 24, ":SM%d#", maxPos);
311 
312  // Set Max Out
313  if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
314  {
315  tty_error_msg(rc, errstr, MAXRBUF);
316  DEBUGF(INDI::Logger::DBG_ERROR, "setPosition error: %s.", errstr);
317  return false;
318  }
319  updateMaxPos();
320  return true;
321 }
322 
323 bool OnFocus::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
324 {
325  if(strcmp(dev,getDeviceName())==0)
326  {
327  if (!strcmp(SetZeroSP.name, name))
328  {
329  setZero();
330  IUResetSwitch(&SetZeroSP);
331  SetZeroSP.s = IPS_OK;
332  IDSetSwitch(&SetZeroSP, NULL);
333  return true;
334  }
335 
336  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
337  }
338  return false;
339 }
340 
341 bool OnFocus::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
342 {
343  if(strcmp(dev,getDeviceName())==0)
344  {
345  if (!strcmp (name, MaxPosNP.name))
346  {
347  if (values[0] < FocusAbsPosN[0].value)
348  {
349  DEBUGF(INDI::Logger::DBG_ERROR, "Can't set max position lower than current absolute position ( %8.0f )", FocusAbsPosN[0].value);
350  return false;
351  }
352  IUUpdateNumber(&MaxPosNP, values, names, n);
353  FocusAbsPosN[0].max = MaxPosN[0].value;
354  setMaxPos(MaxPosN[0].value);
355  MaxPosNP.s = IPS_OK;
356  return true;
357  }
358  }
359 
360  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
361 
362 }
363 
364 void OnFocus::GetFocusParams ()
365 {
366  updatePosition();
367  updateMaxPos();
368 }
369 
370 
371 IPState OnFocus::MoveAbsFocuser(uint32_t targetTicks)
372 {
373  uint32_t targetPos = targetTicks;
374 
375  bool rc = false;
376 
377  rc = MoveMyFocuser(targetPos);
378 
379  if (rc == false)
380  return IPS_ALERT;
381 
383 
384  return IPS_BUSY;
385 }
386 
388 {
389  uint32_t newPosition=0;
390  bool rc=false;
391 
392  if (dir == FOCUS_INWARD)
393  newPosition = uint32_t(FocusAbsPosN[0].value) - ticks;
394  else
395  newPosition = uint32_t(FocusAbsPosN[0].value) + ticks;
396 
397  rc = MoveMyFocuser(newPosition);
398 
399  if (rc == false)
400  return IPS_ALERT;
401 
402  FocusRelPosN[0].value = ticks;
404 
405  return IPS_BUSY;
406 }
407 
409 {
410  if (isConnected() == false)
411  {
413  return;
414  }
415 
416  bool rc = updatePosition();
417  if (rc)
418  {
419  if (fabs(lastPos - FocusAbsPosN[0].value) > 5)
420  {
421  IDSetNumber(&FocusAbsPosNP, NULL);
422  lastPos = FocusAbsPosN[0].value;
423  }
424  }
425 
426 
428  {
429  if (isMoving() == false)
430  {
433  IDSetNumber(&FocusAbsPosNP, NULL);
434  IDSetNumber(&FocusRelPosNP, NULL);
435  lastPos = FocusAbsPosN[0].value;
436  DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached requested position.");
437  }
438  }
440 
441 }
442 
444 {
445  int nbytes_written;
446  if (tty_write(PortFD, ":MH#", 4, &nbytes_written) == TTY_OK)
447  {
450  IDSetNumber(&FocusAbsPosNP, NULL);
451  IDSetNumber(&FocusRelPosNP, NULL);
452  return true;
453  }
454  else
455  return false;
456 }
457 
458 
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
OnFocus::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: onfocus.cpp:48
INDI::FocuserInterface::FOCUSER_CAN_REL_MOVE
@ FOCUSER_CAN_REL_MOVE
Definition: indifocuserinterface.h:75
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
IPState
IPState
Property state.
Definition: indiapi.h:158
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
OnFocus::~OnFocus
~OnFocus()
Definition: onfocus.cpp:44
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
OPTIONS_TAB
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Definition: defaultdevice.cpp:39
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
POLLMS_OVERRIDE
#define POLLMS_OVERRIDE
Definition: onfocus.cpp:34
INDI::Logger::DBG_SESSION
@ DBG_SESSION
Definition: indilogger.h:194
OnFocus::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: onfocus.cpp:323
tty_read_section
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:557
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
OnFocus::getDefaultName
const char * getDefaultName() override
Definition: onfocus.cpp:108
onfocus.h
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
DEBUG
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1156
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
OnFocus
Definition: onfocus.h:25
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::Focuser::PortFD
int PortFD
Definition: indifocuser.h:116
OnFocus::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: onfocus.cpp:387
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
OnFocus::OnFocus
OnFocus()
Definition: onfocus.cpp:38
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
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
OnFocus::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: onfocus.cpp:341
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
ONFOCUS_TIMEOUT
#define ONFOCUS_TIMEOUT
Definition: onfocus.cpp:32
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
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
INDI::FocuserInterface::FocusRelPosNP
INumberVectorProperty FocusRelPosNP
Definition: indifocuserinterface.h:286
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
OnFocus::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t ticks) override
MoveFocuser the focuser to an absolute position.
Definition: onfocus.cpp:371
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
OnFocus::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: onfocus.cpp:76
onFocus
std::unique_ptr< OnFocus > onFocus(new OnFocus())
name
const char * name
Definition: indiserver.c:116
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
OnFocus::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: onfocus.cpp:98
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
DEBUGF
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
ISState
ISState
Switch state.
Definition: indiapi.h:148
OnFocus::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: onfocus.cpp:408
INDI::DefaultDevice::addDebugControl
void addDebugControl()
Add Debug control to the driver.
Definition: defaultdevice.cpp:639
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
TTY_OK
@ TTY_OK
Definition: indicom.h:94
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
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
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
OnFocus::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: onfocus.cpp:443
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370