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
RBFOCUS()14 RBFOCUS::RBFOCUS()
15 {
16 // Absolute, Abort, and Sync
17 FI::SetCapability(FOCUSER_CAN_ABS_MOVE | FOCUSER_CAN_ABORT | FOCUSER_CAN_SYNC);
18 setVersion(1, 0);
19 }
20
initProperties()21 bool RBFOCUS::initProperties()
22 {
23 INDI::Focuser::initProperties();
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",
28 MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
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
updateProperties()56 bool RBFOCUS::updateProperties()
57 {
58 INDI::Focuser::updateProperties();
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
Handshake()77 bool RBFOCUS::Handshake()
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
getDefaultName()94 const char * RBFOCUS::getDefaultName()
95 {
96 return "RB Focuser";
97 }
98
Ack()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
readTemperature()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
readVersion()165 bool RBFOCUS::readVersion()
166 {
167 return true;
168 }
readHold()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 }
readDir()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 }
readPosition()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
isMoving()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
MaxPos()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
SetFocuserMaxPosition(uint32_t mPos)277 bool RBFOCUS::SetFocuserMaxPosition(uint32_t mPos)
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 }
SyncFocuser(uint32_t ticks)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
MoveAbsFocuser(uint32_t targetTicks)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
TimerHit()312 void RBFOCUS::TimerHit()
313 {
314 if (!isConnected())
315 {
316 SetTimer(getCurrentPollingPeriod());
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 {
344 FocusAbsPosNP.s = IPS_OK;
345 IDSetNumber(&FocusAbsPosNP, nullptr);
346 lastPos = FocusAbsPosN[0].value;
347 LOG_INFO("Focuser reached requested position.");
348 }
349 }
350
351 SetTimer(getCurrentPollingPeriod());
352 }
353
AbortFocuser()354 bool RBFOCUS::AbortFocuser()
355 {
356 return sendCommand("L#");
357 }
setHold()358 bool RBFOCUS::setHold()
359 {
360 return sendCommand("C#");
361 }
setDir()362 bool RBFOCUS::setDir()
363 {
364 return sendCommand("D#");
365 }
ISNewSwitch(const char * dev,const char * name,ISState * states,char * names[],int n)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
sendCommand(const char * cmd,char * res)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 }
466