Instrument Neutral Distributed Interface INDI  2.0.2
nexdome_beaver.cpp
Go to the documentation of this file.
1 /*
2  NexDome Beaver Controller
3 
4  Copyright (C) 2021 Jasem Mutlaq (mutlaqja@ikarustech.com)
5  Modified 2021 Sifan Kahale (sifan.kahale@gmail.com)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21 */
22 
23 #include "nexdome_beaver.h"
24 
25 #include "indicom.h"
28 
29 #include <cmath>
30 #include <cstring>
31 #include <cassert>
32 #include <memory>
33 #include <regex>
34 
35 #include <termios.h>
36 #include <unistd.h>
37 #include "config.h"
38 
39 static std::unique_ptr<Beaver> dome(new Beaver());
40 
42 {
43  setVersion(1, 1);
45 
47 }
48 
50 {
52 
55 
59  // Rotator status
60  RotatorStatusTP[0].fill("RSTATUS", "Status", "Idle");
61  RotatorStatusTP.fill(getDeviceName(), "ROTATORSTATUS", "Dome", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
62 
63  // Shutter status
64  ShutterStatusTP[0].fill("SSTATUS", "Status", "Idle");
65  ShutterStatusTP.fill(getDeviceName(), "SHUTTERSTATUS", "Shutter", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
66 
67  // Shutter Voltage
68  ShutterVoltsNP[0].fill("SHUTTERvolts", "Volts", "%.2f", 0.00, 15.00, 0.00, 0.00);
69  ShutterVoltsNP.fill(getDeviceName(), "SHUTTERVOLTS", "Shutter", MAIN_CONTROL_TAB, IP_RO, 60, IPS_OK);
70 
71  // Rotator Home
72  GotoHomeSP[0].fill("ROTATOR_HOME_GOTO", "Home", ISS_OFF);
73  GotoHomeSP.fill(getDefaultName(), "ROTATOR_GOTO_Home", "Rotator", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
74 
76  // Rototor settings tab
78 
79  // Home position
80  HomePositionNP[0].fill("HOME_AZ", "AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0);
81  HomePositionNP.fill(getDeviceName(), "HOME_POSITION", "Home Position", SITE_TAB, IP_RW, 60, IPS_IDLE);
82 
83  // Home set options
84  HomeOptionsSP[HOMECURRENT].fill("HOME_CURRENT", "Current", ISS_OFF);
85  HomeOptionsSP[HOMEDEFAULT].fill("HOME_DEFAULT", "Default (0)", ISS_OFF);
86  HomeOptionsSP.fill(getDeviceName(), "DOME_HOME_OPTION", "Home Options", SITE_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
87 
88  // Rotator Calibrations
89  RotatorCalibrationSP[ROTATOR_HOME_FIND].fill("ROTATOR_HOME_FIND", "Find Home", ISS_OFF);
90  RotatorCalibrationSP[ROTATOR_HOME_MEASURE].fill("ROTATOR_HOME_MEASURE", "Measure Home", ISS_OFF);
91  RotatorCalibrationSP.fill(getDefaultName(), "ROTATOR_CALIBRATION", "Rotator", ROTATOR_TAB, IP_RW, ISR_ATMOST1, 60,
92  IPS_IDLE);
93 
94  // Rotator Settings
95  RotatorSettingsNP[ROTATOR_MAX_SPEED].fill("ROTATOR_MAX_SPEED", "Max Speed (m/s)", "%.f", 1, 1000, 10, 800);
96  RotatorSettingsNP[ROTATOR_MIN_SPEED].fill("ROTATOR_MIN_SPEED", "Min Speed (m/s)", "%.f", 1, 1000, 10, 400);
97  RotatorSettingsNP[ROTATOR_ACCELERATION].fill("ROTATOR_ACCELERATION", "Acceleration (m/s^2)", "%.f", 1, 1000, 10, 500);
98  RotatorSettingsNP[ROTATOR_TIMEOUT].fill("ROTATOR_TIMEOUT", "Timeout (s)", "%.f", 1, 1000, 10, 83);
99  RotatorSettingsNP.fill(getDeviceName(), "ROTATOR_SETTINGS", "Settings", ROTATOR_TAB, IP_RW, 60, IPS_IDLE);
100 
102  // Shutter settings tab
104  // Shutter Home (calibrate, reset)
105  ShutterCalibrationSP[SHUTTER_HOME_FIND].fill("SHUTTER_HOME_FIND", "AutoCalibrate", ISS_OFF);
106  ShutterCalibrationSP.fill(getDeviceName(), "SHUTTER_CALIBRATION", "Shutter", SHUTTER_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
107 
108  // Shutter Settings
109  ShutterSettingsNP[SHUTTER_MAX_SPEED].fill("SHUTTER_MAX_SPEED", "Max Speed (m/s)", "%.f", 1, 1000, 10, 800);
110  ShutterSettingsNP[SHUTTER_MIN_SPEED].fill("SHUTTER_MIN_SPEED", "Min Speed (m/s)", "%.f", 1, 1000, 10, 400);
111  ShutterSettingsNP[SHUTTER_ACCELERATION].fill("SHUTTER_ACCELERATION", "Acceleration (m/s^2)", "%.f", 1, 1000, 10, 500);
112  ShutterSettingsNP[SHUTTER_SAFE_VOLTAGE].fill("SHUTTER_SAFE_VOLTAGE", "Safe Voltage", "%.1f", 10, 14, .5, 11);
113  ShutterSettingsNP.fill(getDeviceName(), "SHUTTER_SETTINGS", "Settings", SHUTTER_TAB, IP_RW, 60, IPS_IDLE);
114 
115  ShutterSettingsTimeoutNP[0].fill("SHUTTER_TIMEOUT", "Timeout (s)", "%.f", 1, 1000, 10, 83);
116  ShutterSettingsTimeoutNP.fill(getDeviceName(), "SHUTTER_R_SETTINGS", "Settings", SHUTTER_TAB, IP_RO, 60, IPS_IDLE);
117 
119  // INFO Tab
121  // Beaver Firmware Version
122  VersionTP[0].fill("CVERSION", "Controller", "");
123  VersionTP.fill(getDeviceName(), "DOME_FIRMWARE", "Version", CONNECTION_TAB, IP_RO, 0, IPS_IDLE);
124 
126  // Communication
128  // NOTE need to figure out how to get network connection working
129  tcpConnection->setDefaultHost("192.168.1.1");
133  addDebugControl();
134  return true;
135 }
136 
138 {
140 
141  if (isConnected())
142  {
143  double curPark;
144  if (!sendCommand("!domerot getpark#", curPark))
145  return false;
146  if (InitPark())
147  {
148  SetAxis1ParkDefault(curPark);
149  }
150  else
151  {
152  SetAxis1Park(curPark);
153  SetAxis1ParkDefault(curPark);
154  }
155  TimerHit();
156 
157  defineProperty(VersionTP);
158  defineProperty(HomePositionNP);
159  defineProperty(HomeOptionsSP);
160  defineProperty(RotatorCalibrationSP);
161  defineProperty(GotoHomeSP);
162  defineProperty(RotatorSettingsNP);
163  defineProperty(RotatorStatusTP);
164  if (shutterOnLine())
165  {
166  defineProperty(ShutterCalibrationSP);
167  defineProperty(ShutterSettingsNP);
168  defineProperty(ShutterSettingsTimeoutNP);
169  defineProperty(ShutterStatusTP);
170  defineProperty(ShutterVoltsNP);
171  }
172  }
173  else
174  {
175  deleteProperty(VersionTP.getName());
176  deleteProperty(RotatorCalibrationSP.getName());
177  deleteProperty(GotoHomeSP.getName());
178  deleteProperty(HomePositionNP.getName());
179  deleteProperty(HomeOptionsSP.getName());
180  deleteProperty(RotatorSettingsNP.getName());
181  deleteProperty(ShutterSettingsTimeoutNP.getName());
182  deleteProperty(RotatorStatusTP.getName());
183  deleteProperty(ShutterCalibrationSP.getName());
184  deleteProperty(ShutterSettingsNP.getName());
185  deleteProperty(ShutterStatusTP.getName());
186  deleteProperty(ShutterVoltsNP.getName());
187 
188  }
189  return true;
190 }
191 
192 
197 {
198  if (echo())
199  {
200  // Check if shutter is online
201  if (shutterOnLine())
202  {
203  LOG_DEBUG("Shutter in online, enabling Dome has shutter property");
205  return true;
206  }
207  return true;
208  }
209 
210  return false;
211 }
212 
217 {
218  return "NexDome Beaver";
219 }
220 
224 bool Beaver::echo()
225 {
226  double res = 0;
227 
228  // retrieve the controller version from the dome
229  char result[DRIVER_LEN] = {0};
230  if (!sendRawCommand("!seletek tversion#", result))
231  {
232  LOG_ERROR("Error getting version info");
233  return false;
234  }
235  std::string resString = result;
236  LOGF_DEBUG("Version string returned %s", resString.c_str());
237  std::regex e(R"(.*:\d*:(.*))");
238  std::sregex_iterator iter(resString.begin(), resString.end(), e);
239  VersionTP[0].setText((*iter)[1]);
240 
241  // retrieve the current az from the dome
242  if (rotatorGetAz())
243  LOGF_INFO("Dome reports az: %.1f", DomeAbsPosN[0].value);
244  else
245  return false;
246 
247  // retrieve the current home offset from the dome
248  if (!sendCommand("!domerot gethome#", res))
249  return false;
250  else
251  {
252  HomePositionNP[0].setValue(res);
253  LOGF_INFO("Dome reports home offset: %f", res);
254  }
255 
256  // retrieve the current park position from the dome
257  if (!sendCommand("!domerot getpark#", res))
258  return false;
259  else
260  {
261  SetAxis1Park(res);
262  LOGF_INFO("Dome reports park: %.1f", res);
263  }
264 
265  // get current rotator settings
266  if (!rotatorGetSettings())
267  return false;
268 
269  // get current shutter settings
270  if (shutterOnLine())
271  {
272  if (!shutterGetSettings())
273  return false;
274  }
275  return true;
276 }
277 
281 bool Beaver::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
282 {
283  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
284  {
286  // Rotator Calibration (find and measure home)
288  if (RotatorCalibrationSP.isNameMatch(name))
289  {
290  RotatorCalibrationSP.update(states, names, n);
291  bool rc = false;
292  switch (RotatorCalibrationSP.findOnSwitchIndex())
293  {
294  case ROTATOR_HOME_FIND:
295  rc = rotatorFindHome();
296  RotatorCalibrationSP.setState(rc ? IPS_BUSY : IPS_ALERT);
297  break;
298 
299  case ROTATOR_HOME_MEASURE:
300  rc = rotatorMeasureHome();
301  RotatorCalibrationSP.setState(rc ? IPS_BUSY : IPS_ALERT);
302  break;
303  }
304  RotatorCalibrationSP.apply();
305  return true;
306  }
307 
309  // Rotator Go Home
311  if (GotoHomeSP.isNameMatch(name))
312  {
313  GotoHomeSP.update(states, names, n);
314  bool rc = false;
315  rc = rotatorGotoHome();
316  GotoHomeSP.setState(rc ? IPS_BUSY : IPS_ALERT);
317  GotoHomeSP.apply();
318  return true;
319  }
320 
322  // Home options
324  if (HomeOptionsSP.isNameMatch(name))
325  {
326  HomeOptionsSP.update(states, names, n);
327  bool rc = false;
328  double newAz, curHome;
329  switch (HomeOptionsSP.findOnSwitchIndex())
330  {
331  case HOMECURRENT:
332  if (!sendCommand("!domerot getpark#", curHome))
333  return false;
334  newAz = 360.0 - curHome + rotatorGetAz();
335  rc = rotatorSetHome(newAz);
336  LOGF_DEBUG("New home az %.1f (from 360 - %1f + %1f)", newAz, curHome, rotatorGetAz());
337  HomeOptionsSP.setState(rc ? IPS_BUSY : IPS_ALERT);
338  break;
339 
340  case HOMEDEFAULT:
341  rc = rotatorSetHome(0.0);
342  HomeOptionsSP.setState(rc ? IPS_OK : IPS_ALERT);
343  break;
344  }
345  HomeOptionsSP.apply();
346  return true;
347  }
348 
350  // Shutter Calibration
352  if (ShutterCalibrationSP.isNameMatch(name))
353  {
354  //TEST
355  ShutterCalibrationSP.update(states, names, n);
356  bool rc = shutterFindHome();
357  if (rc)
359  ShutterCalibrationSP.setState(rc ? IPS_BUSY : IPS_ALERT);
360  ShutterCalibrationSP.apply();
361  return true;
362  }
363  }
364 
365  return INDI::Dome::ISNewSwitch(dev, name, states, names, n);
366 }
367 
371 bool Beaver::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
372 {
373  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
374  {
376  // Rotator Settings
378  if (RotatorSettingsNP.isNameMatch(name))
379  {
380  RotatorSettingsNP.update(values, names, n);
381  RotatorSettingsNP.setState(rotatorSetSettings(RotatorSettingsNP[ROTATOR_MAX_SPEED].getValue(),
382  RotatorSettingsNP[ROTATOR_MIN_SPEED].getValue(),
383  RotatorSettingsNP[ROTATOR_ACCELERATION].getValue(),
384  RotatorSettingsNP[ROTATOR_TIMEOUT].getValue()
385  ) ? IPS_OK : IPS_ALERT);
386  RotatorSettingsNP.apply();
387  return true;
388  }
389 
391  // Shutter Settings
393  if (ShutterSettingsNP.isNameMatch(name))
394  {
395  ShutterSettingsNP.update(values, names, n);
396  ShutterSettingsNP.setState(shutterSetSettings(ShutterSettingsNP[SHUTTER_MAX_SPEED].getValue(),
397  ShutterSettingsNP[SHUTTER_MIN_SPEED].getValue(),
398  ShutterSettingsNP[SHUTTER_ACCELERATION].getValue(),
399  ShutterSettingsNP[SHUTTER_SAFE_VOLTAGE].getValue()
400  ) ? IPS_OK : IPS_ALERT);
401  ShutterSettingsNP.apply();
402  return true;
403  }
404 
408  if (HomePositionNP.isNameMatch(name))
409  {
410  HomePositionNP.update(values, names, n);
411  if (rotatorSetHome(HomePositionNP[0].getValue()))
412  {
413  HomePositionNP.apply();
414  return true;
415  }
416  else
417  return false;
418  }
419 
423  if (strcmp(name, ParkPositionNP.name) == 0)
424  {
425  IUUpdateNumber(&ParkPositionNP, values, names, n);
426  if (rotatorSetPark(ParkPositionN[AXIS_RA].value))
427  {
430  IDSetNumber(&ParkPositionNP, nullptr);
431  return true;
432  }
433  else
434  return false;
435  }
436 
437  }
438 
439  return INDI::Dome::ISNewNumber(dev, name, values, names, n);
440 
441 }
442 
447 {
448  if (!isConnected())
449  {
450  return;
451  }
452 
453  // Get Position and sets az pos field
454  rotatorGetAz();
455  LOGF_DEBUG("Rotator position: %f", DomeAbsPosN[0].value);
456 
457  // Query rotator status
458  uint16_t domeStatus = 0;
459  if (!getDomeStatus(domeStatus))
460  {
461  LOG_ERROR("Could not get dome status");
462  }
463 
465  // Test for general dome errors
467  if (domeStatus & DOME_STATUS_UNSAFE_CW)
468  {
469  LOG_ERROR("CW Unsafe Error");
471  RotatorStatusTP.apply();
472  }
473  if (domeStatus & DOME_STATUS_UNSAFE_RG)
474  {
475  LOG_ERROR("RGx Unsafe Error");
477  RotatorStatusTP.apply();
478  }
479 
481  // Test rotator and set status
483 
484  // Is rotator idle?
485  if (!(domeStatus & DOME_STATUS_ROTATOR_MOVING))
486  {
487 
488  // Dome Parked
489  if (rotatorIsParked() && (getDomeState() == DOME_PARKING))
490  {
491  SetParked(true);
492  std::string rStatus = "Parked";
493  RotatorStatusTP[0].setText(rStatus);
494  RotatorStatusTP.setState(IPS_OK);
495  LOG_DEBUG("Dome is parked.");
496  }
497  // Measuring Home completed
498  else if (!strcmp(RotatorStatusTP[0].getText(), "Measuring Home"))
499  {
501  RotatorCalibrationSP.setState(IPS_OK);
502  RotatorCalibrationSP.apply();
503  std::string rStatus = "Home";
504  RotatorStatusTP[0].setText(rStatus);
505  RotatorStatusTP.setState(IPS_OK);
506  }
507  // Finding Home completed
508  else if (!strcmp(RotatorStatusTP[0].getText(), "Finding Home"))
509  {
511  RotatorCalibrationSP.setState(IPS_OK);
512  RotatorCalibrationSP.apply();
513  std::string rStatus = "Home";
514  RotatorStatusTP[0].setText(rStatus);
515  RotatorStatusTP.setState(IPS_OK);
516  }
517  // Homing completed
518  else if (!strcmp(RotatorStatusTP[0].getText(), "Homing"))
519  {
521  std::string rStatus = "Home";
522  RotatorStatusTP[0].setText(rStatus);
523  RotatorStatusTP.setState(IPS_OK);
524  GotoHomeSP.setState(IPS_OK);
525  GotoHomeSP.apply();
526  LOG_DEBUG("Dome at home");
527  }
528  // Move completed
529  else if (getDomeState() == DOME_MOVING)
530  {
531  RotatorStatusTP.apply();
533  RotatorCalibrationSP.setState(IPS_OK);
534  RotatorCalibrationSP.apply();
535  std::string rStatus = "Idle";
536  RotatorStatusTP[0].setText(rStatus);
537  RotatorStatusTP.setState(IPS_OK);
538  LOG_DEBUG("Dome reached target position.");
539  }
540  RotatorStatusTP.apply();
541  }
542 
544  // Test Shutter and set status
546  if (shutterOnLine())
547  {
548 
549  // Test for shutter error
550  if (domeStatus & DOME_STATUS_SHUTTER_ERROR)
551  {
552  LOG_ERROR("Shutter Mechanical Error");
553  std::string rStatus = "Mechanical Error";
554  ShutterStatusTP[0].setText(rStatus);
555  ShutterStatusTP.apply();
557  }
558 
559  // If moving, set status
561  {
562 
563  if (domeStatus & DOME_STATUS_SHUTTER_OPENING)
564  {
566  std::string rStatus = "Opening";
567  ShutterStatusTP[0].setText(rStatus);
568  LOG_DEBUG("Shutter state set to Opening");
569  }
570  else if (domeStatus & DOME_STATUS_SHUTTER_CLOSING)
571  {
573  std::string rStatus = "Closing";
574  ShutterStatusTP[0].setText(rStatus);
575  LOG_DEBUG("Shutter state set to Closing");
576  }
577  else if (domeStatus & DOME_STATUS_SHUTTER_MOVING)
578  {
580  std::string rStatus = "Moving";
581  ShutterStatusTP[0].setText(rStatus);
582  LOG_DEBUG("Shutter is moving");
583  }
584 
585  }
586 
587  // if stopped, test if opened or closed
588  if (domeStatus & DOME_STATUS_SHUTTER_OPENED)
589  {
591  std::string rStatus = "Open";
592  ShutterStatusTP[0].setText(rStatus);
593  LOG_DEBUG("Shutter state set to OPEN");
594  }
595  if (domeStatus & DOME_STATUS_SHUTTER_CLOSED)
596  {
598  std::string rStatus = "Closed";
599  ShutterStatusTP[0].setText(rStatus);
600  LOG_DEBUG("Shutter state set to CLOSED");
601  }
602  ShutterStatusTP.apply();
603 
604  // Update shutter voltage
605  double res;
606  // ignoring a random get voltage cmd error here and just reporting successful status
607  if (sendCommand("!dome getshutterbatvoltage#", res))
608  {
609  LOGF_DEBUG("Shutter voltage currently is: %.2f", res);
610  ShutterVoltsNP[0].setValue(res);
611  (res < ShutterSettingsNP[SHUTTER_SAFE_VOLTAGE].getValue()) ? ShutterVoltsNP.setState(IPS_ALERT) : ShutterVoltsNP.setState(
612  IPS_OK);
613  ShutterVoltsNP.apply();
614  }
615  }
616 
618 }
619 
624 {
625  if (rotatorGotoAz(az))
626  {
627  m_TargetRotatorAz = az;
629  std::string rStatus = "Moving";
630  RotatorStatusTP[0].setText(rStatus);
631  RotatorStatusTP.apply();
632  return IPS_BUSY;
633  }
634  return IPS_ALERT;
635 }
636 
640 IPState Beaver::MoveRel(double azDiff)
641 {
642 
643  azDiff = domeDir * azDiff;
644  m_TargetRotatorAz = DomeAbsPosN[0].value + azDiff;
645 
646  if (m_TargetRotatorAz < DomeAbsPosN[0].min)
647  m_TargetRotatorAz += DomeAbsPosN[0].max;
648  if (m_TargetRotatorAz > DomeAbsPosN[0].max)
649  m_TargetRotatorAz -= DomeAbsPosN[0].max;
650  LOGF_DEBUG("Requested rel move of %.1f", azDiff);
651  lastAzDiff = fabs(azDiff);
652  return MoveAbs(m_TargetRotatorAz);
653 }
654 
659 {
660  LOG_DEBUG("Re-implemented move was called");
661  if (operation == MOTION_START)
662  {
663  if (dir == DOME_CW)
664  {
665  domeDir = 1;
666  }
667  else
668  {
669  domeDir = -1;
670  }
671  MoveRel(lastAzDiff);
672 
673  }
674  return IPS_OK;
675 }
676 
681 {
682  double res = 0;
683  if (operation == SHUTTER_OPEN)
684  {
685  if (sendCommand("!dome openshutter#", res))
686  {
687  std::string rStatus = "Opening";
688  ShutterStatusTP[0].setText(rStatus);
689  ShutterStatusTP.apply();
691  return IPS_BUSY;
692  }
693  else
694  return IPS_ALERT;
695  }
696  else if (operation == SHUTTER_CLOSE)
697  {
698  if (sendCommand("!dome closeshutter#", res))
699  {
700  std::string rStatus = "Shutting";
701  ShutterStatusTP[0].setText(rStatus);
702  ShutterStatusTP.apply();
704  return IPS_BUSY;
705  }
706  else
707  return IPS_ALERT;
708  }
709  return IPS_ALERT;
710 }
711 
716 {
718  return true;
719 }
720 
724 bool Beaver::rotatorGotoAz(double az)
725 {
726  char cmd[DRIVER_LEN] = {0};
727  double res = 0;
728  snprintf(cmd, DRIVER_LEN, "!dome gotoaz %.2f#", az);
730  std::string rStatus = "Moving";
731  RotatorStatusTP[0].setText(rStatus);
732  RotatorStatusTP.apply();
733  return sendCommand(cmd, res);
734 }
735 
739 bool Beaver::rotatorGetAz()
740 {
741  double res = 0;
742  if (sendCommand("!dome getaz#", res))
743  {
744  DomeAbsPosN[0].value = res;
745  IDSetNumber(&DomeAbsPosNP, nullptr);
746  return true;
747  }
748  return false;
749 }
750 
754 bool Beaver::rotatorSetHome(double az)
755 {
756  char cmd[DRIVER_LEN] = {0};
757  double res = 0;
758  snprintf(cmd, DRIVER_LEN, "!domerot sethome %.2f#", az);
759  if (sendCommand(cmd, res))
760  {
761  LOGF_INFO("Home is set to: %.1f", az);
762  return true;
763  }
764  return false;
765 }
766 
771 {
772  double res;
773  if (sendCommand("!dome gopark#", res))
774  {
775  std::string rStatus = "Parking";
776  RotatorStatusTP[0].setText(rStatus);
777  RotatorStatusTP.apply();
778  // check shutter policy
779  if (shutterOnLine() && (ShutterParkPolicyS[SHUTTER_CLOSE_ON_PARK].s == ISS_ON))
780  {
782  {
785  }
786  else
787  return IPS_ALERT;
788  }
789  return IPS_BUSY;
790  }
791  return IPS_ALERT;
792 }
793 
798 {
799  std::string rStatus = "unParked";
800  RotatorStatusTP[0].setText(rStatus);
801  RotatorStatusTP.apply();
802  // check shutter policy
803  if (shutterOnLine() && (ShutterParkPolicyS[SHUTTER_OPEN_ON_UNPARK].s == ISS_ON))
804  {
806  {
809  }
810  else
811  return IPS_ALERT;
812  }
813  return IPS_OK;
814 }
815 
819 bool Beaver::rotatorSetPark(double az)
820 {
821  double res = 0;
822  char cmd[DRIVER_LEN] = {0};
823  snprintf(cmd, DRIVER_LEN, "!domerot setpark %.2f#", az);
824  if (sendCommand(cmd, res))
825  {
826  LOGF_INFO("Park set to: %.2f", az);
827  SetAxis1Park(az);
828  return true;
829  }
830 
831  return false;
832 }
833 
838 {
839  double res = 0;
840  char cmd[DRIVER_LEN] = {0};
841  snprintf(cmd, DRIVER_LEN, "!domerot setpark %.2f#", DomeAbsPosN[0].value);
842  if (sendCommand(cmd, res))
843  {
844  SetAxis1Park(DomeAbsPosN[0].value);
845  LOGF_INFO("Park set to current: %.2f", DomeAbsPosN[0].value);
846  }
847  return true;
848 
849  return false;
850 }
851 
856 {
857  double res = 0;
858  char cmd[DRIVER_LEN] = {0};
859  snprintf(cmd, DRIVER_LEN, "!domerot setpark %d#", 0);
860  if (sendCommand(cmd, res))
861  {
862  SetAxis1Park(0.0);
863  LOG_INFO("Park set to default: 0.00");
864  return true;
865  }
866 
867  return false;
868 }
869 
870 
874 bool Beaver::rotatorGotoHome()
875 {
876  double res = 0;
877  if (sendCommand("!dome gohome#", res))
878  {
880  std::string rStatus = "Homing";
881  RotatorStatusTP[0].setText(rStatus);
882  RotatorStatusTP.apply();
883  return true;
884  }
885  return false;
886 }
887 
891 bool Beaver::rotatorMeasureHome()
892 {
893  double res = 0;
894  if (sendCommand("!dome autocalrot 1#", res))
895  {
897  std::string rStatus = "Measuring Home";
898  RotatorStatusTP[0].setText(rStatus);
899  RotatorStatusTP.apply();
900  return true;
901  }
902  return false;
903 }
904 
908 bool Beaver::rotatorFindHome()
909 {
910  double res = 0;
911  if (sendCommand("!dome autocalrot 0#", res))
912  {
914  std::string rStatus = "Finding Home";
915  RotatorStatusTP[0].setText(rStatus);
916  RotatorStatusTP.apply();
917  return true;
918  }
919  return false;
920 }
921 
925 bool Beaver::rotatorIsHome()
926 {
927  double status = 0;
928  if (sendCommand("!dome athome#", status))
929  {
930  LOG_ERROR("Error checking home");
931  return false;
932  }
933  LOGF_DEBUG("Rotator Home? %s", (status == 1) ? "true" : "false");
934  if (status == 1)
935  return true;
936  else
937  return false;
938 }
939 
940 
944 bool Beaver::rotatorIsParked()
945 {
946  double status = 0;
947  if (!sendCommand("!dome atpark#", status))
948  {
949  LOG_ERROR("Error checking park");
950  return false;
951  }
952  LOGF_DEBUG("Rotator Parked? %s", (status == 1) ? "true" : "false");
953  if (status == 1)
954  return true;
955  else
956  return false;
957 }
958 
962 bool Beaver::getDomeStatus(uint16_t &domeStatus)
963 {
964  double res = 0;
965  if (!sendCommand("!dome status#", res))
966  {
967  LOG_ERROR("Status cmd errored out");
968  return false;
969  }
970  domeStatus = static_cast<uint16_t>(res);
971  LOGF_DEBUG("Dome status: %0x", domeStatus);
972  return true;
973 }
974 
978 bool Beaver::shutterOnLine()
979 {
980  double res = 0;
981  uint16_t domeStatus;
982  bool shutterIsUp = false;
983  // retrieving shutter status
984  if (!sendCommand("!dome shutterisup#", res))
985  {
986  LOG_ERROR("Shutter status cmd errored out");
987  //failsave, return false/not online
988  return false;
989  }
990  // retrieving comm status
991  shutterIsUp = static_cast<bool>(res);
992  if (!getDomeStatus(domeStatus))
993  {
994  LOG_ERROR("Shutter status cmd errored out");
995  //failsave, return false/not online
996  return false;
997  }
998  LOGF_DEBUG("ShutterIsUp %s Comms error %s", shutterIsUp ? "true" : "false",
999  (domeStatus & DOME_STATUS_SHUTTER_COMM) ? "true" : "false");
1000  bool status = (shutterIsUp | !(domeStatus & DOME_STATUS_SHUTTER_COMM));
1001  LOGF_DEBUG("ShuttOnLine %s", status ? "true" : "false");
1002  return status;
1003 }
1004 
1009 {
1010  return abortAll();
1011 }
1012 
1016 bool Beaver::abortAll()
1017 {
1018  double res = 0;
1019  if (sendCommand("!dome abort 1 1 1#", res))
1020  {
1021  std::string rStatus = "Idle";
1022  RotatorStatusTP[0].setText(rStatus);
1023  RotatorStatusTP.apply();
1024  if (!rotatorGetAz())
1025  return false;
1026  return true;
1027  }
1028 
1029  return false;
1030 }
1031 
1035 bool Beaver::shutterAbort()
1036 {
1037  double res = 0;
1038  return sendCommand("!dome abort 0 0 1#", res);
1039 }
1040 
1044 bool Beaver::shutterSetSettings(double maxSpeed, double minSpeed, double acceleration, double voltage)
1045 {
1046  if (shutterOnLine())
1047  {
1048  char cmd[DRIVER_LEN] = {0};
1049  double res;
1050 
1051  snprintf(cmd, DRIVER_LEN, "!dome setshuttermaxspeed %.2f#", maxSpeed);
1052  if (!sendCommand(cmd, res))
1053  {
1054  LOG_ERROR("Problem setting shutter max speed");
1055  return false;
1056  }
1057  snprintf(cmd, DRIVER_LEN, "!dome setshutterminspeed %.2f#", minSpeed);
1058  if (!sendCommand(cmd, res))
1059  {
1060  LOG_ERROR("Problem setting shutter min speed");
1061  return false;
1062  }
1063  snprintf(cmd, DRIVER_LEN, "!dome setshutteracceleration %.2f#", acceleration);
1064  if (!sendCommand(cmd, res))
1065  {
1066  LOG_ERROR("Problem setting shutter acceleration");
1067  return false;
1068  }
1069  snprintf(cmd, DRIVER_LEN, "!dome setshuttersafevoltage %.2f#", voltage);
1070  if (!sendCommand(cmd, res))
1071  {
1072  LOG_ERROR("Problem setting shutter safe voltage");
1073  return false;
1074  }
1075  if(!sendCommand("!seletek savefs#", res))
1076  {
1077  LOG_ERROR("Problem setting shutter savefs");
1078  return false;
1079  }
1080  LOG_INFO("Shutter parameters have been updated");
1081  }
1082 
1083  return true;
1084 }
1085 
1089 bool Beaver::shutterGetSettings()
1090 {
1091  double res;
1092  if (shutterOnLine())
1093  {
1094  if (!sendCommand("!dome getshuttermaxspeed#", res))
1095  {
1096  LOG_ERROR("Problem getting shutter max speed");
1097  return false;
1098  }
1099  else
1100  {
1101  ShutterSettingsNP[SHUTTER_MAX_SPEED].setValue(res);
1102  LOGF_DEBUG("Shutter reports max speed of: %.1f", res);
1103  }
1104  if (!sendCommand("!dome getshutterminspeed#", res))
1105  {
1106  LOG_ERROR("Problem getting shutter min speed");
1107  return false;
1108  }
1109  else
1110  {
1111  ShutterSettingsNP[SHUTTER_MIN_SPEED].setValue(res);
1112  LOGF_DEBUG("Shutter reports min speed of: %.1f", res);
1113  }
1114  if (!sendCommand("!dome getshutteracceleration#", res))
1115  {
1116  LOG_ERROR("Problem getting shutter acceleration");
1117  return false;
1118  }
1119  else
1120  {
1121  ShutterSettingsNP[SHUTTER_ACCELERATION].setValue(res);
1122  LOGF_DEBUG("Shutter reports acceleration of: %.1f", res);
1123  }
1124  if (!sendCommand("!dome getshuttertimeoutopenclose#", res))
1125  {
1126  LOG_ERROR("Problem getting shutter timeout");
1127  return false;
1128  }
1129  else
1130  {
1131  ShutterSettingsTimeoutNP[0].setValue(res);
1132  LOGF_DEBUG("Shutter reports safe timeout of: %.1f", res);
1133  }
1134  if (!sendCommand("!dome getshuttersafevoltage#", res))
1135  {
1136  LOG_ERROR("Problem getting shutter safe voltage");
1137  return false;
1138  }
1139  else
1140  {
1141  ShutterSettingsNP[SHUTTER_SAFE_VOLTAGE].setValue(res);
1142  LOGF_DEBUG("Shutter reports safe voltage of: %.1f", res);
1143  }
1144  ShutterSettingsNP.apply();
1145  }
1146 
1147  return true;
1148 }
1149 
1153 bool Beaver::rotatorSetSettings(double maxSpeed, double minSpeed, double acceleration, double timeout)
1154 {
1155  char cmd[DRIVER_LEN] = {0};
1156  double res;
1157 
1158  snprintf(cmd, DRIVER_LEN, "!domerot setmaxspeed %.2f#", maxSpeed);
1159  if (!sendCommand(cmd, res))
1160  {
1161  LOG_ERROR("Problem setting rotator max speed");
1162  return false;
1163  }
1164  snprintf(cmd, DRIVER_LEN, "!domerot setminspeed %.2f#", minSpeed);
1165  if (!sendCommand(cmd, res))
1166  {
1167  LOG_ERROR("Problem setting rotator min speed");
1168  return false;
1169  }
1170  snprintf(cmd, DRIVER_LEN, "!domerot setacceleration %.2f#", acceleration);
1171  if (!sendCommand(cmd, res))
1172  {
1173  LOG_ERROR("Problem setting rotator acceleration");
1174  return false;
1175  }
1176  snprintf(cmd, DRIVER_LEN, "!domerot setmaxfullrotsecs %.2f#", timeout);
1177  if (!sendCommand(cmd, res))
1178  {
1179  LOG_ERROR("Problem setting rotator full rot secs");
1180  return false;
1181  }
1182  if(!sendCommand("!seletek savefs#", res))
1183  {
1184  LOG_ERROR("dome could not savefs");
1185  return false;
1186  }
1187  LOG_INFO("Rotator parameters have been updated");
1188 
1189  return true;
1190 }
1191 
1195 bool Beaver::rotatorGetSettings()
1196 {
1197  double res;
1198  if (!sendCommand("!domerot getmaxspeed#", res))
1199  {
1200  LOG_ERROR("Problem getting rotator max speed");
1201  return false;
1202  }
1203  else
1204  {
1205  RotatorSettingsNP[ROTATOR_MAX_SPEED].setValue(res);
1206  LOGF_DEBUG("Rotator reports max speed of: %.1f", res);
1207  }
1208  if (!sendCommand("!domerot getminspeed#", res))
1209  {
1210  LOG_ERROR("Problem getting rotator min speed");
1211  return false;
1212  }
1213  else
1214  {
1215  RotatorSettingsNP[ROTATOR_MIN_SPEED].setValue(res);
1216  LOGF_DEBUG("Rotator reports min speed of: %.1f", res);
1217  }
1218  if (!sendCommand("!domerot getacceleration#", res))
1219  {
1220  LOG_ERROR("Problem getting rotator acceleration");
1221  return false;
1222  }
1223  else
1224  {
1225  RotatorSettingsNP[ROTATOR_ACCELERATION].setValue(res);
1226  LOGF_DEBUG("Rotator reports acceleration of: %.1f", res);
1227  }
1228  if (!sendCommand("!domerot getmaxfullrotsecs#", res))
1229  {
1230  LOG_ERROR("Problem getting rotator full rot secs");
1231  return false;
1232  }
1233  else
1234  {
1235  RotatorSettingsNP[ROTATOR_TIMEOUT].setValue(res);
1236  LOGF_DEBUG("Rotator reports timeout(s) of: %.1f", res);
1237  }
1238  RotatorSettingsNP.apply();
1239 
1240  return true;
1241 }
1242 
1246 bool Beaver::shutterFindHome()
1247 {
1248  if (shutterOnLine())
1249  {
1250  double res = 0;
1251  return sendCommand("!dome autocalshutter#", res);
1252  }
1253  return false;
1254 }
1255 
1259 bool Beaver::sendRawCommand(const char * cmd, char * response)
1260 {
1261  int rc = TTY_OK;
1262  for (int i = 0; i < 3; i++)
1263  {
1264  int nbytes_written = 0, nbytes_read = 0;
1265  rc = tty_write_string(PortFD, cmd, &nbytes_written);
1266 
1267  if (rc != TTY_OK)
1268  {
1269  char errstr[MAXRBUF] = {0};
1270  tty_error_msg(rc, errstr, MAXRBUF);
1271  LOGF_ERROR("Serial write error: %s.", errstr);
1272  return false;
1273  }
1274 
1275  rc = tty_nread_section(PortFD, response, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
1276 
1277  if (rc != TTY_OK)
1278  {
1279  // wait and try again
1280  usleep(100000);
1281  continue;
1282  }
1283 
1284  // Remove extra #
1285  response[nbytes_read - 1] = 0;
1286  LOGF_DEBUG("Command Response: %s", response);
1287  return true;
1288  }
1289 
1290  // timeouts used up, return error
1291  if (rc != TTY_OK)
1292  {
1293  char errstr[MAXRBUF] = {0};
1294  tty_error_msg(rc, errstr, MAXRBUF);
1295  LOGF_ERROR("Serial read error: %s.", errstr);
1296  }
1297  return false;
1298 }
1302 bool Beaver::sendCommand(const char * cmd, double &res)
1303 {
1304  char response[DRIVER_LEN] = {0};
1305  sendRawCommand(cmd, response);
1306 
1307  std::regex rgx(R"(.*:((-*\d+(\.\d*)*)))");
1308  std::smatch match;
1309  std::string input(response);
1310 
1311  if (std::regex_search(input, match, rgx))
1312  {
1313  try
1314  {
1315  res = std::stof(match.str(1));
1316  return true;
1317  }
1318  catch (...)
1319  {
1320  LOGF_ERROR("Failed to process response: %s.", response);
1321  return false;
1322  }
1323  }
1324  LOGF_DEBUG("Command error: %s response: %d", cmd, response);
1325  return false;
1326 }
virtual IPState UnPark() override
Rotator unpark.
virtual IPState ControlShutter(ShutterOperation operation) override
open or close the shutter (will not show if shutter is not present)
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation) override
Rotator move (calc's offset and calles abs move)
virtual IPState MoveRel(double azDiff) override
Rotator relative move (calc's offset and calles abs move)
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState Park() override
Rotator park.
virtual bool SetCurrentPark() override
Rotator set park position to current.
virtual void TimerHit() override
Timer hit - update appropriate fields.
virtual bool SetDefaultPark() override
Rotator set park position to default (0 az)
virtual bool Abort() override
abort everything
const char * getDefaultName() override
Set default name.
bool Handshake() override
Handshake.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
@ DOME_STATUS_SHUTTER_CLOSING
@ DOME_STATUS_SHUTTER_COMM
@ DOME_STATUS_SHUTTER_OPENED
@ DOME_STATUS_UNSAFE_RG
@ DOME_STATUS_SHUTTER_CLOSED
@ DOME_STATUS_ROTATOR_MOVING
@ DOME_STATUS_SHUTTER_MOVING
@ DOME_STATUS_SHUTTER_OPENING
@ DOME_STATUS_SHUTTER_ERROR
@ DOME_STATUS_UNSAFE_CW
virtual IPState MoveAbs(double az) override
Rotator absolute move.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Number field updated.
virtual bool saveConfigItems(FILE *fp) override
INDI save config.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Switch field updated.
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
void setDefaultHost(const char *addressHost)
void setConnectionType(int type)
TODO should be renamed to setDefaultConnectionType.
void setDefaultPort(uint32_t addressPort)
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
INDI::PropertyText getText(const char *name) const
Definition: basedevice.cpp:94
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.
ISwitch DomeShutterS[2]
Definition: indidome.h:549
Connection::TCP * tcpConnection
Definition: indidome.h:620
@ DOME_CAN_PARK
Definition: indidome.h:159
@ DOME_CAN_ABS_MOVE
Definition: indidome.h:157
@ DOME_HAS_SHUTTER
Definition: indidome.h:161
@ DOME_CAN_REL_MOVE
Definition: indidome.h:158
@ DOME_CAN_ABORT
Definition: indidome.h:156
@ CONNECTION_SERIAL
Definition: indidome.h:172
@ CONNECTION_TCP
Definition: indidome.h:173
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1633
void SetDomeCapability(uint32_t cap)
SetDomeCapability set the dome capabilities. All capabilities must be initialized.
Definition: indidome.cpp:1561
void setDomeConnection(const uint8_t &value)
setDomeConnection Set Dome connection mode. Child class should call this in the constructor before Do...
Definition: indidome.cpp:2297
@ SHUTTER_OPEN_ON_UNPARK
Definition: indidome.h:579
@ SHUTTER_CLOSE_ON_PARK
Definition: indidome.h:578
INumber ParkPositionN[1]
Definition: indidome.h:554
@ DOME_ERROR
Definition: indidome.h:139
@ DOME_PARKING
Definition: indidome.h:134
@ DOME_MOVING
Definition: indidome.h:132
void SetAxis1Park(double value)
SetRAPark Set current AZ parking position. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1861
INumber DomeAbsPosN[1]
Definition: indidome.h:534
ISwitch ShutterParkPolicyS[2]
Definition: indidome.h:575
void SetAxis1ParkDefault(double steps)
SetAxis1Park Set default AZ parking position.
Definition: indidome.cpp:1868
ShutterOperation
Shutter operation command.
Definition: indidome.h:114
@ SHUTTER_CLOSE
Definition: indidome.h:116
@ SHUTTER_OPEN
Definition: indidome.h:115
int PortFD
Definition: indidome.h:617
DomeMotionCommand
Definition: indidome.h:97
@ MOTION_START
Definition: indidome.h:98
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indidome.cpp:93
INumberVectorProperty DomeAbsPosNP
Definition: indidome.h:533
INumberVectorProperty ParkPositionNP
Definition: indidome.h:555
uint32_t GetDomeCapability() const
GetDomeCapability returns the capability of the dome.
Definition: indidome.h:204
@ SHUTTER_ERROR
Definition: indidome.h:151
@ SHUTTER_MOVING
Definition: indidome.h:149
@ SHUTTER_OPENED
Definition: indidome.h:147
@ SHUTTER_CLOSED
Definition: indidome.h:148
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indidome.cpp:279
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indidome.cpp:492
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
Definition: indidome.cpp:1043
void setShutterState(const ShutterState &value)
Definition: indidome.cpp:1119
void setDomeState(const DomeState &value)
Definition: indidome.cpp:1156
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Definition: indidome.cpp:1644
Connection::Serial * serialConnection
Definition: indidome.h:619
void SetParkDataType(DomeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
Definition: indidome.cpp:1587
ShutterState getShutterState() const
Definition: indidome.h:291
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indidome.cpp:390
DomeState getDomeState() const
Definition: indidome.h:285
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
const char * getName() const
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
std::unique_ptr< Dome > dome(new Dome())
double max(void)
double min(void)
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
@ IP_RO
Definition: indiapi.h:184
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_ATMOST1
Definition: indiapi.h:174
@ AXIS_RA
Definition: indibasetypes.h:35
void tty_set_generic_udp_format(int enabled)
Definition: indicom.c:370
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 IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#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
const char * CONNECTION_TAB
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323