Instrument Neutral Distributed Interface INDI  2.0.2
nframe.cpp
Go to the documentation of this file.
1 /*
2  nFrameRotator Rotator
3 
4  nFrame added by Gene N
5  Modified from indi_nstep_focuser
6 
7  Copyright(c) 2019 Jasem Mutlaq. All rights reserved.
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23 
24 #include "nframe.h"
25 
26 #include "indicom.h"
27 
28 #include <cstring>
29 #include <termios.h>
30 #include <memory>
31 #include <thread>
32 #include <chrono>
33 
34 static std::unique_ptr<nFrameRotator> rotator(new nFrameRotator());
35 
36 
38 {
39  setVersion(1, 2);
42  );
43 }
44 
46 {
48 
49 
50 
51  // Stepping Modes
52  IUFillSwitch(&SteppingModeS[STEPPING_WAVE], "STEPPING_WAVE", "Wave", ISS_OFF);
53  IUFillSwitch(&SteppingModeS[STEPPING_HALF], "STEPPING_HALF", "Half", ISS_OFF);
54  IUFillSwitch(&SteppingModeS[STEPPING_FULL], "STEPPING_FULL", "Full", ISS_ON);
55  IUFillSwitchVector(&SteppingModeSP, SteppingModeS, 3, getDeviceName(), "STEPPING_MODE", "Mode",
56  STEPPING_TAB, IP_RW, ISR_1OFMANY, 0, IPS_OK);
57 
58  // Stepping Phase
59  IUFillNumber(&SteppingPhaseN[0], "PHASES", "Wiring", "%.f", 0, 2, 1, 0);
60  IUFillNumberVector(&SteppingPhaseNP, SteppingPhaseN, 1, getDeviceName(), "STEPPING_PHASE", "Phase",
61  STEPPING_TAB, IP_RW, 0, IPS_OK);
62 
63 
64  IUFillNumber(&RotatorSpeedN[0], "ROTATE_SPEED_VALUE", "Step Rate", "%3.0f", 0.0, 255.0, 1.0, 255.0);
66  IPS_OK);
67 
68  // Max Speed
69  IUFillNumber(&MaxSpeedN[0], "RATE", "Rate", "%.f", 1, 254, 10, 0);
70  IUFillNumberVector(&MaxSpeedNP, MaxSpeedN, 1, getDeviceName(), "MAX_SPEED", "Max Speed", MAIN_CONTROL_TAB, IP_RW, 0,
71  IPS_OK);
72 
73  // Coil Energized Status
74  IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_OFF], "COIL_ENERGIZED_OFF", "De-energized", ISS_OFF);
75  IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_ON], "COIL_ENERGIZED_ON", "Energized", ISS_OFF);
76  // IUFillSwitch(&CoilStatusS[COIL_ENERGIZED_ON], "COIL_ENERGIZED_OFF", "Energized", ISS_OFF);
77  IUFillSwitchVector(&CoilStatusSP, CoilStatusS, 2, getDeviceName(), "COIL_MODE", "Coil After Move",
79  IUFillNumber(&SettingN[PARAM_STEPS_DEGREE], "PARAM_STEPS_DEGREE", "Steps/Degree", "%.2f", 1., 10000., 500., 1000.);
80  IUFillNumberVector(&SettingNP, SettingN, 1, getDeviceName(), "ROTATOR_SETTINGS", "Parameters", SETTINGS_TAB, IP_RW, 0,
81  IPS_OK);
82  // Rotator Ticks
83  IUFillNumber(&RotatorAbsPosN[0], "ROTATOR_ABSOLUTE_POSITION", "Value", "%.f", 0., 1000000., 0., 0.);
84  IUFillNumberVector(&RotatorAbsPosNP, RotatorAbsPosN, 1, getDeviceName(), "ABS_ROTATOR_POSITION", "Steps", MAIN_CONTROL_TAB,
85  IP_RW, 0, IPS_IDLE );
86 
87 
89 
90  // Set limits as per documentation
91  GotoRotatorN[0].min = 0;
92  GotoRotatorN[0].max = 999999;
93  GotoRotatorN[0].step = 1000;
94 
95  RotatorSpeedN[0].min = 1;
96  RotatorSpeedN[0].max = 254;
97  RotatorSpeedN[0].step = 10;
98 
99  return true;
100 }
101 
103 {
104  return "nFrameRotator";
105 }
106 
108 {
110 
111  if (isConnected())
112  {
113  // Read these values before defining focuser interface properties
114  defineProperty(&RotatorAbsPosNP);
115  defineProperty(&SettingNP);
118  loadConfig(true, SettingNP.name);
119  readPosition();
120  readSpeedInfo();
121  IDSetNumber(&RotatorAbsPosNP, nullptr);
122  IDSetNumber(&GotoRotatorNP, nullptr);
123 
124  loadConfig(true, PresetNP.name);
125 
126  bool rc = getStartupValues();
127 
128  // Settings
129  defineProperty(&MaxSpeedNP);
130  defineProperty(&SteppingModeSP);
131  defineProperty(&SteppingPhaseNP);
132  defineProperty(&CoilStatusSP);
133 
134  if (rc)
135  LOG_INFO("nFrameRotator is ready.");
136  else
137  LOG_WARN("Failed to query startup values.");
138  }
139  else
140  {
141 
142  deleteProperty(MaxSpeedNP.name);
143  deleteProperty(SteppingModeSP.name);
144  deleteProperty(SteppingPhaseNP.name);
145  deleteProperty(CoilStatusSP.name);
147  deleteProperty(RotatorAbsPosNP.name);
148  }
149 
150  return true;
151 }
152 
154 {
155  char cmd[NFRAME_LEN] = {0}, res[NFRAME_LEN] = {0};
156 
157  // Ack
158  cmd[0] = 0x6;
159 
160  bool rc = sendCommand(cmd, res, 1, 1);
161  if (rc == false)
162  return false;
163 
164  return res[0] == 'S';
165 }
166 
167 bool nFrameRotator::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
168 {
169  int nbytes_written = 0, nbytes_read = 0, rc = -1;
170 
171  tcflush(PortFD, TCIOFLUSH);
172 
173  if (cmd_len > 0)
174  {
175  char hex_cmd[NFRAME_LEN * 3] = {0};
176  hexDump(hex_cmd, cmd, cmd_len);
177  LOGF_DEBUG("CMD <%s>", hex_cmd);
178  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
179  }
180  else
181  {
182  LOGF_DEBUG("CMD <%s>", cmd);
183  rc = tty_write_string(PortFD, cmd, &nbytes_written);
184  }
185 
186  if (rc != TTY_OK)
187  {
188  char errstr[MAXRBUF] = {0};
189  tty_error_msg(rc, errstr, MAXRBUF);
190  LOGF_ERROR("Serial write error: %s.", errstr);
191  return false;
192  }
193 
194  if (res == nullptr)
195  return true;
196 
197  if (res_len > 0)
198  rc = tty_read(PortFD, res, res_len, NFRAME_TIMEOUT, &nbytes_read);
199  else
200  rc = tty_nread_section(PortFD, res, NFRAME_LEN, NFRAME_STOP_CHAR, NFRAME_TIMEOUT, &nbytes_read);
201 
202  if (rc != TTY_OK)
203  {
204  char errstr[MAXRBUF] = {0};
205  tty_error_msg(rc, errstr, MAXRBUF);
206  LOGF_ERROR("Serial read error: %s.", errstr);
207  return false;
208  }
209 
210  if (res_len > 0)
211  {
212  char hex_res[NFRAME_LEN * 3] = {0};
213  hexDump(hex_res, res, res_len);
214  LOGF_DEBUG("RES <%s>", hex_res);
215  }
216  else
217  {
218  LOGF_DEBUG("RES <%s>", res);
219  }
220 
221  tcflush(PortFD, TCIOFLUSH);
222 
223  return true;
224 }
225 
226 void nFrameRotator::hexDump(char * buf, const char * data, int size)
227 {
228  for (int i = 0; i < size; i++)
229  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
230 
231  if (size > 0)
232  buf[3 * size - 1] = '\0';
233 }
234 
235 bool nFrameRotator::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
236 {
237  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
238  {
239 
240  // Stepping Phase
241  if (!strcmp(name, SteppingPhaseNP.name))
242  {
243  if (setSteppingPhase(static_cast<uint8_t>(values[0])))
244  {
245  IUUpdateNumber(&SteppingPhaseNP, values, names, n);
246  SteppingPhaseNP.s = IPS_OK;
247  }
248  else
249  SteppingPhaseNP.s = IPS_ALERT;
250 
251  IDSetNumber(&SteppingPhaseNP, nullptr);
252  return true;
253  }
254 
255  // Current speed
256 
257  if (!strcmp(name, RotatorSpeedNP.name))
258  {
259  if (SetRotatorSpeed(static_cast<uint8_t>(values[0])))
260  {
261  IUUpdateNumber(&RotatorSpeedNP, values, names, n);
263  }
264  else
265  {
267  }
268 
269  IDSetNumber(&RotatorSpeedNP, nullptr);
270  return true;
271  }
272 
273  // Max Speed
274  if (!strcmp(name, MaxSpeedNP.name))
275  {
276  if (setMaxSpeed(static_cast<uint8_t>(values[0])))
277  {
278  IUUpdateNumber(&MaxSpeedNP, values, names, n);
279  MaxSpeedNP.s = IPS_OK;
280 
281  // We must update the Min/Max of focus speed
282  RotatorSpeedN[0].max = values[0];
284  }
285  else
286  {
287  MaxSpeedNP.s = IPS_ALERT;
288  }
289 
290  IDSetNumber(&MaxSpeedNP, nullptr);
291  return true;
292  }
293  if (!strcmp(name, SettingNP.name))
294  {
295  bool rc = true;
296  std::vector<double> prevValue(SettingNP.nnp);
297  for (uint8_t i = 0; i < SettingNP.nnp; i++)
298  prevValue[i] = SettingN[i].value;
299  IUUpdateNumber(&SettingNP, values, names, n);
300 
301 
302  if (SettingN[PARAM_STEPS_DEGREE].value != prevValue[PARAM_STEPS_DEGREE])
303  {
304  GotoRotatorN[0].value = calculateAngle(RotatorAbsPosN[0].value);
305  IDSetNumber(&GotoRotatorNP, nullptr);
306  }
307 
308  if (!rc)
309  {
310  for (uint8_t i = 0; i < SettingNP.nnp; i++)
311  SettingN[i].value = prevValue[i];
312  }
313 
314  SettingNP.s = rc ? IPS_OK : IPS_ALERT;
315  IDSetNumber(&SettingNP, nullptr);
316  return true;
317  }
318 
319  }
320 
321  return INDI::Rotator::ISNewNumber(dev, name, values, names, n);
322 }
323 
324 bool nFrameRotator::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
325 {
326  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
327  {
328 
329  // Stepping Mode
330  if (!strcmp(name, SteppingModeSP.name))
331  {
332  IUUpdateSwitch(&SteppingModeSP, states, names, n);
333  SteppingModeSP.s = IPS_OK;
334  IDSetSwitch(&SteppingModeSP, nullptr);
335  return true;
336  }
337 
338  // Coil Status after Move is done
339  if (!strcmp(name, CoilStatusSP.name))
340  {
341  int prevIndex = IUFindOnSwitchIndex(&CoilStatusSP);
342  LOGF_DEBUG("SETCOIL PINDEX=%d", prevIndex);
343  IUUpdateSwitch(&CoilStatusSP, states, names, n);
344  int state = IUFindOnSwitchIndex(&CoilStatusSP);
345  if (setCoilStatus(state))
346  {
347  CoilStatusSP.s = IPS_OK;
348  if (state == COIL_ENERGIZED_ON)
349  LOG_WARN("Coil shall be kept energized after motion is complete. Watch for motor heating!");
350  else
351  LOG_INFO("Coil shall be de-energized after motion is complete.");
352  }
353  else
354  {
355  IUResetSwitch(&CoilStatusSP);
356  CoilStatusS[prevIndex].s = ISS_ON;
357  CoilStatusSP.s = IPS_ALERT;
358  LOG_ERROR("Failed to update coil energization status.");
359  }
360 
361  IDSetSwitch(&CoilStatusSP, nullptr);
362  return true;
363  }
364  }
365 
366  return INDI::Rotator::ISNewSwitch(dev, name, states, names, n);
367 }
368 
369 bool nFrameRotator::getStartupValues()
370 {
371  bool rc1 = readCoilStatus();
372  bool rc2 = readSteppingInfo();
373 
374  return (rc1 && rc2 );
375 }
376 
378 {
379  requestedAngle = angle ;
380 
381  LOGF_DEBUG("Angle = <%f> Step/Deg=<%d>", angle, (int)SettingN[PARAM_STEPS_DEGREE].value);
382  // Find closest distance
383  double r = (angle > 180) ? 360 - angle : angle;
384  int sign = (angle >= 0 && angle <= 180) ? 1 : -1;
385  sign = 1;
386  r = angle;
387 
388  r *= sign;
390 
391  double newTarget = r * SettingN[PARAM_STEPS_DEGREE].value + m_ZeroPosition;
392  m_TargetDiff = (int)newTarget - (int)RotatorAbsPosN[0].value;
393  return IPS_BUSY;
394 }
395 
396 
398 {
399  if(m_TargetDiff > 0)
400  {
401  m_TargetDiff = 1;
402  wantAbort = true;
403  return false;
404  }
405  return true;
406 }
407 
409 {
410  if (isConnected() == false)
411  return;
412 
413  readPosition();
414 
415  // Check if we have a pending motion
416  // and if we STOPPED, then let's take the next action
417  if ( ((RotatorAbsPosNP.s == IPS_BUSY || GotoRotatorNP.s == IPS_BUSY) && isMoving() == false) || wantAbort == true)
418  {
419  LOGF_DEBUG("wantAbort = %d, diff = %d", wantAbort, m_TargetDiff);
420  // Are we done moving?
421  if (m_TargetDiff == 0)
422  {
423  RotatorAbsPosNP.s = IPS_OK;
425  LOGF_DEBUG("HIT reqAngle=%f diff=%d", requestedAngle, m_TargetDiff);
426  IDSetNumber(&RotatorAbsPosNP, nullptr);
427  wantAbort = false;
428  }
429  else
430  {
431  // 999 is the max we can go in one command
432  // so we need to go 999 or LESS
433  // therefore for larger movements, we break it down.
434  int nextMotion = (std::abs(m_TargetDiff) > 999) ? 999 : std::abs(m_TargetDiff);
435  int direction = m_TargetDiff > 0 ? ROTATE_OUTWARD : ROTATE_INWARD;
436  int mode = IUFindOnSwitchIndex(&SteppingModeSP);
437  char cmd[NFRAME_LEN] = {0};
438  snprintf(cmd, NFRAME_LEN, ":F%d%d%03d#", direction, mode, nextMotion);
439  if (sendCommand(cmd) == false)
440  {
441  LOG_ERROR("Failed to issue motion command.");
442  if (GotoRotatorNP.s == IPS_BUSY)
443  {
445  IDSetNumber(&GotoRotatorNP, nullptr);
446  }
447  if (RotatorAbsPosNP.s == IPS_BUSY)
448  {
449  RotatorAbsPosNP.s = IPS_ALERT;
450  IDSetNumber(&RotatorAbsPosNP, nullptr);
451  }
452  }
453  else
454  {
455  // Reduce target diff depending on the motion direction
456  // Negative targetDiff increases eventually to zero
457  // Positive targetDiff decreases eventually to zero
458  m_TargetDiff = m_TargetDiff + (nextMotion * ((direction == ROTATE_INWARD) ? 1 : -1));
459  }
460  }
461  // Check if can update the absolute position in case it changed.
462  }
463  if (m_TargetDiff == 0)
464  {
465  IDSetNumber(&RotatorAbsPosNP, nullptr);
466  }
467  IDSetNumber(&RotatorAbsPosNP, nullptr);
468  IDSetNumber(&GotoRotatorNP, nullptr);
469 
471 }
472 
473 bool nFrameRotator::isMoving()
474 {
475  char res[NFRAME_LEN] = {0};
476 
477  bool rc = sendCommand("S", res, 1, 1);
478 
479  if (rc && res[0] == '1')
480  return true;
481 
482  return false;
483 }
484 
485 
486 bool nFrameRotator::readPosition()
487 {
488  char res[NFRAME_LEN] = {0};
489 
490  if (sendCommand(":RP", res, 3, 7) == false)
491  return false;
492 
493  int32_t pos = 1e6;
494  sscanf(res, "%d", &pos);
495 
496  if (pos == 1e6)
497  return false;
498  // LOGF_DEBUG("readPosFBPNB=< %d >", pos);
499 
500  RotatorAbsPosN[0].value = pos;
501  // if(m_TargetDiff != 0)
502  GotoRotatorN[0].value = calculateAngle(RotatorAbsPosN[0].value );
503  IDSetNumber(&RotatorAbsPosNP, nullptr);
504  IDSetNumber(&GotoRotatorNP, nullptr);
505 
506  return true;
507 }
508 
509 
510 bool nFrameRotator::readSpeedInfo()
511 {
512  char res[NFRAME_LEN] = {0};
513  int32_t max_step = 1e6, current_step = 1e6;
514 
515  // Max Step
516  if (sendCommand(":RS", res, 3, 3) == false)
517  return false;
518  sscanf(res, "%d", &max_step);
519  if (max_step == 1e6)
520  return false;
521 
522  // Current Step
523  if (sendCommand(":RO", res, 3, 3) == false)
524  return false;
525  sscanf(res, "%d", &current_step);
526  if (current_step == 1e6)
527  return false;
528 
529  MaxSpeedN[0].value = 254 - max_step + 1;
530  MaxSpeedNP.s = IPS_OK;
531 
532  // nStep defines speed step rates from 1 to 254
533  // when 1 being the fastest, so for speed we flip the values
534  RotatorSpeedN[0].max = 254 - max_step + 1;
535  RotatorSpeedN[0].value = 254 - current_step + 1;
536  IDSetNumber(&RotatorSpeedNP, nullptr);
538  LOGF_DEBUG("Speed= %f cs=%d", RotatorSpeedN[0].value, current_step);
539 
540  return true;
541 }
542 
543 bool nFrameRotator::readSteppingInfo()
544 {
545  char res[NFRAME_LEN] = {0};
546 
547  if (sendCommand(":RW", res, 3, 1) == false)
548  return false;
549 
550  int32_t phase = 1e6;
551  sscanf(res, "%d", &phase);
552 
553  if (phase == 1e6)
554  return false;
555 
556  SteppingPhaseN[0].value = phase;
557  SteppingPhaseNP.s = IPS_OK;
558 
559  return true;
560 }
561 
562 bool nFrameRotator::readCoilStatus()
563 {
564  char res[NFRAME_LEN] = {0};
565 
566  if (sendCommand(":RC", res, 3, 1) == false)
567  return false;
568 
569  IUResetSwitch(&CoilStatusSP);
570  LOGF_DEBUG("Coil status = %c", res[0]);
571 
572  CoilStatusS[COIL_ENERGIZED_OFF].s = (res[0] == '0') ? ISS_OFF : ISS_ON;
573  CoilStatusS[COIL_ENERGIZED_ON].s = (res[0] == '0') ? ISS_ON : ISS_OFF;
574  CoilStatusSP.s = IPS_OK;
575 
576  return true;
577 }
578 
579 bool nFrameRotator::SyncRotator(double angle)
580 {
581  // double min = range360(SettingN[PARAM_MIN_LIMIT].value);
582  // double max = range360(SettingN[PARAM_MAX_LIMIT].value);
583  // Clamp to range
584  // angle = std::max(min, std::min(max, angle));
585 
586  // Find closest distance
587  double r = (angle > 180) ? 360 - angle : angle;
588  int sign = (angle >= 0 && angle <= 180) ? 1 : -1;
589 
590  r *= sign;
592  double newTarget = r * SettingN[PARAM_STEPS_DEGREE].value + m_ZeroPosition;
593 
594  char cmd[NFRAME_LEN] = {0};
595  snprintf(cmd, NFRAME_LEN, "#:CP+%06d#", (int)newTarget);
596  return sendCommand(cmd);
597 }
598 
600 {
601  // Speed and Current nFrameRotator steps are opposite.
602  // Speed 1 is slowest, translated to 254 for nStep.
603  char cmd[NFRAME_LEN] = {0};
604  snprintf(cmd, NFRAME_LEN, "#:CO%03d#", 254 - speed + 1);
605  return sendCommand(cmd);
606 }
607 
608 bool nFrameRotator::setMaxSpeed(uint8_t maxSpeed)
609 {
610  // INDI Rotate Speed and Current nFrameRotator steps are opposite.
611  // INDI Speed 1 is slowest, translated to 254 for nFrame.
612  // and vice versa
613  char cmd[NFRAME_LEN] = {0};
614  snprintf(cmd, NFRAME_LEN, ":CS%03d#", 254 - maxSpeed + 1);
615  return sendCommand(cmd);
616 }
617 
618 
619 
620 bool nFrameRotator::setSteppingPhase(uint8_t phase)
621 {
622  char cmd[NFRAME_LEN] = {0};
623  snprintf(cmd, NFRAME_LEN, "#:CW%01d#", phase);
624  return sendCommand(cmd);
625 }
626 
627 bool nFrameRotator::setCoilStatus(uint8_t status)
628 {
629  char cmd[NFRAME_LEN] = {0};
630  snprintf(cmd, NFRAME_LEN, "#:CC%01d#", status == COIL_ENERGIZED_OFF ? 1 : 0);
631  LOGF_DEBUG("setCoil = %d hex=%x", status, status);
632  LOGF_DEBUG("setCoilS = %s CEOFF=%d CEON = %d", cmd, COIL_ENERGIZED_OFF, COIL_ENERGIZED_ON);
633  return sendCommand(cmd);
634 }
635 
637 {
639 
640  IUSaveConfigSwitch(fp, &SteppingModeSP);
641  IUSaveConfigNumber(fp, &SettingNP);
642 
643 
644  return true;
645 }
646 double nFrameRotator::calculateAngle(uint32_t steps)
647 {
648  int diff = (static_cast<int32_t>(steps) - m_ZeroPosition) *
650  // LOGF_DEBUG("RANGE=%f",(int)(range360((float(diff)+0.5) / SettingN[PARAM_STEPS_DEGREE].value)*100)/100.);
651  return range360((float(diff) + 0.5) / SettingN[PARAM_STEPS_DEGREE].value);
652  // return (int)(range360((float(diff)+0.5) / SettingN[PARAM_STEPS_DEGREE].value)*100)/100.;
653 }
654 
655 /*
656 bool nFrameRotator::setSpeedRange(uint32_t min, uint32_t max)
657 {
658  return true;
659 }
660 */
661 
662 void nFrameRotator::ISGetProperties(const char *dev)
663 {
665 
666  loadConfig(true, SettingNP.name);
667 }
668 
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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.
INumberVectorProperty GotoRotatorNP
void SetCapability(uint32_t cap)
SetRotatorCapability sets the Rotator capabilities. All capabilities must be initialized.
ISwitchVectorProperty ReverseRotatorSP
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indirotator.cpp:37
INumberVectorProperty PresetNP
Definition: indirotator.h:91
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indirotator.cpp:83
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indirotator.cpp:94
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the reverse direction property in the configuration file
@ ROTATE_OUTWARD
Definition: nframe.h:36
@ ROTATE_INWARD
Definition: nframe.h:35
virtual bool SyncRotator(double angle) override
SyncRotator Set current angle as the supplied angle without moving the rotator.
Definition: nframe.cpp:579
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: nframe.cpp:107
virtual IPState MoveRotator(double angle) override
MoveRotator Go to specific angle.
Definition: nframe.cpp:377
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the reverse direction property in the configuration file
Definition: nframe.cpp:636
INumber RotatorSpeedN[1]
Definition: nframe.h:64
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: nframe.cpp:408
virtual bool Handshake() override
perform handshake with device to check communication
Definition: nframe.cpp:153
INumberVectorProperty RotatorSpeedNP
Definition: nframe.h:63
bool SetRotatorSpeed(uint8_t speed)
Definition: nframe.cpp:599
const char * getDefaultName() override
Definition: nframe.cpp:102
virtual bool AbortRotator() override
AbortRotator Abort all motion.
Definition: nframe.cpp:397
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: nframe.cpp:324
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: nframe.cpp:662
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: nframe.cpp:235
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: nframe.cpp:45
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:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition: indicom.c:1245
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
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:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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:158
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:180
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:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1296
#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 MAXRBUF
Definition: indiserver.cpp:102
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371