Instrument Neutral Distributed Interface INDI 2.2.5
nstep.cpp
Go to the documentation of this file.
1/*
2 NStep Focuser
3
4 Copyright(c) 2019 Jasem Mutlaq. All rights reserved.
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20
21#include "nstep.h"
22
23#include "indicom.h"
24
25#include <cstring>
26#include <termios.h>
27#include <memory>
28#include <thread>
29#include <chrono>
30
31static std::unique_ptr<NStep> nstep(new NStep());
32
42
44{
46
47 // Focuser temperature
48 IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -100, 100, 0, 0);
49 IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
51
52 // Compensation Modes
53 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_OFF], "COMPENSATION_MODE_OFF", "Off", ISS_ON);
54 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_ONE_SHOT], "COMPENSATION_MODE_ONE_SHOT", "One shot", ISS_OFF);
55 IUFillSwitch(&CompensationModeS[COMPENSATION_MODE_AUTO], "COMPENSATION_MODE_AUTO", "Auto", ISS_OFF);
56 IUFillSwitchVector(&CompensationModeSP, CompensationModeS, 3, getDeviceName(), "COMPENSATION_MODE", "Mode",
57 COMPENSATION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_OK);
58
59 // Prime for Manual
60 IUFillSwitch(&PrimeManualS[0], "MANUAL_MODE_PRIME", "Prime Manual Mode", ISS_OFF);
61 IUFillSwitchVector(&PrimeManualSP, PrimeManualS, 1, getDeviceName(), "COMPENSATION_PRIME", "Prime",
62 COMPENSATION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_OK);
63
64 // Compensation Settings
65 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_CHANGE], "COMPENSATION_SETTING_CHANGE", "Delta T. (C)", "%.1f",
66 -99, 99, 0.1, 0);
67 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_STEP], "COMPENSATION_SETTING_STEP", "Steps per Delta", "%.0f", 0,
68 999, 1, 0);
69 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_BACKLASH], "COMPENSATION_SETTING_BACKLASH", "Backlash steps",
70 "%.0f", 0, 999, 1, 0);
71 IUFillNumber(&CompensationSettingsN[COMPENSATION_SETTING_TIMER], "COMPENSATION_SETTING_TIMER", "Averaged Time (s)", "%.0f",
72 0, 75, 1, 0);
73 IUFillNumberVector(&CompensationSettingsNP, CompensationSettingsN, 4, getDeviceName(), "COMPENSATION_SETTING", "Settings",
74 COMPENSATION_TAB, IP_RW, 0, IPS_OK);
75
76 // Stepping Modes
77 IUFillSwitch(&SteppingModeS[STEPPING_WAVE], "STEPPING_WAVE", "Wave", ISS_OFF);
78 IUFillSwitch(&SteppingModeS[STEPPING_HALF], "STEPPING_HALF", "Half", ISS_OFF);
79 IUFillSwitch(&SteppingModeS[STEPPING_FULL], "STEPPING_FULL", "Full", ISS_ON);
80 IUFillSwitchVector(&SteppingModeSP, SteppingModeS, 3, getDeviceName(), "STEPPING_MODE", "Mode",
81 STEPPING_TAB, IP_RW, ISR_1OFMANY, 0, IPS_OK);
82
83 // Stepping Phase
84 IUFillNumber(&SteppingPhaseN[0], "PHASES", "Wiring", "%.f", 0, 2, 1, 0);
85 IUFillNumberVector(&SteppingPhaseNP, SteppingPhaseN, 1, getDeviceName(), "STEPPING_PHASE", "Phase",
86 STEPPING_TAB, IP_RW, 0, IPS_OK);
87
88 // Max Speed
89 IUFillNumber(&MaxSpeedN[0], "RATE", "Rate", "%.f", 1, 254, 10, 0);
90 IUFillNumberVector(&MaxSpeedNP, MaxSpeedN, 1, getDeviceName(), "MAX_SPEED", "Max Speed",
92
93 // Coil Energized Status
94 IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_OFF], "COIL_ENERGIZED_OFF", "De-energized", ISS_OFF);
95 IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_ON], "COIL_ENERGIZED_ON", "Energized", ISS_OFF);
96 IUFillSwitchVector(&CoilStatusSP, CoilStatusS, 2, getDeviceName(), "COIL_MODE", "Coil After Move",
98
100
101 // Set limits as per documentation
102 FocusAbsPosNP[0].setMin(0);
103 FocusAbsPosNP[0].setMax(999999);
104 FocusAbsPosNP[0].setStep(1000);
105
106 FocusRelPosNP[0].setMin(0);
107 FocusRelPosNP[0].setMax(999);
108 FocusRelPosNP[0].setStep(100);
109
110 FocusSpeedNP[0].setMin(1);
111 FocusSpeedNP[0].setMax(254);
112 FocusSpeedNP[0].setStep(10);
113
114 return true;
115}
116
118{
119 return "Rigel NStep";
120}
121
123{
124 if (isConnected())
125 {
126 // Read these values before defining focuser interface properties
127 readPosition();
128 readSpeedInfo();
129 }
130
132
133 if (isConnected())
134 {
135 if (readTemperature())
136 defineProperty(&TemperatureNP);
137
138 bool rc = getStartupValues();
139
140 // Settings
141 defineProperty(&MaxSpeedNP);
142 defineProperty(&CompensationModeSP);
143 defineProperty(&PrimeManualSP);
144 defineProperty(&CompensationSettingsNP);
145 defineProperty(&SteppingModeSP);
146 defineProperty(&SteppingPhaseNP);
147 defineProperty(&CoilStatusSP);
148
149 if (rc)
150 LOG_INFO("NStep is ready.");
151 else
152 LOG_WARN("Failed to query startup values.");
153 }
154 else
155 {
156 if (TemperatureNP.s == IPS_OK)
157 deleteProperty(TemperatureNP.name);
158
159 deleteProperty(MaxSpeedNP.name);
160 deleteProperty(CompensationModeSP.name);
161 deleteProperty(PrimeManualSP.name);
162 deleteProperty(CompensationSettingsNP.name);
163 deleteProperty(SteppingModeSP.name);
164 deleteProperty(SteppingPhaseNP.name);
165 deleteProperty(CoilStatusSP.name);
166 }
167
168 return true;
169}
170
172{
173 char cmd[NSTEP_LEN] = {0}, res[NSTEP_LEN] = {0};
174
175 // Ack
176 cmd[0] = 0x6;
177
178 bool rc = sendCommand(cmd, res, 1, 1);
179 if (rc == false)
180 return false;
181
182 return res[0] == 'S';
183}
184
185bool NStep::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
186{
187 int nbytes_written = 0, nbytes_read = 0, rc = -1;
188
189 tcflush(PortFD, TCIOFLUSH);
190
191 if (cmd_len > 0)
192 {
193 char hex_cmd[NSTEP_LEN * 3] = {0};
194 hexDump(hex_cmd, cmd, cmd_len);
195 LOGF_DEBUG("CMD <%s>", hex_cmd);
196 rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
197 }
198 else
199 {
200 LOGF_DEBUG("CMD <%s>", cmd);
201 rc = tty_write_string(PortFD, cmd, &nbytes_written);
202 }
203
204 if (rc != TTY_OK)
205 {
206 char errstr[MAXRBUF] = {0};
207 tty_error_msg(rc, errstr, MAXRBUF);
208 LOGF_ERROR("Serial write error: %s.", errstr);
209 return false;
210 }
211
212 if (res == nullptr)
213 return true;
214
215 if (res_len > 0)
216 rc = tty_read(PortFD, res, res_len, NSTEP_TIMEOUT, &nbytes_read);
217 else
218 rc = tty_nread_section(PortFD, res, NSTEP_LEN, NSTEP_STOP_CHAR, NSTEP_TIMEOUT, &nbytes_read);
219
220 if (rc != TTY_OK)
221 {
222 char errstr[MAXRBUF] = {0};
223 tty_error_msg(rc, errstr, MAXRBUF);
224 LOGF_ERROR("Serial read error: %s.", errstr);
225 return false;
226 }
227
228 if (res_len > 0)
229 {
230 char hex_res[NSTEP_LEN * 3] = {0};
231 hexDump(hex_res, res, res_len);
232 LOGF_DEBUG("RES <%s>", hex_res);
233 }
234 else
235 {
236 LOGF_DEBUG("RES <%s>", res);
237 }
238
239 tcflush(PortFD, TCIOFLUSH);
240
241 return true;
242}
243
244void NStep::hexDump(char * buf, const char * data, int size)
245{
246 for (int i = 0; i < size; i++)
247 sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
248
249 if (size > 0)
250 buf[3 * size - 1] = '\0';
251}
252
253bool NStep::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
254{
255 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
256 {
257 // Compensation Settings
258 if (!strcmp(name, CompensationSettingsNP.name))
259 {
260 // Extract values
261 int change = 0, step = 0, backlash = 0, timer = 0;
262 for (int i = 0; i < n; i++)
263 {
264 if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_CHANGE].name))
265 {
266 change = values[i];
267 }
268 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_STEP].name))
269 {
270 step = values[i];
271 }
272 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_BACKLASH].name))
273 {
274 backlash = values[i];
275 }
276 else if (!strcmp(names[i], CompensationSettingsN[COMPENSATION_SETTING_TIMER].name))
277 {
278 timer = values[i];
279 }
280 }
281
282 // Try to update settings
283 if (setCompensationSettings(change, step, backlash, timer))
284 {
285 IUUpdateNumber(&CompensationSettingsNP, values, names, n);
286 CompensationSettingsNP.s = IPS_OK;
287 }
288 else
289 {
290 CompensationSettingsNP.s = IPS_ALERT;
291 }
292
293 IDSetNumber(&CompensationSettingsNP, nullptr);
294 return true;
295 }
296
297
298 // Stepping Phase
299 if (!strcmp(name, SteppingPhaseNP.name))
300 {
301 if (setSteppingPhase(static_cast<uint8_t>(values[0])))
302 {
303 IUUpdateNumber(&SteppingPhaseNP, values, names, n);
304 SteppingPhaseNP.s = IPS_OK;
305 }
306 else
307 SteppingPhaseNP.s = IPS_ALERT;
308
309 IDSetNumber(&SteppingPhaseNP, nullptr);
310 return true;
311 }
312
313 // Max Speed
314 if (!strcmp(name, MaxSpeedNP.name))
315 {
316 if (setMaxSpeed(static_cast<uint8_t>(values[0])))
317 {
318 IUUpdateNumber(&MaxSpeedNP, values, names, n);
319 MaxSpeedNP.s = IPS_OK;
320
321 // We must update the Min/Max of focus speed
322 FocusSpeedNP[0].setMax(values[0]);
324 }
325 else
326 {
327 MaxSpeedNP.s = IPS_ALERT;
328 }
329
330 IDSetNumber(&MaxSpeedNP, nullptr);
331 return true;
332 }
333 }
334
335 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
336}
337
338bool NStep::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
339{
340 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
341 {
342 // Temperature Compensation Mode
343 if (!strcmp(name, CompensationModeSP.name))
344 {
345 int prevIndex = IUFindOnSwitchIndex(&CompensationModeSP);
346 IUUpdateSwitch(&CompensationModeSP, states, names, n);
347 int mode = IUFindOnSwitchIndex(&CompensationModeSP);
348 if (setCompensationMode(mode))
349 {
350 CompensationModeSP.s = IPS_OK;
351 // If it was set to one shot, we put it back to off?
352 switch (mode)
353 {
354 case COMPENSATION_MODE_OFF:
355 LOG_INFO("Temperature compensation is disabled.");
356 break;
357
358 case COMPENSATION_MODE_ONE_SHOT:
359 IUResetSwitch(&CompensationModeSP);
360 CompensationModeS[COMPENSATION_MODE_OFF].s = ISS_ON;
361 LOG_INFO("One shot compensation applied.");
362 break;
363
364 case COMPENSATION_MODE_AUTO:
365 LOG_INFO("Automatic temperature compensation is enabled.");
366 break;
367 }
368 }
369 else
370 {
371 IUResetSwitch(&CompensationModeSP);
372 CompensationModeS[prevIndex].s = ISS_ON;
373 CompensationModeSP.s = IPS_ALERT;
374 LOG_ERROR("Failed to change temperature compensation mode.");
375 }
376
377 IDSetSwitch(&CompensationModeSP, nullptr);
378 return true;
379 }
380
381 // Manual Prime
382 if (!strcmp(name, PrimeManualSP.name))
383 {
384 sendCommand(":TI");
385 PrimeManualSP.s = IPS_OK;
386 IDSetSwitch(&PrimeManualSP, nullptr);
387 LOG_INFO("Prime for manual complete. Click One Shot to apply manual compensation once.");
388 return true;
389 }
390
391 // Stepping Mode
392 if (!strcmp(name, SteppingModeSP.name))
393 {
394 IUUpdateSwitch(&SteppingModeSP, states, names, n);
395 SteppingModeSP.s = IPS_OK;
396 IDSetSwitch(&SteppingModeSP, nullptr);
397 return true;
398 }
399
400 // Coil Status after Move is done
401 if (!strcmp(name, CoilStatusSP.name))
402 {
403 int prevIndex = IUFindOnSwitchIndex(&CoilStatusSP);
404 IUUpdateSwitch(&CoilStatusSP, states, names, n);
405 int state = IUFindOnSwitchIndex(&CoilStatusSP);
406 if (setCoilStatus(state))
407 {
408 CoilStatusSP.s = IPS_OK;
409 if (state == COIL_ENERGIZED_ON)
410 LOG_WARN("Coil shall be kept energized after motion is complete. Watch for motor heating!");
411 else
412 LOG_INFO("Coil shall be de-energized after motion is complete.");
413 }
414 else
415 {
416 IUResetSwitch(&CoilStatusSP);
417 CoilStatusS[prevIndex].s = ISS_ON;
418 CoilStatusSP.s = IPS_ALERT;
419 LOG_ERROR("Failed to update coil energization status.");
420 }
421
422 IDSetSwitch(&CoilStatusSP, nullptr);
423 return true;
424 }
425 }
426
427 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
428}
429
430bool NStep::getStartupValues()
431{
432 bool rc1 = readCoilStatus();
433 bool rc2 = readSteppingInfo();
434 bool rc3 = readCompensationInfo();
435
436 return (rc1 && rc2 && rc3);
437}
438
439IPState NStep::MoveAbsFocuser(uint32_t targetTicks)
440{
441 m_TargetDiff = targetTicks - FocusAbsPosNP[0].getValue();
442 return IPS_BUSY;
443}
444
446{
447 m_TargetDiff = ticks * ((dir == FOCUS_INWARD) ? -1 : 1);
448 return MoveAbsFocuser(FocusAbsPosNP[0].getValue() + m_TargetDiff);
449}
450
452{
453 return sendCommand("F00000#");
454}
455
457{
458 if (isConnected() == false)
459 return;
460
461 double currentPosition = FocusAbsPosNP[0].getValue();
462
463 readPosition();
464
465 // Check if we have a pending motion
466 // and if we STOPPED, then let's take the next action
467 if ( (FocusAbsPosNP.getState() == IPS_BUSY || FocusRelPosNP.getState() == IPS_BUSY) && isMoving() == false)
468 {
469 // Are we done moving?
470 if (m_TargetDiff == 0)
471 {
476 }
477 else
478 {
479 // 999 is the max we can go in one command
480 // so we need to go 999 or LESS
481 // therefore for larger movements, we break it down.
482 int nextMotion = (std::abs(m_TargetDiff) > 999) ? 999 : std::abs(m_TargetDiff);
483 int direction = m_TargetDiff > 0 ? FOCUS_OUTWARD : FOCUS_INWARD;
484 int mode = IUFindOnSwitchIndex(&SteppingModeSP);
485 char cmd[NSTEP_LEN] = {0};
486 snprintf(cmd, NSTEP_LEN, ":F%d%d%03d#", direction, mode, nextMotion);
487 if (sendCommand(cmd) == false)
488 {
489 LOG_ERROR("Failed to issue motion command.");
491 {
494 }
496 {
499 }
500 }
501 else
502 // Reduce target diff depending on the motion direction
503 // Negative targetDiff increases eventually to zero
504 // Positive targetDiff decreases eventually to zero
505 m_TargetDiff = m_TargetDiff + (nextMotion * ((direction == FOCUS_INWARD) ? 1 : -1));
506 }
507 // Check if can update the absolute position in case it changed.
508 }
509 else if (currentPosition != FocusAbsPosNP[0].getValue())
510 {
512 }
513
514 // Read temperature
515 if (TemperatureNP.s == IPS_OK && m_TemperatureCounter++ == NSTEP_TEMPERATURE_FREQ)
516 {
517 m_TemperatureCounter = 0;
518 if (readTemperature())
519 IDSetNumber(&TemperatureNP, nullptr);
520 }
521
523}
524
525bool NStep::isMoving()
526{
527 char res[NSTEP_LEN] = {0};
528
529 bool rc = sendCommand("S", res, 1, 1);
530
531 if (rc && res[0] == '1')
532 return true;
533
534 return false;
535}
536
537bool NStep::readTemperature()
538{
539 char res[NSTEP_LEN] = {0};
540
541 if (sendCommand(":RT", res, 3, 4) == false)
542 return false;
543
544 float temperature = -1000;
545 sscanf(res, "%f", &temperature);
546
547 // Divide by 10 to get actual value
548 temperature /= 10.0;
549
550 if (temperature < -80)
551 return false;
552
553 TemperatureN[0].value = temperature;
554 TemperatureNP.s = IPS_OK;
555
556 return true;
557}
558
559bool NStep::readPosition()
560{
561 char res[NSTEP_LEN] = {0};
562
563 if (sendCommand(":RP", res, 3, 7) == false)
564 return false;
565
566 int32_t pos = 1e6;
567 sscanf(res, "%d", &pos);
568
569 if (pos == 1e6)
570 return false;
571
572 FocusAbsPosNP[0].setValue(pos);
573
574 return true;
575}
576
577bool NStep::readCompensationInfo()
578{
579 char res[NSTEP_LEN] = {0};
580 int32_t change = 1e6, step = 1e6, state = 1e6, backlash = 1e6, timer = 1e6;
581
582 // State (Off, One shot, or Auto)
583 if (sendCommand(":RG", res, 3, 1) == false)
584 {
585 std::this_thread::sleep_for(std::chrono::milliseconds(250));
586 if (sendCommand(":RG", res, 3, 1) == false)
587 return false;
588 }
589 sscanf(res, "%d", &state);
590 if (state == 1e6)
591 return false;
592 IUResetSwitch(&CompensationModeSP);
593 CompensationModeS[state].s = ISS_ON;
594 CompensationModeSP.s = IPS_OK;
595
596 // Change
597 memset(res, 0, NSTEP_LEN);
598 if (sendCommand(":RA", res, 3, 4) == false)
599 {
600 std::this_thread::sleep_for(std::chrono::milliseconds(250));
601 if (sendCommand(":RA", res, 3, 4) == false)
602 return false;
603 }
604 sscanf(res, "%d", &change);
605 if (change == 1e6)
606 return false;
607 CompensationSettingsN[COMPENSATION_SETTING_CHANGE].value = change;
608
609 // Step
610 memset(res, 0, NSTEP_LEN);
611 if (sendCommand(":RB", res, 3, 3) == false)
612 {
613 std::this_thread::sleep_for(std::chrono::milliseconds(250));
614 if (sendCommand(":RB", res, 3, 3) == false)
615 return false;
616 }
617 sscanf(res, "%d", &step);
618 if (step == 1e6)
619 return false;
620 CompensationSettingsN[COMPENSATION_SETTING_STEP].value = step;
621
622 // Backlash
623 memset(res, 0, NSTEP_LEN);
624 if (sendCommand(":RE", res, 3, 3) == false)
625 {
626 std::this_thread::sleep_for(std::chrono::milliseconds(250));
627 if (sendCommand(":RE", res, 3, 3) == false)
628 return false;
629 }
630 sscanf(res, "%d", &backlash);
631 if (backlash == 1e6)
632 return false;
633 CompensationSettingsN[COMPENSATION_SETTING_BACKLASH].value = backlash;
634
635 // Timer
636 memset(res, 0, NSTEP_LEN);
637 if (sendCommand(":RH", res, 3, 2) == false)
638 {
639 std::this_thread::sleep_for(std::chrono::milliseconds(250));
640 if (sendCommand(":RH", res, 3, 2) == false)
641 return false;
642 }
643 sscanf(res, "%d", &timer);
644 if (timer == 1e6)
645 return false;
646 CompensationSettingsN[COMPENSATION_SETTING_TIMER].value = timer;
647 CompensationSettingsNP.s = IPS_OK;
648
649 return true;
650
651}
652
653bool NStep::readSpeedInfo()
654{
655 char res[NSTEP_LEN] = {0};
656 int32_t max_step = 1e6, current_step = 1e6;
657
658 // Max Step
659 if (sendCommand(":RS", res, 3, 3) == false)
660 return false;
661 sscanf(res, "%d", &max_step);
662 if (max_step == 1e6)
663 return false;
664
665 // Current Step
666 if (sendCommand(":RO", res, 3, 3) == false)
667 return false;
668 sscanf(res, "%d", &current_step);
669 if (current_step == 1e6)
670 return false;
671
672 MaxSpeedN[0].value = 254 - max_step + 1;
673 MaxSpeedNP.s = IPS_OK;
674
675 // nStep defines speed step rates from 1 to 254
676 // when 1 being the fastest, so for speed we flip the values
677 FocusSpeedNP[0].setMax(254 - max_step + 1);
678 FocusSpeedNP[0].setValue(254 - current_step + 1);
680
681 return true;
682}
683
684bool NStep::readSteppingInfo()
685{
686 char res[NSTEP_LEN] = {0};
687
688 if (sendCommand(":RW", res, 3, 1) == false)
689 return false;
690
691 int32_t phase = 1e6;
692 sscanf(res, "%d", &phase);
693
694 if (phase == 1e6)
695 return false;
696
697 SteppingPhaseN[0].value = phase;
698 SteppingPhaseNP.s = IPS_OK;
699
700 return true;
701}
702
703bool NStep::readCoilStatus()
704{
705 char res[NSTEP_LEN] = {0};
706
707 if (sendCommand(":RC", res, 3, 1) == false)
708 return false;
709
710 IUResetSwitch(&CoilStatusSP);
711
712 CoilStatusS[COIL_ENERGIZED_OFF].s = (res[0] == '0') ? ISS_ON : ISS_OFF;
713 CoilStatusS[COIL_ENERGIZED_ON].s = (res[0] == '0') ? ISS_OFF : ISS_ON;
714 CoilStatusSP.s = IPS_OK;
715
716 return true;
717}
718
719bool NStep::SyncFocuser(uint32_t ticks)
720{
721 char cmd[NSTEP_LEN] = {0};
722 snprintf(cmd, NSTEP_LEN, "#:CP+%06d#", ticks);
723 return sendCommand(cmd);
724}
725
727{
728 // Speed and Current NStep steps are opposite.
729 // Speed 1 is slowest, translated to 254 for nStep.
730 char cmd[NSTEP_LEN] = {0};
731 snprintf(cmd, NSTEP_LEN, "#:CO%03d#", 254 - speed + 1);
732 return sendCommand(cmd);
733}
734
735bool NStep::setMaxSpeed(uint8_t maxSpeed)
736{
737 // INDI Focus Speed and Current NStep steps are opposite.
738 // INDI Speed 1 is slowest, translated to 254 for nStep.
739 // and vice versa
740 char cmd[NSTEP_LEN] = {0};
741 snprintf(cmd, NSTEP_LEN, ":CS%03d#", 254 - maxSpeed + 1);
742 return sendCommand(cmd);
743}
744
745bool NStep::setCompensationMode(uint8_t mode)
746{
747 char cmd[NSTEP_LEN] = {0};
748 snprintf(cmd, NSTEP_LEN, "#:TA%01d#", mode);
749 return sendCommand(cmd);
750}
751
752bool NStep::setCompensationSettings(double change, double move, double backlash, double timer)
753{
754 int temperature_change = change * 10;
755 char cmd[NSTEP_LEN] = {0};
756 snprintf(cmd, NSTEP_LEN, ":TT%+03d#", temperature_change);
757 bool rc1 = sendCommand(cmd);
758
759 int temperature_steps = static_cast<int>(move);
760 snprintf(cmd, NSTEP_LEN, ":TS%03d#", temperature_steps);
761 bool rc2 = sendCommand(cmd);
762
763 int temperature_backlash = static_cast<int>(backlash);
764 snprintf(cmd, NSTEP_LEN, ":TB%03d#", temperature_backlash);
765 bool rc3 = sendCommand(cmd);
766
767
768 int temperature_timer = static_cast<int>(timer);
769 bool rc4 = true;
770 if (timer > 0)
771 {
772 snprintf(cmd, NSTEP_LEN, ":TC%02d#", temperature_timer);
773 rc4 = sendCommand(cmd);
774 }
775
776 return (rc1 && rc2 && rc3 && rc4);
777}
778
779bool NStep::setSteppingPhase(uint8_t phase)
780{
781 char cmd[NSTEP_LEN] = {0};
782 snprintf(cmd, NSTEP_LEN, "#:CW%01d#", phase);
783 return sendCommand(cmd);
784}
785
786bool NStep::setCoilStatus(uint8_t status)
787{
788 char cmd[NSTEP_LEN] = {0};
789 snprintf(cmd, NSTEP_LEN, "#:CC%01d#", status == COIL_ENERGIZED_OFF ? 1 : 0);
790 return sendCommand(cmd);
791}
792
794{
796
797 IUSaveConfigNumber(fp, &CompensationSettingsNP);
798 IUSaveConfigSwitch(fp, &CompensationModeSP);
799 IUSaveConfigSwitch(fp, &SteppingModeSP);
800
801 return true;
802}
double temperature
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.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSpeedNP
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 saveConfigItems(FILE *fp) override
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 bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
Definition nstep.h:29
NStep()
Definition nstep.cpp:33
bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition nstep.cpp:43
bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
Definition nstep.cpp:726
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition nstep.cpp:439
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition nstep.cpp:456
bool saveConfigItems(FILE *fp) override
Definition nstep.cpp:793
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition nstep.cpp:445
bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
Definition nstep.cpp:122
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
Definition nstep.cpp:253
const char * getDefaultName() override
Definition nstep.cpp:117
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
Definition nstep.cpp:171
bool AbortFocuser() override
AbortFocuser all focus motion.
Definition nstep.cpp:451
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 nstep.cpp:338
bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition nstep.cpp:719
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 IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
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 IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
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
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOG_WARN(txt)
Definition indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#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