Instrument Neutral Distributed Interface INDI  2.0.2
rbfocus.cpp
Go to the documentation of this file.
1 #include "rbfocus.h"
2 
3 #include "indicom.h"
4 
5 #include <cmath>
6 #include <cstring>
7 #include <memory>
8 
9 #include <termios.h>
10 #include <unistd.h>
11 
12 static std::unique_ptr<RBFOCUS> rbfocus(new RBFOCUS());
13 
15 {
16  // Absolute, Abort, and Sync
18  setVersion(1, 0);
19 }
20 
22 {
24 
25  // Focuser temperature
26  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
27  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
29 
30  IUFillSwitch(&focuserHoldS[HOLD_ON], "HOLD_ON", "Hold Enabled", ISS_OFF);
31  IUFillSwitch(&focuserHoldS[HOLD_OFF], "HOLD_OFF", "Hold Disabled", ISS_OFF);
32  IUFillSwitchVector(&focuserHoldSP, focuserHoldS, 2, getDeviceName(), "Focuser Hold", "", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0,
33  IPS_IDLE);
34 
35  IUFillSwitch(&dirS[NORMAL], "NORMAL", "Normal", ISS_OFF);
36  IUFillSwitch(&dirS[REVERSED], "REVERSED", "Reverse", ISS_OFF);
37  IUFillSwitchVector(&dirSP, dirS, 2, getDeviceName(), "Direction", "", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0,
38  IPS_IDLE);
39 
40 
41  // Relative and absolute movement
42  FocusRelPosN[0].min = 0.;
43  FocusRelPosN[0].max = 50000.;
44  FocusRelPosN[0].value = 0.;
45  FocusRelPosN[0].step = 1000;
46 
47  FocusAbsPosN[0].min = 0.;
48  FocusAbsPosN[0].max = 100000.;
49  FocusAbsPosN[0].value = 0;
50  FocusAbsPosN[0].step = 1000;
51 
52 
53  return true;
54 }
55 
57 {
59 
60  if (isConnected())
61  {
62  defineProperty(&TemperatureNP);
63  defineProperty(&focuserHoldSP);
64  defineProperty(&dirSP);
65  LOG_INFO("Focuser ready.");
66  }
67  else
68  {
69  deleteProperty(TemperatureNP.name);
70  deleteProperty(focuserHoldSP.name);
71  deleteProperty(dirSP.name);
72  }
73 
74  return true;
75 }
76 
78 {
79  if (Ack())
80  {
81 
82  LOG_INFO("RBF is online.");
83  readVersion();
84  MaxPos();
85  readHold();
86  readDir();
87  return true;
88  }
89 
90  LOG_INFO("Error retrieving data from RBFocuser, please ensure RBFocus controller is powered and the port is correct.");
91  return false;
92 }
93 
95 {
96  return "RB Focuser";
97 }
98 
99 bool RBFOCUS::Ack()
100 {
101  int nbytes_written = 0, nbytes_read = 0, rc = -1;
102  char errstr[MAXRBUF];
103  char resp[5] = {0};
104 
105  tcflush(PortFD, TCIOFLUSH);
106 
107  int numChecks = 0;
108  bool success = false;
109  while (numChecks < 3 && !success)
110  {
111  numChecks++;
112  //wait 1 second between each test.
113  sleep(1);
114 
115  bool transmissionSuccess = (rc = tty_write(PortFD, "#", 1, &nbytes_written)) == TTY_OK;
116  if(!transmissionSuccess)
117  {
118  tty_error_msg(rc, errstr, MAXRBUF);
119  LOGF_ERROR("Handshake Attempt %i, tty transmission error: %s.", numChecks, errstr);
120  }
121 
122  bool responseSuccess = (rc = tty_read(PortFD, resp, 4, DRIVER_TIMEOUT, &nbytes_read)) == TTY_OK;
123  if(!responseSuccess)
124  {
125  tty_error_msg(rc, errstr, MAXRBUF);
126  LOGF_ERROR("Handshake Attempt %i, updatePosition response error: %s.", numChecks, errstr);
127  }
128 
129  success = transmissionSuccess && responseSuccess;
130  }
131 
132  if(!success)
133  {
134  LOG_INFO("Handshake failed after 3 attempts");
135  return false;
136  }
137 
138  tcflush(PortFD, TCIOFLUSH);
139 
140  return !strcmp(resp, "OK!#");
141 }
142 
143 
144 bool RBFOCUS::readTemperature()
145 {
146  char res[DRIVER_RES] = {0};
147 
148  if (sendCommand("Q#", res) == false)
149  return false;
150 
151  int32_t temp = 0;
152  int rc = sscanf(res, "C%d#", &temp);
153  if (rc > 0)
154  // Hundredth of a degree
155  TemperatureN[0].value = temp / 100.0;
156  else
157  {
158  LOGF_ERROR("Unknown error: focuser temperature value (%s)", res);
159  return false;
160  }
161 
162  return true;
163 }
164 
165 bool RBFOCUS::readVersion()
166 {
167  return true;
168 }
169 bool RBFOCUS::readHold()
170 {
171  char res[DRIVER_RES] = {0};
172 
173  if (sendCommand("V#", res) == false)
174  {
175  return false;
176  }
177 
178  if(strcmp(res, "Enable") == 0)
179  {
180  focuserHoldS[HOLD_ON].s = ISS_ON;
181 
182  }
183  else if (strcmp(res, "Disable") == 0)
184  {
185  focuserHoldS[HOLD_OFF].s = ISS_ON;
186 
187 
188  }
189 
190 
191 
192  return true;
193 }
194 bool RBFOCUS::readDir()
195 {
196  char res[DRIVER_RES] = {0};
197 
198  if (sendCommand("B#", res) == false)
199  {
200  return false;
201  }
202 
203  if(strcmp(res, "Reversed") == 0)
204  {
205  dirS[REVERSED].s = ISS_ON;
206 
207  }
208  else if (strcmp(res, "Normal") == 0)
209  {
210  dirS[NORMAL].s = ISS_ON;
211 
212 
213  }
214 
215 
216 
217  return true;
218 }
219 bool RBFOCUS::readPosition()
220 {
221  char res[DRIVER_RES] = {0};
222 
223  if (sendCommand("P#", res) == false)
224  return false;
225 
226  int32_t pos;
227  int rc = sscanf(res, "%d#", &pos);
228 
229  if (rc > 0)
230  FocusAbsPosN[0].value = pos;
231  else
232  {
233  return false;
234  }
235 
236  return true;
237 }
238 
239 bool RBFOCUS::isMoving()
240 {
241  char res[DRIVER_RES] = {0};
242 
243  if (sendCommand("J#", res) == false)
244  return false;
245 
246  if (strcmp(res, "M1:OK") == 0)
247  return true;
248  else if (strcmp(res, "M0:OK") == 0)
249  return false;
250 
251  LOGF_ERROR("Unknown error: isMoving value (%s)", res);
252  return false;
253 
254 }
255 
256 bool RBFOCUS::MaxPos()
257 {
258  char res[DRIVER_RES] = {0};
259 
260  if (sendCommand("X#", res) == false)
261  return false;
262 
263  uint32_t mPos = 0;
264  int rc = sscanf(res, "%u#", &mPos);
265  if (rc > 0)
266  {
267 
268  FocusMaxPosN[0].value = mPos;
269  RBFOCUS::SyncPresets(mPos);
270  }
271  else
272  {
273  LOGF_ERROR("Invalid Response: focuser hold value (%s)", res);
274  return false;
275  }
276 
277  return true;
278 
279 
280 }
281 
283 {
284  char cmd[DRIVER_RES] = {0};
285 
286  snprintf(cmd, DRIVER_RES, "H%d#", mPos);
287 
288  if(sendCommand(cmd))
289  {
290  Focuser::SyncPresets(mPos);
291 
292  return true;
293  }
294  return false;
295 }
296 bool RBFOCUS::SyncFocuser(uint32_t ticks)
297 {
298  char cmd[DRIVER_RES] = {0};
299  snprintf(cmd, DRIVER_RES, "I%d#", ticks);
300  return sendCommand(cmd);
301 }
302 
303 IPState RBFOCUS::MoveAbsFocuser(uint32_t targetTicks)
304 {
305  char cmd[DRIVER_RES] = {0};
306  snprintf(cmd, DRIVER_RES, "T%d#", targetTicks);
307 
308  if (sendCommand(cmd) == false)
309  return IPS_BUSY;
310 
311  targetPos = targetTicks;
312  return IPS_BUSY;
313 }
314 
315 
316 
318 {
319  if (!isConnected())
320  {
322  return;
323  }
324 
325  bool rc = readPosition();
326  if (rc)
327  {
328  if (fabs(lastPos - FocusAbsPosN[0].value) > 5)
329  {
330  IDSetNumber(&FocusAbsPosNP, nullptr);
331  lastPos = FocusAbsPosN[0].value;
332  }
333  }
334 
335  rc = readTemperature();
336  if (rc)
337  {
338  if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
339  {
340  IDSetNumber(&TemperatureNP, nullptr);
341  lastTemperature = TemperatureN[0].value;
342  }
343  }
344 
345  if (FocusAbsPosNP.s == IPS_BUSY)
346  {
347  if (!isMoving())
348  {
350  IDSetNumber(&FocusAbsPosNP, nullptr);
351  lastPos = FocusAbsPosN[0].value;
352  LOG_INFO("Focuser reached requested position.");
353  }
354  }
355 
357 }
358 
360 {
361  return sendCommand("L#");
362 }
363 bool RBFOCUS::setHold()
364 {
365  return sendCommand("C#");
366 }
367 bool RBFOCUS::setDir()
368 {
369  return sendCommand("D#");
370 }
371 bool RBFOCUS::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
372 {
373  if (strcmp(focuserHoldSP.name, name) == 0)
374  {
375  int current_mode = IUFindOnSwitchIndex(&focuserHoldSP);
376 
377  IUUpdateSwitch(&focuserHoldSP, states, names, n);
378 
379  int target_mode = IUFindOnSwitchIndex(&focuserHoldSP);
380 
381  if (current_mode == target_mode)
382  {
383  focuserHoldSP.s = IPS_OK;
384  IDSetSwitch(&focuserHoldSP, nullptr);
385  }
386 
387  bool rc = setHold();
388  if (!rc)
389  {
390  IUResetSwitch(&focuserHoldSP);
391  focuserHoldS[current_mode].s = ISS_ON;
392  focuserHoldSP.s = IPS_ALERT;
393  IDSetSwitch(&focuserHoldSP, nullptr);
394  return false;
395  }
396 
397  focuserHoldSP.s = IPS_OK;
398  IDSetSwitch(&focuserHoldSP, nullptr);
399  return true;
400  }
401 
402  if (strcmp(dirSP.name, name) == 0)
403  {
404  int current_mode = IUFindOnSwitchIndex(&dirSP);
405 
406  IUUpdateSwitch(&dirSP, states, names, n);
407 
408  int target_mode = IUFindOnSwitchIndex(&dirSP);
409 
410  if (current_mode == target_mode)
411  {
412  dirSP.s = IPS_OK;
413  IDSetSwitch(&dirSP, nullptr);
414  }
415 
416  bool rc = setDir();
417  if (!rc)
418  {
419  IUResetSwitch(&dirSP);
420  dirS[current_mode].s = ISS_ON;
421  dirSP.s = IPS_ALERT;
422  IDSetSwitch(&dirSP, nullptr);
423  return false;
424  }
425 
426  dirSP.s = IPS_OK;
427  IDSetSwitch(&dirSP, nullptr);
428  return true;
429  }
430 
431 
432  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
433 }
434 
435 
436 bool RBFOCUS::sendCommand(const char * cmd, char * res)
437 {
438  int nbytes_written = 0, nbytes_read = 0, rc = -1;
439 
440  tcflush(PortFD, TCIOFLUSH);
441 
442  LOGF_DEBUG("CMD <%s>", cmd);
443 
444  if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
445  {
446  char errstr[MAXRBUF] = {0};
447  tty_error_msg(rc, errstr, MAXRBUF);
448  LOGF_ERROR("Serial write error: %s.", errstr);
449  return false;
450  }
451 
452  if (res == nullptr)
453  return true;
454 
455  if ((rc = tty_nread_section(PortFD, res, DRIVER_RES, DRIVER_DEL, DRIVER_TIMEOUT, &nbytes_read)) != TTY_OK)
456  {
457  char errstr[MAXRBUF] = {0};
458  tty_error_msg(rc, errstr, MAXRBUF);
459  LOGF_ERROR("Serial read error: %s.", errstr);
460  return false;
461  }
462 
463  // Remove the #
464  res[nbytes_read - 1] = 0;
465 
466  LOGF_DEBUG("RES <%s>", res);
467 
468  tcflush(PortFD, TCIOFLUSH);
469 
470  return true;
471 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INumberVectorProperty FocusAbsPosNP
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 void SyncPresets(uint32_t ticks)
syncPresets Updates the min/max/step range of the preset as per the maximum name of Absolute Focus Tr...
Definition: rbfocus.h:9
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
Definition: rbfocus.cpp:303
virtual bool SyncFocuser(uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
Definition: rbfocus.cpp:296
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: rbfocus.cpp:317
virtual bool Handshake() override
Handshake Try to communicate with Focuser and see if there is a valid response.
Definition: rbfocus.cpp:77
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: rbfocus.cpp:21
@ REVERSED
Definition: rbfocus.h:14
@ NORMAL
Definition: rbfocus.h:14
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: rbfocus.cpp:371
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
Definition: rbfocus.cpp:282
RBFOCUS()
Definition: rbfocus.cpp:14
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: rbfocus.cpp:56
@ HOLD_OFF
Definition: rbfocus.h:13
@ HOLD_ON
Definition: rbfocus.h:13
const char * getDefaultName() override
Definition: rbfocus.cpp:94
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: rbfocus.cpp:359
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
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_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
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
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
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
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
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371