Instrument Neutral Distributed Interface INDI 2.2.5
sestosenso.cpp
Go to the documentation of this file.
1/*
2 SestoSenso Focuser
3 Copyright (C) 2018 Jasem Mutlaq ([email protected])
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 Commands and responses:
20
21 Only use the SM/Sm commands during calibration. Will cause direction reversal!
22 #Sm;xxxxxxx! Set xxxxxxx as min value
23 #SM! Set current position as max
24 #SM;xxxxxxx! Set xxxxxxx as max value (xxxxxxx between 0 to 2097152)
25
26 #SPxxxx! Set_current_position as xxxx
27 #SC;HOLD;RUN;ACC;DEC! Shell_set_current_supply in HOLD, RUN, ACC, DEC situations (Value must be from 0 to 24, maximum hold value 10)
28 #QM! Query max value
29 #Qm! Query min value
30 #QT! Query temperature
31 #QF! Query firmware version
32 #QN! Read the device name -> reply QN;SESTOSENSO!
33 #QP! Query_position
34 #FI! Fast_inward
35 #FO! Fast_outward
36 #SI! Slow_inward
37 #SO! Slow_outward
38 #GTxxxx! Go_to absolute position xxxx
39 #MA! Motion_abort and hold position
40 #MF! Motor free
41 #PS! param_save save current position for next power ON and currents supply
42 #PD! param_to_default , and position to zero
43
44 Response examples:
45
46 #QF! 14.06\r
47 #QT! -10.34\r
48 #FI! FIok!\r
49 #FO! FOok!\r
50 #SI! SIok!\r
51 #SO! SOok!\r
52 #GTxxxx! 100\r 200\r 300\r xxxx\r GTok!\r
53 #MA! MAok!\r
54 #MF! MFok!\r
55 #QP! 1530\r
56 #SPxxxx! SPok!\r
57 #SC;HOLD;RUN;ACC;DEC! SCok!\r
58 #PS! PSok!\r
59 #PD! PDok!\r
60
61 Before to disconnect the COM port, send the #PS! command in order to save the position on internal memory
62
63*/
64
65#include "sestosenso.h"
66
67#include "indicom.h"
68
69#include <cmath>
70#include <cstring>
71#include <memory>
72
73#include <termios.h>
74#include <unistd.h>
75
76static std::unique_ptr<SestoSenso> sesto(new SestoSenso());
77
79{
80 setVersion(1, 4);
81 // Can move in Absolute & Relative motions, can AbortFocuser motion.
83}
84
86{
88
89 // Firmware Information
90 IUFillText(&FirmwareT[0], "VERSION", "Version", "");
91 IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "FOCUS_FIRMWARE", "Firmware", MAIN_CONTROL_TAB, IP_RO, 0,
92 IPS_IDLE);
93
94 // Focuser temperature
95 IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
96 IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB,
97 IP_RO, 0, IPS_IDLE);
98
99 // Focuser calibration
100 IUFillText(&CalibrationMessageT[0], "CALIBRATION", "Calibration stage", "");
101 IUFillTextVector(&CalibrationMessageTP, CalibrationMessageT, 1, getDeviceName(), "CALIBRATION_MESSAGE", "Calibration",
103
104 IUFillSwitch(&CalibrationS[CALIBRATION_START], "CALIBRATION_START", "Start", ISS_OFF);
105 IUFillSwitch(&CalibrationS[CALIBRATION_NEXT], "CALIBRATION_NEXT", "Next", ISS_OFF);
106 IUFillSwitchVector(&CalibrationSP, CalibrationS, 2, getDeviceName(), "FOCUS_CALIBRATION", "Calibration", MAIN_CONTROL_TAB,
108
109 IUFillSwitch(&FastMoveS[FASTMOVE_IN], "FASTMOVE_IN", "Move In", ISS_OFF);
110 IUFillSwitch(&FastMoveS[FASTMOVE_OUT], "FASTMOVE_OUT", "Move out", ISS_OFF);
111 IUFillSwitch(&FastMoveS[FASTMOVE_STOP], "FASTMOVE_STOP", "Stop", ISS_OFF);
112 IUFillSwitchVector(&FastMoveSP, FastMoveS, 3, getDeviceName(), "FAST_MOVE", "Calibration Move", MAIN_CONTROL_TAB, IP_RW,
114
115 //
116 // Override the default Max. Position to make it Read-Only
117 FocusMaxPosNP.fill(getDeviceName(), "FOCUS_MAX", "Max. Position", MAIN_CONTROL_TAB, IP_RO,
118 0, IPS_IDLE);
119
120 // Relative and absolute movement
121 FocusRelPosNP[0].setMin(0.);
122 FocusRelPosNP[0].setMax(50000.);
123 FocusRelPosNP[0].setValue(0);
124 FocusRelPosNP[0].setStep(1000);
125
126 FocusAbsPosNP[0].setMin(0.);
127 FocusAbsPosNP[0].setMax(2097152.);
128 FocusAbsPosNP[0].setValue(0);
129 FocusAbsPosNP[0].setStep(1000);
130
131 FocusMaxPosNP[0].setValue(2097152);
132
134
136
137 m_MotionProgressTimer.callOnTimeout(std::bind(&SestoSenso::checkMotionProgressCallback, this));
138 m_MotionProgressTimer.setSingleShot(true);
139
140 return true;
141}
142
144{
146
147 if (isConnected())
148 {
149 // Only define temperature if there is a probe
150 if (updateTemperature())
151 defineProperty(&TemperatureNP);
152 defineProperty(&FirmwareTP);
153 IUSaveText(&CalibrationMessageT[0], "Press START to begin the Calibration");
154 defineProperty(&CalibrationMessageTP);
155 defineProperty(&CalibrationSP);
156
157 if (getStartupValues())
158 LOG_INFO("SestoSenso parameters updated, focuser ready for use.");
159 else
160 LOG_WARN("Failed to inquire parameters. Check logs.");
161 }
162 else
163 {
164 if (TemperatureNP.s == IPS_OK)
165 deleteProperty(TemperatureNP.name);
166 deleteProperty(FirmwareTP.name);
167 deleteProperty(CalibrationMessageTP.name);
168 deleteProperty(CalibrationSP.name);
169 }
170
171 return true;
172}
173
175{
176 if (Ack())
177 {
178 LOG_INFO("SestoSenso is online. Getting focus parameters...");
179 return true;
180 }
181
182 LOG_INFO(
183 "Error retrieving data from SestoSenso, please ensure SestoSenso controller is powered and the port is correct.");
184 return false;
185}
186
188{
189 // Save current position to memory.
190 if (isSimulation() == false)
191 sendCommand("#PS!");
192
194}
195
197{
198 return "Sesto Senso";
199}
200
201bool SestoSenso::Ack()
202{
203 char res[SESTO_LEN] = {0};
204
205 if (isSimulation())
206 strncpy(res, "1.0 Simulation", SESTO_LEN);
207 else if (sendCommand("#QF!", res) == false)
208 return false;
209
210 IUSaveText(&FirmwareT[0], res);
211
212 return true;
213}
214
215bool SestoSenso::updateTemperature()
216{
217 char res[SESTO_LEN] = {0};
218 double temperature = 0;
219
220 if (isSimulation())
221 strncpy(res, "23.45", SESTO_LEN);
222 else if (sendCommand("#QT!", res) == false)
223 return false;
224
225 try
226 {
227 temperature = std::stod(res);
228 }
229 catch(...)
230 {
231 LOGF_WARN("Failed to process temperature response: %s (%d bytes)", res, strlen(res));
232 return false;
233 }
234
235 if (temperature > 90)
236 return false;
237
238 TemperatureN[0].value = temperature;
239 TemperatureNP.s = IPS_OK;
240
241 return true;
242}
243
244bool SestoSenso::updateMaxLimit()
245{
246 char res[SESTO_LEN] = {0};
247
248 if (isSimulation())
249 return true;
250
251 if (sendCommand("#QM!", res) == false)
252 return false;
253
254 int maxLimit = 0;
255
256 sscanf(res, "QM;%d!", &maxLimit);
257
258 if (maxLimit > 0)
259 {
260 FocusMaxPosNP[0].setMax(maxLimit);
261 if (FocusMaxPosNP[0].getValue() > maxLimit)
262 FocusMaxPosNP[0].setValue(maxLimit);
263
264 FocusAbsPosNP[0].setMin(0);
265 FocusAbsPosNP[0].setMax(maxLimit);
266 FocusAbsPosNP[0].setValue(0);
267 FocusAbsPosNP[0].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
268
269 FocusRelPosNP[0].setMin(0.);
270 FocusRelPosNP[0].setMax(FocusAbsPosNP[0].getStep() * 10);
271 FocusRelPosNP[0].setValue(0);
272 FocusRelPosNP[0].setStep(FocusAbsPosNP[0].getStep());
273
276
279 return true;
280 }
281
283 return false;
284}
285
286bool SestoSenso::updatePosition()
287{
288 char res[SESTO_LEN] = {0};
289 if (isSimulation())
290 snprintf(res, SESTO_LEN, "%d", static_cast<uint32_t>(FocusAbsPosNP[0].getValue()));
291 else if (sendCommand("#QP!", res) == false)
292 return false;
293
294 try
295 {
296 FocusAbsPosNP[0].setValue(std::stoi(res));
298 return true;
299 }
300 catch(...)
301 {
302 LOGF_WARN("Failed to process position response: %s (%d bytes)", res, strlen(res));
304 return false;
305 }
306}
307
308bool SestoSenso::isMotionComplete()
309{
310 char res[SESTO_LEN] = {0};
311
312 if (isSimulation())
313 {
314 int32_t nextPos = FocusAbsPosNP[0].getValue();
315 int32_t targPos = static_cast<int32_t>(targetPos);
316
317 if (targPos > nextPos)
318 nextPos += 250;
319 else if (targPos < nextPos)
320 nextPos -= 250;
321
322 if (abs(nextPos - targPos) < 250)
323 nextPos = targetPos;
324 else if (nextPos < 0)
325 nextPos = 0;
326 else if (nextPos > FocusAbsPosNP[0].getMax())
327 nextPos = FocusAbsPosNP[0].getMax();
328
329 snprintf(res, SESTO_LEN, "%d", nextPos);
330 }
331 else
332 {
333 int nbytes_read = 0;
334
335 //while (rc != TTY_TIME_OUT)
336 //{
337 int rc = tty_read_section(PortFD, res, SESTO_STOP_CHAR, 1, &nbytes_read);
338 if (rc == TTY_OK)
339 {
340 res[nbytes_read - 1] = 0;
341
342
343 if (!strcmp(res, "GTok!"))
344 return true;
345
346 try
347 {
348 uint32_t newPos = std::stoi(res);
349 FocusAbsPosNP[0].setValue(newPos);
350 }
351 catch (...)
352 {
353 LOGF_WARN("Failed to process motion response: %s (%d bytes)", res, strlen(res));
354 }
355 }
356 //}
357 }
358
359 return false;
360}
361
362bool SestoSenso::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
363{
364 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
365 {
366
367 // Calibrate focuser
368 if (!strcmp(name, CalibrationSP.name))
369 {
370 char res[SESTO_LEN] = {0};
371 int current_switch = 0;
372
373 CalibrationSP.s = IPS_BUSY;
374 //IDSetSwitch(&CalibrationSP, nullptr);
375 IUUpdateSwitch(&CalibrationSP, states, names, n);
376
377 current_switch = IUFindOnSwitchIndex(&CalibrationSP);
378 CalibrationS[current_switch].s = ISS_ON;
379 IDSetSwitch(&CalibrationSP, nullptr);
380
381 if (current_switch == CALIBRATION_START)
382 {
383 if (cStage == Idle || cStage == Complete )
384 {
385 // Start the calibration process
386 LOG_INFO("Start Calibration");
387 CalibrationSP.s = IPS_BUSY;
388 IDSetSwitch(&CalibrationSP, nullptr);
389
390 //
391 // Unlock the motor to allow manual movement of the focuser
392 //
393 if (sendCommand("#MF!") == false)
394 return false;
395
396 IUSaveText(&CalibrationMessageT[0], "Move focuser manually to the middle then press NEXT");
397 IDSetText(&CalibrationMessageTP, nullptr);
398
399 // Set next step
400 cStage = GoToMiddle;
401 }
402 else
403 {
404 LOG_INFO("Already started calibration. Proceed to next step.");
405 IUSaveText(&CalibrationMessageT[0], "Already started. Proceed to NEXT.");
406 IDSetText(&CalibrationMessageTP, nullptr);
407 }
408 }
409 else if (current_switch == CALIBRATION_NEXT)
410 {
411 if (cStage == GoToMiddle)
412 {
413 defineProperty(&FastMoveSP);
414 IUSaveText(&CalibrationMessageT[0], "Move In/Move Out/Stop to MIN position then press NEXT");
415 IDSetText(&CalibrationMessageTP, nullptr);
416 cStage = GoMinimum;
417 }
418 else if (cStage == GoMinimum)
419 {
420 // Minimum position needs setting
421 if (sendCommand("#Sm;0!") == false)
422 return false;
423
424 IUSaveText(&CalibrationMessageT[0], "Move In/Move Out/Stop to MAX position then press NEXT");
425 IDSetText(&CalibrationMessageTP, nullptr);
426 cStage = GoMaximum;
427 }
428 else if (cStage == GoMaximum)
429 {
430 // Maximum position needs setting and save
431 // Do not split these commands.
432
433 if (sendCommand("#SM!", res) == false)
434 return false;
435 if (sendCommand("#PS!") == false)
436 return false;
437 //
438 // MAX value is in maxLimit
439 // MIN value is 0
440 //
441 int maxLimit = 0;
442 sscanf(res, "SM;%d!", &maxLimit);
443 LOGF_INFO("MAX setting is %d", maxLimit);
444
445 FocusMaxPosNP[0].setMax(maxLimit);
446 FocusMaxPosNP[0].setValue(maxLimit);
447
448 FocusAbsPosNP[0].setMin(0);
449 FocusAbsPosNP[0].setMax(maxLimit);
450 FocusAbsPosNP[0].setValue(maxLimit);
451 FocusAbsPosNP[0].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
452
453 FocusRelPosNP[0].setMin(0.);
454 FocusRelPosNP[0].setMax(FocusAbsPosNP[0].getStep() * 10);
455 FocusRelPosNP[0].setValue(0);
456 FocusRelPosNP[0].setStep(FocusAbsPosNP[0].getStep());
457
462
463 IUSaveText(&CalibrationMessageT[0], "Calibration Completed.");
464 IDSetText(&CalibrationMessageTP, nullptr);
465
466 deleteProperty(FastMoveSP.name);
467 cStage = Complete;
468
469 LOG_INFO("Calibration completed");
470 CalibrationSP.s = IPS_OK;
471 IDSetSwitch(&CalibrationSP, nullptr);
472 CalibrationS[current_switch].s = ISS_OFF;
473 IDSetSwitch(&CalibrationSP, nullptr);
474 }
475 else
476 {
477 IUSaveText(&CalibrationMessageT[0], "Calibration not in process");
478 IDSetText(&CalibrationMessageTP, nullptr);
479 }
480
481 }
482 return true;
483 }
484 else if (!strcmp(name, FastMoveSP.name))
485 {
486 IUUpdateSwitch(&FastMoveSP, states, names, n);
487 int current_switch = IUFindOnSwitchIndex(&FastMoveSP);
488
489 switch (current_switch)
490 {
491 case FASTMOVE_IN:
492 if (sendCommand("#FI!") == false)
493 {
494 return false;
495 }
496 break;
497 case FASTMOVE_OUT:
498 if (sendCommand("#FO!") == false)
499 {
500 return false;
501 }
502 break;
503 case FASTMOVE_STOP:
504 if (sendCommand("#MA!") == false)
505 {
506 return false;
507 }
508 break;
509 default:
510 break;
511 }
512
513 FastMoveSP.s = IPS_BUSY;
514 IDSetSwitch(&FastMoveSP, nullptr);
515 return true;
516 }
517
518 }
519 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
520}
521
523{
524 targetPos = targetTicks;
525
526 char cmd[SESTO_LEN] = {0};
527 snprintf(cmd, 16, "#GT%u!", targetTicks);
528 if (isSimulation() == false)
529 {
530 if (sendCommand(cmd) == false)
531 return IPS_ALERT;
532 }
533
534 m_MotionProgressTimer.start(10);
535 return IPS_BUSY;
536}
537
539{
540 int reversed = (FocusReverseSP.findOnSwitchIndex() == INDI_ENABLED) ? -1 : 1;
541 int relativeTicks = ((dir == FOCUS_INWARD) ? -ticks : ticks) * reversed;
542 double newPosition = FocusAbsPosNP[0].getValue() + relativeTicks;
543
544 bool rc = MoveAbsFocuser(newPosition);
545
546 return (rc ? IPS_BUSY : IPS_ALERT);
547}
548
550{
551 m_MotionProgressTimer.stop();
552
553 if (isSimulation())
554 return true;
555
556 return sendCommand("#MA!");
557}
558
559//
560// This timer function is initiated when a GT command has been issued
561// A timer will call this function on a regular interval during the motion
562// Modified the code to exit when motion is complete
563//
564void SestoSenso::checkMotionProgressCallback()
565{
566 if (isMotionComplete())
567 {
572 lastPos = FocusAbsPosNP[0].getValue();
573 LOG_INFO("Focuser reached requested position.");
574 return;
575 }
576 else
578
579 lastPos = FocusAbsPosNP[0].getValue();
580
581 m_MotionProgressTimer.start(250);
582}
583
585{
587 || CalibrationSP.s == IPS_BUSY)
588 {
590 return;
591 }
592
593 bool rc = updatePosition();
594 if (rc)
595 {
596 if (fabs(lastPos - FocusAbsPosNP[0].getValue()) > 0)
597 {
599 lastPos = FocusAbsPosNP[0].getValue();
600 }
601 }
602
603 if (m_TemperatureCounter++ == SESTO_TEMPERATURE_FREQ)
604 {
605 rc = updateTemperature();
606 if (rc)
607 {
608 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.1)
609 {
610 IDSetNumber(&TemperatureNP, nullptr);
611 lastTemperature = TemperatureN[0].value;
612 }
613 }
614 m_TemperatureCounter = 0; // Reset the counter
615 }
616
618}
619
620bool SestoSenso::getStartupValues()
621{
622 bool rc1 = updatePosition();
623 if (rc1)
625
626 if (updateMaxLimit() == false)
627 LOG_WARN("Check you have the latest SestoSenso firmware. Focuser requires calibration.");
628
629 return (rc1);
630}
631
632bool SestoSenso::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
633{
634 int nbytes_written = 0, nbytes_read = 0, rc = -1;
635
636 tcflush(PortFD, TCIOFLUSH);
637
638 if (cmd_len > 0)
639 {
640 char hex_cmd[SESTO_LEN * 3] = {0};
641 hexDump(hex_cmd, cmd, cmd_len);
642 LOGF_DEBUG("CMD <%s>", hex_cmd);
643 rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
644 }
645 else
646 {
647 LOGF_DEBUG("CMD <%s>", cmd);
648 rc = tty_write_string(PortFD, cmd, &nbytes_written);
649 }
650
651 if (rc != TTY_OK)
652 {
653 char errstr[MAXRBUF] = {0};
654 tty_error_msg(rc, errstr, MAXRBUF);
655 LOGF_ERROR("Serial write error: %s.", errstr);
656 return false;
657 }
658
659 if (res == nullptr)
660 return true;
661
662 if (res_len > 0)
663 rc = tty_read(PortFD, res, res_len, SESTO_TIMEOUT, &nbytes_read);
664 else
665 {
666 rc = tty_nread_section(PortFD, res, SESTO_LEN, SESTO_STOP_CHAR, SESTO_TIMEOUT, &nbytes_read);
667 res[nbytes_read - 1] = 0;
668 }
669
670 if (rc != TTY_OK)
671 {
672 char errstr[MAXRBUF] = {0};
673 tty_error_msg(rc, errstr, MAXRBUF);
674 LOGF_ERROR("Serial read error: %s.", errstr);
675 return false;
676 }
677
678 if (res_len > 0)
679 {
680 char hex_res[SESTO_LEN * 3] = {0};
681 hexDump(hex_res, res, res_len);
682 LOGF_DEBUG("RES <%s>", hex_res);
683 }
684 else
685 {
686 LOGF_DEBUG("RES <%s>", res);
687 }
688
689 tcflush(PortFD, TCIOFLUSH);
690
691 return true;
692}
693
694void SestoSenso::hexDump(char * buf, const char * data, int size)
695{
696 for (int i = 0; i < size; i++)
697 sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
698
699 if (size > 0)
700 buf[3 * size - 1] = '\0';
701}
702
704{
705 INDI_UNUSED(enable);
706 return false;
707}
double temperature
bool isConnected() const
virtual bool Disconnect()
Disconnect from device.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
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,...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void setSingleShot(bool singleShot)
Set whether the timer is a single-shot timer.
void callOnTimeout(const std::function< void()> &callback)
Definition inditimer.cpp:76
void start()
Starts or restarts the timer with the timeout specified in interval.
Definition inditimer.cpp:82
void stop()
Stops the timer.
Definition inditimer.cpp:97
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
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 ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
const char * getDefaultName() override
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool Disconnect() override
Disconnect from device.
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:653
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 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 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 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
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
#define INDI_UNUSED(x)
Definition indidevapi.h:132
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
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 getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248