Instrument Neutral Distributed Interface INDI  2.0.2
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,
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  FocusRelPosN[0].min = 0.;
62  FocusRelPosN[0].max = 200.;
63  FocusRelPosN[0].value = 0.;
64  FocusRelPosN[0].step = 10.;
65 
66  FocusAbsPosN[0].min = 0.;
67  FocusAbsPosN[0].max = 10000000.;
68  FocusAbsPosN[0].value = 0.;
69  FocusAbsPosN[0].step = 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 
114 bool 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 
148 bool 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  FocusAbsPosN[0].value = pos;
180  IDSetNumber(&FocusAbsPosNP, NULL);
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 
192 bool 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  FocusAbsPosN[0].max = maxposition;
225  IDSetNumber(&FocusAbsPosNP, NULL);
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 
234 bool 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 
271 bool 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 
289 void 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 
305 bool 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 
324 bool 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 
342 bool 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] < FocusAbsPosN[0].value)
349  {
350  DEBUGF(INDI::Logger::DBG_ERROR, "Can't set max position lower than current absolute position ( %8.0f )",
351  FocusAbsPosN[0].value);
352  return false;
353  }
354  IUUpdateNumber(&MaxPosNP, values, names, n);
355  FocusAbsPosN[0].max = 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 
366 void OnFocus::GetFocusParams ()
367 {
368  updatePosition();
369  updateMaxPos();
370 }
371 
372 
373 IPState 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(FocusAbsPosN[0].value) - ticks;
396  else
397  newPosition = uint32_t(FocusAbsPosN[0].value) + ticks;
398 
399  rc = MoveMyFocuser(newPosition);
400 
401  if (rc == false)
402  return IPS_ALERT;
403 
404  FocusRelPosN[0].value = 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 - FocusAbsPosN[0].value) > 5)
422  {
423  IDSetNumber(&FocusAbsPosNP, NULL);
424  lastPos = FocusAbsPosN[0].value;
425  }
426  }
427 
428 
430  {
431  if (isMoving() == false)
432  {
435  IDSetNumber(&FocusAbsPosNP, NULL);
436  IDSetNumber(&FocusRelPosNP, NULL);
437  lastPos = FocusAbsPosN[0].value;
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  {
452  IDSetNumber(&FocusAbsPosNP, NULL);
453  IDSetNumber(&FocusRelPosNP, NULL);
454  return true;
455  }
456  else
457  return false;
458 }
459 
460 
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
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.
OnFocus()
Definition: onfocus.cpp:38
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
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
Initilize properties initial state and value. The child class must implement this function.
Definition: onfocus.cpp:48
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
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
perform handshake with device to check communication
Definition: onfocus.cpp:99
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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: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_1OFMANY
Definition: indiapi.h:173
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:566
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
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
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
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 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 MAXRBUF
Definition: indiserver.cpp:102
#define POLLMS_OVERRIDE
Definition: onfocus.cpp:34
#define ONFOCUS_TIMEOUT
Definition: onfocus.cpp:32
std::unique_ptr< OnFocus > onFocus(new OnFocus())
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371