Instrument Neutral Distributed Interface INDI  1.9.5
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  return false;
175 }
176 
177  if(strcmp(res, "Enable")==0)
178  {
179  focuserHoldS[HOLD_ON].s = ISS_ON;
180 
181  }
182  else if (strcmp(res, "Disable")==0)
183  {
184  focuserHoldS[HOLD_OFF].s = ISS_ON;
185 
186 
187  }
188 
189 
190 
191  return true;
192 }
193 bool RBFOCUS::readDir()
194 {
195  char res[DRIVER_RES] = {0};
196 
197  if (sendCommand("B#", res) == false){
198  return false;
199 }
200 
201  if(strcmp(res, "Reversed")==0)
202  {
203  dirS[REVERSED].s = ISS_ON;
204 
205  }
206  else if (strcmp(res, "Normal")==0)
207  {
208  dirS[NORMAL].s = ISS_ON;
209 
210 
211  }
212 
213 
214 
215  return true;
216 }
217 bool RBFOCUS::readPosition()
218 {
219  char res[DRIVER_RES] = {0};
220 
221  if (sendCommand("P#", res) == false)
222  return false;
223 
224  int32_t pos;
225  int rc = sscanf(res, "%d#", &pos);
226 
227  if (rc > 0)
228  FocusAbsPosN[0].value = pos;
229  else
230  {
231  return false;
232  }
233 
234  return true;
235 }
236 
237 bool RBFOCUS::isMoving()
238 {
239  char res[DRIVER_RES] = {0};
240 
241  if (sendCommand("J#", res) == false)
242  return false;
243 
244  if (strcmp(res, "M1:OK") == 0)
245  return true;
246  else if (strcmp(res, "M0:OK") == 0)
247  return false;
248 
249  LOGF_ERROR("Unknown error: isMoving value (%s)", res);
250  return false;
251 
252 }
253 
254 bool RBFOCUS::MaxPos(){
255  char res[DRIVER_RES] = {0};
256 
257  if (sendCommand("X#", res) == false)
258  return false;
259 
260  uint32_t mPos = 0;
261  int rc = sscanf(res, "%u#", &mPos);
262  if (rc >0){
263 
264  FocusMaxPosN[0].value = mPos;
265  RBFOCUS::SyncPresets(mPos);
266  }else
267  {
268  LOGF_ERROR("Invalid Response: focuser hold value (%s)", res);
269  return false;
270  }
271 
272  return true;
273 
274 
275 }
276 
278 {
279  char cmd[DRIVER_RES] = {0};
280 
281  snprintf(cmd, DRIVER_RES, "H%d#", mPos);
282 
283  if(sendCommand(cmd))
284  {
285  Focuser::SyncPresets(mPos);
286 
287  return true;
288  }
289  return false;
290 }
291 bool RBFOCUS::SyncFocuser(uint32_t ticks)
292 {
293  char cmd[DRIVER_RES] = {0};
294  snprintf(cmd, DRIVER_RES, "I%d#", ticks);
295  return sendCommand(cmd);
296 }
297 
298 IPState RBFOCUS::MoveAbsFocuser(uint32_t targetTicks)
299 {
300  char cmd[DRIVER_RES] = {0};
301  snprintf(cmd, DRIVER_RES, "T%d#", targetTicks);
302 
303  if (sendCommand(cmd) == false)
304  return IPS_BUSY;
305 
306  targetPos = targetTicks;
307  return IPS_BUSY;
308 }
309 
310 
311 
313 {
314  if (!isConnected())
315  {
317  return;
318  }
319 
320  bool rc = readPosition();
321  if (rc)
322  {
323  if (fabs(lastPos - FocusAbsPosN[0].value) > 5)
324  {
325  IDSetNumber(&FocusAbsPosNP, nullptr);
326  lastPos = FocusAbsPosN[0].value;
327  }
328  }
329 
330  rc = readTemperature();
331  if (rc)
332  {
333  if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
334  {
335  IDSetNumber(&TemperatureNP, nullptr);
336  lastTemperature = TemperatureN[0].value;
337  }
338  }
339 
340  if (FocusAbsPosNP.s == IPS_BUSY)
341  {
342  if (!isMoving())
343  {
345  IDSetNumber(&FocusAbsPosNP, nullptr);
346  lastPos = FocusAbsPosN[0].value;
347  LOG_INFO("Focuser reached requested position.");
348  }
349  }
350 
352 }
353 
355 {
356  return sendCommand("L#");
357 }
358 bool RBFOCUS::setHold()
359 {
360  return sendCommand("C#");
361 }
362 bool RBFOCUS::setDir()
363 {
364  return sendCommand("D#");
365 }
366 bool RBFOCUS::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n){
367  if (strcmp(focuserHoldSP.name, name) == 0)
368  {
369  int current_mode = IUFindOnSwitchIndex(&focuserHoldSP);
370 
371  IUUpdateSwitch(&focuserHoldSP, states, names, n);
372 
373  int target_mode = IUFindOnSwitchIndex(&focuserHoldSP);
374 
375  if (current_mode == target_mode)
376  {
377  focuserHoldSP.s = IPS_OK;
378  IDSetSwitch(&focuserHoldSP, nullptr);
379  }
380 
381  bool rc = setHold();
382  if (!rc)
383  {
384  IUResetSwitch(&focuserHoldSP);
385  focuserHoldS[current_mode].s = ISS_ON;
386  focuserHoldSP.s = IPS_ALERT;
387  IDSetSwitch(&focuserHoldSP, nullptr);
388  return false;
389  }
390 
391  focuserHoldSP.s = IPS_OK;
392  IDSetSwitch(&focuserHoldSP, nullptr);
393  return true;
394  }
395 
396  if (strcmp(dirSP.name, name) == 0)
397  {
398  int current_mode = IUFindOnSwitchIndex(&dirSP);
399 
400  IUUpdateSwitch(&dirSP, states, names, n);
401 
402  int target_mode = IUFindOnSwitchIndex(&dirSP);
403 
404  if (current_mode == target_mode)
405  {
406  dirSP.s = IPS_OK;
407  IDSetSwitch(&dirSP, nullptr);
408  }
409 
410  bool rc = setDir();
411  if (!rc)
412  {
413  IUResetSwitch(&dirSP);
414  dirS[current_mode].s = ISS_ON;
415  dirSP.s = IPS_ALERT;
416  IDSetSwitch(&dirSP, nullptr);
417  return false;
418  }
419 
420  dirSP.s = IPS_OK;
421  IDSetSwitch(&dirSP, nullptr);
422  return true;
423  }
424 
425 
426  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
427 }
428 
429 
430 bool RBFOCUS::sendCommand(const char * cmd, char * res)
431 {
432  int nbytes_written = 0, nbytes_read = 0, rc = -1;
433 
434  tcflush(PortFD, TCIOFLUSH);
435 
436  LOGF_DEBUG("CMD <%s>", cmd);
437 
438  if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
439  {
440  char errstr[MAXRBUF] = {0};
441  tty_error_msg(rc, errstr, MAXRBUF);
442  LOGF_ERROR("Serial write error: %s.", errstr);
443  return false;
444  }
445 
446  if (res == nullptr)
447  return true;
448 
449  if ((rc = tty_nread_section(PortFD, res, DRIVER_RES, DRIVER_DEL, DRIVER_TIMEOUT, &nbytes_read)) != TTY_OK)
450  {
451  char errstr[MAXRBUF] = {0};
452  tty_error_msg(rc, errstr, MAXRBUF);
453  LOGF_ERROR("Serial read error: %s.", errstr);
454  return false;
455  }
456 
457  // Remove the #
458  res[nbytes_read - 1] = 0;
459 
460  LOGF_DEBUG("RES <%s>", res);
461 
462  tcflush(PortFD, TCIOFLUSH);
463 
464  return true;
465 }
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::FocuserInterface::FOCUSER_CAN_SYNC
@ FOCUSER_CAN_SYNC
Definition: indifocuserinterface.h:78
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
RBFOCUS::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
Definition: rbfocus.cpp:298
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
IPState
IPState
Property state.
Definition: indiapi.h:158
tty_nread_section
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:657
RBFOCUS::NORMAL
@ NORMAL
Definition: rbfocus.h:14
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
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
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
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
RBFOCUS::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: rbfocus.cpp:366
INDI::DefaultDevice::setVersion
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
Definition: defaultdevice.cpp:1219
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
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
INDI::Focuser::SyncPresets
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: indifocuser.cpp:392
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
RBFOCUS::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: rbfocus.cpp:56
RBFOCUS::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: rbfocus.cpp:21
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
RBFOCUS::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: rbfocus.cpp:354
RBFOCUS::Handshake
virtual bool Handshake() override
Handshake Try to communicate with Focuser and see if there is a valid response.
Definition: rbfocus.cpp:77
rbfocus.h
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
RBFOCUS
Definition: rbfocus.h:8
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
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
RBFOCUS::RBFOCUS
RBFOCUS()
Definition: rbfocus.cpp:14
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
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
name
const char * name
Definition: indiserver.c:116
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::FocuserInterface::FocusMaxPosN
INumber FocusMaxPosN[1]
Definition: indifocuserinterface.h:291
RBFOCUS::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: rbfocus.cpp:312
IP_RW
@ IP_RW
Definition: indiapi.h:185
RBFOCUS::getDefaultName
const char * getDefaultName() override
Definition: rbfocus.cpp:94
ISState
ISState
Switch state.
Definition: indiapi.h:148
RBFOCUS::SyncFocuser
virtual bool SyncFocuser(uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
Definition: rbfocus.cpp:291
RBFOCUS::HOLD_ON
@ HOLD_ON
Definition: rbfocus.h:13
RBFOCUS::HOLD_OFF
@ HOLD_OFF
Definition: rbfocus.h:13
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
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_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:465
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.
RBFOCUS::REVERSED
@ REVERSED
Definition: rbfocus.h:14
RBFOCUS::SetFocuserMaxPosition
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
Definition: rbfocus.cpp:277
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
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151