Instrument Neutral Distributed Interface INDI 2.2.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
12static 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 FocusRelPosNP[0].setMin(0.);
43 FocusRelPosNP[0].setMax(50000.);
44 FocusRelPosNP[0].setValue(0.);
45 FocusRelPosNP[0].setStep(1000);
46
47 FocusAbsPosNP[0].setMin(0.);
48 FocusAbsPosNP[0].setMax(100000.);
49 FocusAbsPosNP[0].setValue(0);
50 FocusAbsPosNP[0].setStep(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
99bool 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
144bool 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
165bool RBFOCUS::readVersion()
166{
167 return true;
168}
169bool 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}
194bool 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}
219bool 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 FocusAbsPosNP[0].setValue(pos);
231 else
232 {
233 return false;
234 }
235
236 return true;
237}
238
239bool 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
256bool 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 FocusMaxPosNP[0].setValue(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}
296bool 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
303IPState 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 - FocusAbsPosNP[0].getValue()) > 5)
329 {
331 lastPos = FocusAbsPosNP[0].getValue();
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
346 {
347 if (!isMoving())
348 {
351 lastPos = FocusAbsPosNP[0].getValue();
352 LOG_INFO("Focuser reached requested position.");
353 }
354 }
355
357}
358
360{
361 return sendCommand("L#");
362}
363bool RBFOCUS::setHold()
364{
365 return sendCommand("C#");
366}
367bool RBFOCUS::setDir()
368{
369 return sendCommand("D#");
370}
371bool 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
436bool 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
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.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusMaxPosNP
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 void SyncPresets(uint32_t ticks)
Synchronizes the range (min, max, step) of the preset number properties (PresetNP) based on the focus...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
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
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
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
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
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
Updates the state and definition of properties based on the current connection status....
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:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
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_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
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
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:759
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
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition indidevapi.c:337
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
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
#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 getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369