Instrument Neutral Distributed Interface INDI 2.2.5
lx200_OpenAstroTech.cpp
Go to the documentation of this file.
1/*
2 OpenAstroTech
3 Copyright (C) 2021 Anjo Krank
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 "lx200_OpenAstroTech.h"
22
23#include "indicom.h"
24#include "lx200driver.h"
25
26#include <cmath>
27#include <string.h>
28
29#include <libnova/transform.h>
30#include <termios.h>
31#include <unistd.h>
32#include <mutex>
33
34#define RB_MAX_LEN 64
35#define CMD_MAX_LEN 32
36extern std::mutex lx200CommsLock;
37
44
46{
47 bool result = LX200GPS::Handshake();
48 return result;
49}
50
51#define OAT_MEADE_COMMAND "OAT_MEADE_COMMAND"
52#define OAT_DEC_LOWER_LIMIT "OAT_DEC_LOWER_LIMIT"
53#define OAT_DEC_UPPER_LIMIT "OAT_DEC_UPPER_LIMIT"
54#define OAT_GET_DEBUG_LEVEL "OAT_GET_DEBUG_LEVEL"
55#define OAT_GET_ENABLED_DEBUG_LEVEL "OAT_GET_ENABLED_DEBUG_LEVEL"
56#define OAT_SET_DEBUG_LEVEL "OAT_GET_DEBUG_LEVEL"
57
58const char *OAT_TAB = "Open Astro Tech";
59
61{
63 IUFillText(&MeadeCommandT, OAT_MEADE_COMMAND, "Result / Command", "");
64 IUFillTextVector(&MeadeCommandTP, &MeadeCommandT, 1, getDeviceName(), "Meade", "", OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
65
66 // Set focuser capabilities
69
70 // Initialize focuser properties
72
73 // Set custom ranges for focuser properties
74 FocusSpeedNP[0].setMinMax(0.0, 4.0);
75 FocusSpeedNP[0].setStep(1.0);
76 FocusSpeedNP[0].setValue(2.0);
77
78 FocusTimerNP[0].setMinMax(0.0, 5000.0);
79 FocusTimerNP[0].setStep(50.0);
80 FocusTimerNP[0].setValue(1000.0);
81 lastTimerValue = 1000.0;
82
83 FocusAbsPosNP[0].setMinMax(0.0, 100000.0);
84 FocusAbsPosNP[0].setStep(100.0);
85 FocusAbsPosNP[0].setValue(0);
86
87 FocusRelPosNP[0].setMinMax(0.0, 100000.0);
88 FocusRelPosNP[0].setStep(100.0);
89 FocusRelPosNP[0].setValue(0);
90
91 FocusSyncNP[0].setMinMax(0.0, 100000.0);
92 FocusSyncNP[0].setStep(1000.0);
93 FocusSyncNP[0].setValue(0);
94
95 FocusMaxPosNP[0].setMinMax(1000.0, 100000.0);
96 FocusMaxPosNP[0].setStep(10000.0);
97 FocusMaxPosNP[0].setValue(50000.0);
98
99 FocusBacklashNP[0].setMinMax(0, 5000.0);
100 FocusBacklashNP[0].setStep(100);
101 FocusBacklashNP[0].setValue(0);
102
103 // Polar Align Alt
104 IUFillNumber(&PolarAlignAltN, "OAT_POLAR_ALT", "Arcmin", "%.f", -140.0, 140.0, 1.0, 0);
105 IUFillNumberVector(&PolarAlignAltNP, &PolarAlignAltN, 1, getDeviceName(), "POLAR_ALT",
106 "Polar Align Alt",
107 MOTION_TAB, IP_RW, 60, IPS_OK);
108 // Polar Align Az
109 IUFillNumber(&PolarAlignAzN, "OAT_POLAR_AZ", "Arcmin", "%.f", -320.0, 320.0, 1.0, 0);
110 IUFillNumberVector(&PolarAlignAzNP, &PolarAlignAzN, 1, getDeviceName(), "POLAR_AZ",
111 "Polar Align Azimuth",
112 MOTION_TAB, IP_RW, 60, IPS_OK);
113
114 // Home
115 // IUFillSwitch(&HomeS, "OAT_HOME", "Home", ISS_OFF);
116 // IUFillSwitchVector(&HomeSP, &HomeS, 1, getDeviceName(),
117 // "OAT_HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
118
119 // RA Home
120 IUFillNumber(&RAHomeN, "RA_HOME", "Hours", "%d", 1.0, 7.0, 1.0, 2);
121 IUFillNumberVector(&RAHomeNP, &RAHomeN, 1, getDeviceName(),
122 "OAT_RA_HOME", "RA Home", MOTION_TAB, IP_RW, 60, IPS_IDLE);
123
124 // RA Home
125 IUFillNumber(&RAHomeOffsetN, "OAT_RA_HOME_OFFSET", "Steps", "%d", -10000.0, 10000.0, 100.0, 0);
126 IUFillNumberVector(&RAHomeOffsetNP, &RAHomeOffsetN, 1, getDeviceName(),
127 "OAT_RA_HOME", "RA Home Offset", MOTION_TAB, IP_RW, 60, IPS_IDLE);
128
129 // DEC Limits
130 IUFillNumber(&DecLimitsN[0], "OAT_DEC_LIMIT_LOWER", "Lower", "%.f", 0.0, -50.0, 0.0, 0);
131 IUFillNumber(&DecLimitsN[1], "OAT_DEC_LIMIT_UPPER", "Upper", "%.f", 0.0, 180.0, 120.0, 0);
132 IUFillNumberVector(&DecLimitsNP, DecLimitsN, 2, getDeviceName(), "OAT_DEC_LIMITS",
133 "DEC Limits", MOTION_TAB, IP_RW, 60, IPS_OK);
134 // SetParkDataType(PARK_RA_DEC);
135 return true;
136}
137
139{
141
142 if (isConnected())
143 {
144 defineProperty(&MeadeCommandTP);
145 defineProperty(&PolarAlignAltNP);
146 defineProperty(&PolarAlignAzNP);
147 // defineProperty(&HeaterNP);
148 //defineProperty(&HomeSP);
149 defineProperty(&RAHomeNP);
150 defineProperty(&RAHomeOffsetNP);
151 defineProperty(&DecLimitsNP);
152 }
153 else
154 {
155 deleteProperty(MeadeCommandTP.name);
156 deleteProperty(PolarAlignAltNP.name);
157 deleteProperty(PolarAlignAzNP.name);
158 // deleteProperty(HeaterNP.name);
159 //deleteProperty(HomeSP.name);
160 deleteProperty(RAHomeNP.name);
161 deleteProperty(RAHomeOffsetNP.name);
162 deleteProperty(DecLimitsNP.name);
163 }
164
165 return true;
166}
167
169{
170 if (!isConnected())
171 return false;
172
173 if (isSimulation()) //if Simulation is selected
174 {
175 mountSim();
176 return true;
177 }
178
179 if(OATUpdateProperties() != 0)
180 {
181
182 }
183 if (OATUpdateFocuser() != 0) // Update Focuser Position
184 {
185 LOG_WARN("Communication error on Focuser Update, this update aborted, will try again...");
186 }
188}
189
190int LX200_OpenAstroTech::OATUpdateProperties()
191{
192 // we don't need to poll if we're not moving
193 if(!(
194 PolarAlignAltNP.s == IPS_BUSY || PolarAlignAzNP.s == IPS_BUSY
195 || RAHomeNP.s == IPS_BUSY
196 ))
197 {
198 return 0;
199 }
200
201 tcflush(PortFD, TCIOFLUSH);
202 flushIO(PortFD);
203
204 char value[RB_MAX_LEN] = {0};
205 int rc = executeMeadeCommand(":GX#", value);
206 if (rc == 0 && strlen(value) > 10)
207 {
208 const char *motors = strchr(value, ',') + 1;
209 if(PolarAlignAzNP.s == IPS_BUSY && motors[3] == '-')
210 {
211 PolarAlignAzNP.s = IPS_OK;
212 IDSetNumber(&PolarAlignAzNP, nullptr);
213 }
214 if(PolarAlignAltNP.s == IPS_BUSY && motors[4] == '-')
215 {
216 PolarAlignAltNP.s = IPS_OK;
217 IDSetNumber(&PolarAlignAltNP, nullptr);
218 }
219 if(RAHomeNP.s == IPS_BUSY && value[0] == 'H')
220 {
221 RAHomeNP.s = IPS_IDLE;
222 IDSetNumber(&RAHomeNP, nullptr);
223 }
224 }
225 // updateProperties();
226 return 0;
227}
228
229bool LX200_OpenAstroTech::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
230{
231 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
232 {
233 if (!strcmp(name, MeadeCommandTP.name))
234 {
235 if(!isSimulation())
236 {
237 // we're using the "Set" field for the command and the actual field for the result
238 // we need to:
239 // - get the value
240 // - check if it's a command
241 // - if so, execute it, then set the result to the control
242 // the client side needs to
243 // - push ":somecmd#"
244 // - listen to change on MeadeCommand and log it
245 char * cmd = texts[0];
246 size_t len = strlen(cmd);
247 DEBUGFDEVICE(getDeviceName(), DBG_SCOPE, "Meade Command <%s>", cmd);
248 if(len > 2)
249 {
250 IText *tp = IUFindText(&MeadeCommandTP, names[0]);
251 MeadeCommandResult[0] = 0;
252 int err = 0;
253 if(cmd[0] == ':' && cmd[len - 1] == '#')
254 {
255 err = executeMeadeCommand(cmd, MeadeCommandResult);
256 }
257 else if(cmd[0] == '@' && cmd[len - 1] == '#')
258 {
259 cmd[0] = ':';
260 err = executeMeadeCommandBlind(cmd);
261 }
262 else if(cmd[0] == '&' && cmd[len - 1] == '#')
263 {
264 cmd[0] = ':';
265 int val = getCommandChar(PortFD, cmd);
266 if(val != -1)
267 {
268 sprintf(MeadeCommandResult, "%c", val);
269 }
270 }
271 DEBUGFDEVICE(getDeviceName(), DBG_SCOPE, "Meade Command Result %d <%s>", err, MeadeCommandResult);
272 if(err == 0)
273 {
274 MeadeCommandTP.s = IPS_OK;
275 }
276 else
277 {
278 MeadeCommandTP.s = IPS_ALERT;
279 }
280 IUSaveText(tp, MeadeCommandResult);
281 IDSetText(&MeadeCommandTP, "%s", MeadeCommandResult);
282 return true;
283 }
284 }
285 }
286 }
287
288 return INDI::Telescope::ISNewText(dev, name, texts, names, n);
289}
290
291bool LX200_OpenAstroTech::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
292{
293 if (strcmp(dev, getDeviceName()) == 0)
294 {
295 char read_buffer[RB_MAX_LEN] = {0};
296 if (!strcmp(name, PolarAlignAltN.name) || !strcmp(name, PolarAlignAltNP.name))
297 {
298 /*if (IUUpdateNumber(&PolarAlignAltNP, values, names, n) < 0)
299 return false;
300 */
301 LOGF_WARN("Moving Polar Alt to %.3f", values[0]);
302 snprintf(read_buffer, sizeof(read_buffer), ":MAL%.3f#", values[0]);
303 executeMeadeCommandBlind(read_buffer);
304 PolarActive = true;
305 PolarAlignAltNP.s = IPS_BUSY;
306 IDSetNumber(&PolarAlignAltNP, nullptr);
307 return true;
308 }
309 if (!strcmp(name, PolarAlignAzN.name) || !strcmp(name, PolarAlignAzNP.name))
310 {
311 /*if (IUUpdateNumber(&PolarAlignAzNP, values, names, n) < 0)
312 return false;
313 */
314 LOGF_WARN("Moving Polar Az to %.3f", values[0]);
315 snprintf(read_buffer, sizeof(read_buffer), ":MAZ%.3f#", values[0]);
316 executeMeadeCommandBlind(read_buffer);
317 PolarActive = true;
318 PolarAlignAzNP.s = IPS_BUSY;
319 IDSetNumber(&PolarAlignAzNP, nullptr);
320 return true;
321 }
322 }
323
324 return LX200GPS::ISNewNumber(dev, name, values, names, n);
325}
326
327// bool LX200_OpenAstroTech::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
328// {
329// if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
330// {
331// if (!strcmp(name, HomeS.name))
332// {
333// HomeSP.s = IPS_OK;
334// IUResetSwitch(&HomeSP);
335// /*int targetState = */IUFindOnSwitchIndex(&HomeSP);
336// IDSetSwitch(&HomeSP, nullptr);
337// return executeMeadeCommandBlind(":hF#");
338// }
339// }
340// return LX200GPS::ISNewSwitch(dev, name, states, names, n);
341// }
342
344{
345 return "LX200 OpenAstroTech";
346}
347
348int LX200_OpenAstroTech::executeMeadeCommand(const char *cmd, char *data)
349{
350 bool wait = true, getchar = false;
351 int len = strlen(cmd);
352 data[0] = 0;
353 if(len > 2)
354 {
355 if(cmd[1] == 'F') // Fx except for Fp
356 {
357 if(!(cmd[2] == 'p' || cmd[2] == 'B'))
358 {
359 wait = false;
360 }
361 else if(cmd[2] == 'B')
362 {
363 getchar = true;
364 }
365 }
366 else if(cmd[1] == 'M' && cmd[2] == 'A') // MAL, MAZ
367 {
368 wait = false;
369 }
370 else if(cmd[1] == 'M' && (cmd[2] == 'X' || cmd[2] == 'T')) // MXxnnnnn#
371 {
372 getchar = true;
373 }
374 else if(cmd[1] == 'M' && (cmd[2] == 'g' || cmd[2] == 'G')) // Mgnxxxx#
375 {
376 wait = false;
377 }
378 else if(cmd[1] == 'S' && cmd[2] != 'C') // SCMM/DD/YY#
379 {
380 getchar = true;
381 }
382 else if(cmd[1] == 'X' && cmd[2] == 'S') // :XSRn.n# :XSDn.n# :XS...
383 {
384 wait = false;
385 }
386 }
387 if(!wait)
388 {
389 return executeMeadeCommandBlind(cmd);
390 }
391 int err = 0;
392 if(getchar)
393 {
394 int val = getCommandChar(PortFD, cmd);
395 if(0 < val)
396 {
397 sprintf(data, "%c", val);
398 }
399 else if(0 == val)
400 {
401 sprintf(data, "%s", "null");
402 }
403 else
404 {
405 err = val;
406 }
407 }
408 else
409 {
410 err = getCommandString(PortFD, data, cmd);
411 }
412 if(err)
413 {
414 LOGF_WARN("Executed Meade Command error: %d %s -> '%s'", err, cmd, data);
415 }
416 else
417 {
418 LOGF_INFO("Executed Meade Command: %d %s -> '%s'", wait, cmd, data);
419 }
420 return err;
421}
422
423// stupid meade protocol... why not just always add a # after a result??
424// now you have to know what each command will return
425char LX200_OpenAstroTech::getCommandChar(int fd, const char * cmd)
426{
427 char read_buffer[RB_MAX_LEN] = {0};
428 int nbytes_write = 0, nbytes_read = 0, error_type;
429
430 /* Add mutex */
431 std::unique_lock<std::mutex> guard(lx200CommsLock);
432
433 //LOGF_INFO("getCommandChar 1: %s -> '%s'", cmd, read_buffer);
434 if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) == TTY_OK)
435 {
436 error_type = tty_read(fd, read_buffer, 1, 5, &nbytes_read);
437 //LOGF_INFO("getCommandChar 2: %s -> '%s'", cmd, read_buffer);
438 if (nbytes_read == 1)
439 {
440 // LOGF_INFO("getCommandChar 3: %s -> '%s'", cmd, read_buffer);
441 return read_buffer[0];
442 }
443 }
444
445 LOGF_WARN("getCommandChar error: %d %s -> '%s'", error_type, cmd, read_buffer);
446 return -1;
447}
448
449bool LX200_OpenAstroTech::executeMeadeCommandBlind(const char *cmd)
450{
451 int error_type;
452 int nbytes_write = 0;
453
454 DEBUGF(DBG_SCOPE, "CMD <%s>", cmd);
455
456 flushIO(PortFD);
457 /* Add mutex */
458 std::unique_lock<std::mutex> guard(lx200CommsLock);
459 tcflush(PortFD, TCIFLUSH);
460
461 if ((error_type = tty_write_string(PortFD, cmd, &nbytes_write)) != TTY_OK)
462 {
463 LOGF_ERROR("CHECK CONNECTION: Error sending command %s", cmd);
464 return 1;
465 }
466 LOGF_INFO("Executed Meade Command Immediate: %s", cmd);
467 return 0;
468}
469
470int LX200_OpenAstroTech::flushIO(int fd)
471{
472 tcflush(fd, TCIOFLUSH);
473 int error_type = 0;
474 int nbytes_read;
475 std::unique_lock<std::mutex> guard(lx200CommsLock);
476 tcflush(fd, TCIOFLUSH);
477 do
478 {
479 char discard_data[RB_MAX_LEN] = {0};
480 error_type = tty_read_section_expanded(fd, discard_data, '#', 0, 1000, &nbytes_read);
481 if (error_type >= 0)
482 {
483 LOGF_DEBUG("flushIO: Information in buffer: Bytes: %u, string: %s", nbytes_read, discard_data);
484 }
485 //LOGF_DEBUG("flushIO: error_type = %i", error_type);
486 }
487 while (error_type > 0);
488 return 0;
489}
490
492{
493 int reversed = (FocusReverseSP.findOnSwitchIndex() == INDI_ENABLED) ? -1 : 1;
494 INDI_UNUSED(speed);
495 // :FRsnnn# Set focuser target position relative (in microns)
496 // Returns: Nothing
497 LOGF_ERROR("MoveFocuser shouldn't be called: %d at %d for %d", dir, speed, duration);
498 double output;
499 char read_buffer[32];
500 output = duration;
501 if (dir != FocuserDirectionLast)
502 {
503 FocuserDirectionLast = dir;
504 LOGF_INFO("Applying backlash %d to %d", FocuserBacklash, output);
505 output += FocuserBacklash;
506 }
507 if (dir == FOCUS_INWARD) output = 0 - output;
508 snprintf(read_buffer, sizeof(read_buffer), ":FM%f#", output * reversed);
509 executeMeadeCommandBlind(read_buffer);
510 return IPS_BUSY; // Normal case, should be set to normal by update.
511}
512
514{
515 if (FocusAbsPosNP[0].getMax() >= int(targetTicks) && FocusAbsPosNP[0].getMin() <= int(targetTicks))
516 {
517 char read_buffer[32];
518 snprintf(read_buffer, sizeof(read_buffer), ":Fp#");
519 if(!executeMeadeCommand(read_buffer, read_buffer))
520 {
521 uint32_t currentTicks = atoi(read_buffer);
522 if(FocuserDirectionLast == FOCUS_INWARD && targetTicks > currentTicks)
523 {
524 targetTicks += FocuserBacklash;
525 FocuserDirectionLast = FOCUS_OUTWARD;
526 }
527 else if(FocuserDirectionLast == FOCUS_OUTWARD && targetTicks < currentTicks)
528 {
529 targetTicks -= FocuserBacklash;
530 FocuserDirectionLast = FOCUS_INWARD;
531 }
532 uint32_t relTicks = targetTicks - currentTicks;
533
534 char read_buffer[32];
535 snprintf(read_buffer, sizeof(read_buffer), ":FM%d#", int(relTicks));
536 executeMeadeCommandBlind(read_buffer);
537 return IPS_BUSY; // Normal case, should be set to normal by update.
538 }
539 return IPS_ALERT;
540 }
541 else
542 {
543 LOG_INFO("Unable to move focuser, out of range");
544 return IPS_ALERT;
545 }
546}
547
549{
550 int reversed = (FocusReverseSP.findOnSwitchIndex() == INDI_ENABLED) ? -1 : 1;
551 // :FMsnnn# Set focuser target position relative (in microns)
552 // Returns: Nothing
553 char read_buffer[64];
554 if (dir != FocuserDirectionLast)
555 {
556 FocuserDirectionLast = dir;
557 LOGF_INFO("Applying backlash %d to %d", FocuserBacklash, ticks);
558 ticks += FocuserBacklash;
559 }
560 int output = ticks;
561 if (dir == FOCUS_INWARD) output = 0 - ticks;
562 snprintf(read_buffer, sizeof(read_buffer), ":FM%d#", output * reversed);
563 executeMeadeCommandBlind(read_buffer);
564 return IPS_BUSY; // Normal case, should be set to normal by update.
565}
566
568{
569
570 LOGF_INFO("Set backlash %d", steps);
571 FocuserBacklash = steps;
572 return true;
573}
574
576{
577 // :FQ# Stop the focuser
578 // Returns: Nothing
579 char cmd[CMD_MAX_LEN] = {0};
580 strncpy(cmd, ":FQ#", sizeof(cmd));
581 executeMeadeCommandBlind(cmd);
582 return IPS_OK;
583}
584
586{
587 // :FPnnn#
588 // Description:
589 // Set position
590 // Information:
591 // Sets the current position of the focus stepper motor
592 // Returns:
593 // "1"
594 char cmd[CMD_MAX_LEN] = {0};
595 snprintf(cmd, sizeof(cmd), ":FP%d#", int(ticks));
596 int val = getCommandChar(PortFD, cmd);
597 return val == '1';
598}
599
600// initFocuserProperties function removed as we're using FocuserInterface properties
601
602int LX200_OpenAstroTech::OATUpdateFocuser()
603{
604 // we don't need to poll if we're not moving
605 if(!(FocusRelPosNP.getState() == IPS_BUSY || FocusAbsPosNP.getState() == IPS_BUSY) && FocusAbsPosNP[0].getValue() != 0.0)
606 {
607 return 0;
608 }
609
610 tcflush(PortFD, TCIOFLUSH);
611 flushIO(PortFD);
612 // get position
613 char value[RB_MAX_LEN] = {0};
614 if (!getCommandString(PortFD, value, ":Fp#"))
615 {
616 FocusAbsPosNP[0].setValue(atof(value));
617 FocusSyncNP[0].setValue(atof(value));
620 // LOGF_INFO("Current focuser: %f", FocusAbsPosNP[0].getValue());
621 }
622 // get is_moving
623 char valueStatus = getCommandChar(PortFD, ":FB#");
624 if (valueStatus == '0')
625 {
630 }
631 else if (valueStatus == '1')
632 {
637 }
638 else
639 {
640 LOGF_WARN("Communication :FB# error, check connection: %d", valueStatus);
641 //INVALID REPLY
646 }
648 LOGF_DEBUG("After update properties: FocusAbsPosN min: %f max: %f", FocusAbsPosNP[0].getMin(), FocusAbsPosNP[0].getMax());
649 return 0;
650}
651
652
654{
655 char value[RB_MAX_LEN] = "";
656 int rc = executeMeadeCommand(enabled ? ":MT1#" : ":MT0#", value);
657 LOGF_INFO("Set Tracking to %d: %d/'%s'", (int)enabled, rc, value);
658 return rc == 0 && value[0] == '1';
659}
660
665{
666 switch (action)
667 {
668 case HOME_GO:
669 return executeMeadeCommandBlind(":hF#") ? IPS_BUSY : IPS_ALERT;
670
671 default:
672 return IPS_ALERT;
673 }
674}
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)
bool isSimulation() const
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSyncNP
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusTimerNP
void initProperties(const char *groupName)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusBacklashNP
INDI::PropertyNumber FocusAbsPosNP
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
bool updateProperties()
Called when connected state changes, to add/remove properties.
Definition lx200gps.cpp:125
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
Definition lx200gps.cpp:400
bool initProperties()
Called to initialize basic properties required all the time.
Definition lx200gps.cpp:41
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual const char * getDefaultName(void) override
IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual IPState ExecuteHomeAction(TelescopeHomeAction action) override
Execute a homing action.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
@ IP_RW
Definition indiapi.h:184
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
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
int tty_read_section_expanded(int fd, char *buf, char stop_char, long timeout_seconds, long timeout_microseconds, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:658
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition indidevapi.c:265
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
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:509
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition indidevapi.c:44
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition indidevapi.c:416
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
#define INDI_UNUSED(x)
Definition indidevapi.h:132
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_WARN(fmt,...)
Definition indilogger.h:81
#define LOG_WARN(txt)
Definition indilogger.h:73
#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 DEBUGFDEVICE(device, priority, msg,...)
Definition indilogger.h:61
#define DEBUGF(priority, msg,...)
Definition indilogger.h:57
#define getDeviceName
int fd
#define RB_MAX_LEN
std::mutex lx200CommsLock
#define OAT_MEADE_COMMAND
const char * OAT_TAB
#define MINOR_VERSION
#define MAJOR_VERSION
std::mutex lx200CommsLock
unsigned int DBG_SCOPE
int getCommandString(int fd, char *data, const char *cmd)
uint8_t cmd[4]
Definition pwc-ioctl.h:2
#define currentTicks
Definition robofocus.cpp:38
One text descriptor.
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:248
#define CMD_MAX_LEN