Instrument Neutral Distributed Interface INDI  2.0.2
pegasus_ppba.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2019 Jasem Mutlaq. All rights reserved.
3 
4  Pegasus Pocket Power Box Advance Driver.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the Free
8  Software Foundation; either version 2 of the License, or (at your option)
9  any later version.
10 
11  This program is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 
21  The full GNU General Public License is included in this distribution in the
22  file called LICENSE.
23 *******************************************************************************/
24 
25 #include "pegasus_ppba.h"
26 #include "indicom.h"
28 
29 #include <regex>
30 #include <termios.h>
31 #include <chrono>
32 #include <iomanip>
33 
34 // We declare an auto pointer to PegasusPPBA.
35 static std::unique_ptr<PegasusPPBA> ppba(new PegasusPPBA());
36 
37 PegasusPPBA::PegasusPPBA() : FI(this), WI(this)
38 {
39  setVersion(1, 2);
40  lastSensorData.reserve(PA_N);
41  lastConsumptionData.reserve(PS_N);
42  lastMetricsData.reserve(PC_N);
43 }
44 
46 {
48 
50 
57 
59  WI::initProperties(ENVIRONMENT_TAB, ENVIRONMENT_TAB);
60 
62 
66  // Quad 12v Power
67  IUFillSwitch(&QuadOutS[INDI_ENABLED], "QUADOUT_ON", "Enable", ISS_OFF);
68  IUFillSwitch(&QuadOutS[INDI_DISABLED], "QUADOUT_OFF", "Disable", ISS_OFF);
69  IUFillSwitchVector(&QuadOutSP, QuadOutS, 2, getDeviceName(), "QUADOUT_POWER", "Quad Output", MAIN_CONTROL_TAB,
70  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
71 
72  // Adjustable Power
73  // IUFillSwitch(&AdjOutS[INDI_ENABLED], "ADJOUT_ON", "Enable", ISS_OFF);
74  // IUFillSwitch(&AdjOutS[INDI_DISABLED], "ADJOUT_OFF", "Disable", ISS_OFF);
75  // IUFillSwitchVector(&AdjOutSP, AdjOutS, 2, getDeviceName(), "ADJOUT_POWER", "Adj Output", MAIN_CONTROL_TAB, IP_RW,
76  // ISR_1OFMANY, 60, IPS_IDLE);
77 
78  // Adjustable Voltage
79  IUFillSwitch(&AdjOutVoltS[ADJOUT_OFF], "ADJOUT_OFF", "Off", ISS_ON);
80  IUFillSwitch(&AdjOutVoltS[ADJOUT_3V], "ADJOUT_3V", "3V", ISS_OFF);
81  IUFillSwitch(&AdjOutVoltS[ADJOUT_5V], "ADJOUT_5V", "5V", ISS_OFF);
82  IUFillSwitch(&AdjOutVoltS[ADJOUT_8V], "ADJOUT_8V", "8V", ISS_OFF);
83  IUFillSwitch(&AdjOutVoltS[ADJOUT_9V], "ADJOUT_9V", "9V", ISS_OFF);
84  IUFillSwitch(&AdjOutVoltS[ADJOUT_12V], "ADJOUT_12V", "12V", ISS_OFF);
85  IUFillSwitchVector(&AdjOutVoltSP, AdjOutVoltS, 6, getDeviceName(), "ADJOUT_VOLTAGE", "Adj voltage", MAIN_CONTROL_TAB, IP_RW,
86  ISR_1OFMANY, 60, IPS_IDLE);
87 
88  // Reboot
89  IUFillSwitch(&RebootS[0], "REBOOT", "Reboot Device", ISS_OFF);
90  IUFillSwitchVector(&RebootSP, RebootS, 1, getDeviceName(), "REBOOT_DEVICE", "Device", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1,
91  60, IPS_IDLE);
92 
93  // Power Sensors
94  IUFillNumber(&PowerSensorsN[SENSOR_VOLTAGE], "SENSOR_VOLTAGE", "Voltage (V)", "%4.2f", 0, 999, 100, 0);
95  IUFillNumber(&PowerSensorsN[SENSOR_CURRENT], "SENSOR_CURRENT", "Current (A)", "%4.2f", 0, 999, 100, 0);
96  IUFillNumber(&PowerSensorsN[SENSOR_AVG_AMPS], "SENSOR_AVG_AMPS", "Average Current (A)", "%4.2f", 0, 999, 100, 0);
97  IUFillNumber(&PowerSensorsN[SENSOR_AMP_HOURS], "SENSOR_AMP_HOURS", "Amp hours (Ah)", "%4.2f", 0, 999, 100, 0);
98  IUFillNumber(&PowerSensorsN[SENSOR_WATT_HOURS], "SENSOR_WATT_HOURS", "Watt hours (Wh)", "%4.2f", 0, 999, 100, 0);
99  IUFillNumber(&PowerSensorsN[SENSOR_TOTAL_CURRENT], "SENSOR_TOTAL_CURRENT", "Total current (A)", "%4.2f", 0, 999, 100, 0);
100  IUFillNumber(&PowerSensorsN[SENSOR_12V_CURRENT], "SENSOR_12V_CURRENT", "12V current (A)", "%4.2f", 0, 999, 100, 0);
101  IUFillNumber(&PowerSensorsN[SENSOR_DEWA_CURRENT], "SENSOR_DEWA_CURRENT", "DewA current (A)", "%4.2f", 0, 999, 100, 0);
102  IUFillNumber(&PowerSensorsN[SENSOR_DEWB_CURRENT], "SENSOR_DEWB_CURRENT", "DewB current (A)", "%4.2f", 0, 999, 100, 0);
103  IUFillNumberVector(&PowerSensorsNP, PowerSensorsN, 9, getDeviceName(), "POWER_SENSORS", "Sensors", MAIN_CONTROL_TAB, IP_RO,
104  60, IPS_IDLE);
105 
106  IUFillLight(&PowerWarnL[0], "POWER_WARN_ON", "Current Overload", IPS_IDLE);
107  IUFillLightVector(&PowerWarnLP, PowerWarnL, 1, getDeviceName(), "POWER_WARM", "Power Warn", MAIN_CONTROL_TAB, IPS_IDLE);
108 
109  // LED Indicator
110  IUFillSwitch(&LedIndicatorS[INDI_ENABLED], "LED_ON", "Enable", ISS_ON);
111  IUFillSwitch(&LedIndicatorS[INDI_DISABLED], "LED_OFF", "Disable", ISS_OFF);
112  IUFillSwitchVector(&LedIndicatorSP, LedIndicatorS, 2, getDeviceName(), "LED_INDICATOR", "LED Indicator", MAIN_CONTROL_TAB,
113  IP_RW,
114  ISR_1OFMANY, 60, IPS_IDLE);
115 
119 
120  // Power on Boot
121  IUFillSwitch(&PowerOnBootS[0], "POWER_PORT_1", "Quad Out", ISS_ON);
122  IUFillSwitch(&PowerOnBootS[1], "POWER_PORT_2", "Adj Out", ISS_ON);
123  IUFillSwitch(&PowerOnBootS[2], "POWER_PORT_3", "Dew A", ISS_ON);
124  IUFillSwitch(&PowerOnBootS[3], "POWER_PORT_4", "Dew B", ISS_ON);
125  IUFillSwitchVector(&PowerOnBootSP, PowerOnBootS, 4, getDeviceName(), "POWER_ON_BOOT", "Power On Boot", MAIN_CONTROL_TAB,
126  IP_RW, ISR_NOFMANY, 60, IPS_IDLE);
127 
131 
132  // Automatic Dew
133  IUFillSwitch(&AutoDewS[INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
134  IUFillSwitch(&AutoDewS[INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_OFF);
135  IUFillSwitchVector(&AutoDewSP, AutoDewS, 2, getDeviceName(), "AUTO_DEW", "Auto Dew", DEW_TAB, IP_RW, ISR_1OFMANY, 60,
136  IPS_IDLE);
137 
138  // Dew PWM
139  IUFillNumber(&DewPWMN[DEW_PWM_A], "DEW_A", "Dew A (%)", "%.2f", 0, 100, 10, 0);
140  IUFillNumber(&DewPWMN[DEW_PWM_B], "DEW_B", "Dew B (%)", "%.2f", 0, 100, 10, 0);
141  IUFillNumberVector(&DewPWMNP, DewPWMN, 2, getDeviceName(), "DEW_PWM", "Dew PWM", DEW_TAB, IP_RW, 60, IPS_IDLE);
142 
146  IUFillText(&FirmwareT[FIRMWARE_VERSION], "VERSION", "Version", "NA");
147  IUFillText(&FirmwareT[FIRMWARE_UPTIME], "UPTIME", "Uptime (h)", "NA");
148  IUFillTextVector(&FirmwareTP, FirmwareT, 2, getDeviceName(), "FIRMWARE_INFO", "Firmware", FIRMWARE_TAB, IP_RO, 60,
149  IPS_IDLE);
150 
154  addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
155  addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
156  addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
157  setCriticalParameter("WEATHER_TEMPERATURE");
158 
162 
163  // Max Speed
164  IUFillNumber(&FocuserSettingsN[SETTING_MAX_SPEED], "SETTING_MAX_SPEED", "Max Speed (%)", "%.f", 0, 900, 100, 400);
165  IUFillNumberVector(&FocuserSettingsNP, FocuserSettingsN, 1, getDeviceName(), "FOCUSER_SETTINGS", "Settings", FOCUS_TAB,
166  IP_RW, 60, IPS_IDLE);
167 
168  // Stepping
169  IUFillSwitch(&FocuserDriveS[STEP_FULL], "STEP_FULL", "Full", ISS_OFF);
170  IUFillSwitch(&FocuserDriveS[STEP_HALF], "STEP_HALF", "Half", ISS_ON);
171  IUFillSwitch(&FocuserDriveS[STEP_FORTH], "STEP_FORTH", "1/4", ISS_OFF);
172  IUFillSwitch(&FocuserDriveS[STEP_EIGHTH], "STEP_EIGHTH", "1/8", ISS_OFF);
173  IUFillSwitchVector(&FocuserDriveSP, FocuserDriveS, 4, getDeviceName(), "FOCUSER_DRIVE", "Microstepping", FOCUS_TAB,
174  IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
175 
179  serialConnection = new Connection::Serial(this);
180  serialConnection->registerHandshake([&]()
181  {
182  return Handshake();
183  });
184  registerConnection(serialConnection);
185 
186  return true;
187 }
188 
190 {
192 
193  if (isConnected())
194  {
195  m_HasExternalMotor = findExternalMotorController();
196 
197  if (m_HasExternalMotor)
198  {
199  getXMCStartupData();
201  syncDriverInfo();
202  }
203 
204  // Main Control
205  defineProperty(&QuadOutSP);
206  //defineProperty(&AdjOutSP);
207  defineProperty(&AdjOutVoltSP);
208  defineProperty(&PowerSensorsNP);
209  defineProperty(&PowerOnBootSP);
210  defineProperty(&RebootSP);
211  defineProperty(&PowerWarnLP);
212  defineProperty(&LedIndicatorSP);
213 
214  // Dew
215  defineProperty(&AutoDewSP);
216  defineProperty(&DewPWMNP);
217 
218  // Focuser
219  if (m_HasExternalMotor)
220  {
222  defineProperty(&FocuserSettingsNP);
223  defineProperty(&FocuserDriveSP);
224  }
225 
227 
228  // Firmware
229  defineProperty(&FirmwareTP);
230 
231  setupComplete = true;
232  }
233  else
234  {
235  // Main Control
236  deleteProperty(QuadOutSP.name);
237  //deleteProperty(AdjOutSP.name);
238  deleteProperty(AdjOutVoltSP.name);
239  deleteProperty(PowerSensorsNP.name);
240  deleteProperty(PowerOnBootSP.name);
241  deleteProperty(RebootSP.name);
242  deleteProperty(PowerWarnLP.name);
243  deleteProperty(LedIndicatorSP.name);
244 
245  // Dew
246  deleteProperty(AutoDewSP.name);
247  deleteProperty(DewPWMNP.name);
248 
249  if (m_HasExternalMotor)
250  {
252  deleteProperty(FocuserSettingsNP.name);
253  deleteProperty(FocuserDriveSP.name);
254  }
255 
257 
258  deleteProperty(FirmwareTP.name);
259 
260  setupComplete = false;
261  }
262 
263  return true;
264 }
265 
267 {
268  return "Pegasus PPBA";
269 }
270 
271 bool PegasusPPBA::Handshake()
272 {
273  int tty_rc = 0, nbytes_written = 0, nbytes_read = 0;
274  char command[PEGASUS_LEN] = {0}, response[PEGASUS_LEN] = {0};
275 
276  PortFD = serialConnection->getPortFD();
277 
278  LOG_DEBUG("CMD <P#>");
279 
280  tcflush(PortFD, TCIOFLUSH);
281  strncpy(command, "P#\n", PEGASUS_LEN);
282  if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
283  {
284  char errorMessage[MAXRBUF];
285  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
286  LOGF_ERROR("Serial write error: %s", errorMessage);
287  return false;
288  }
289 
290  // Try first with stopChar as the stop character
291  if ( (tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read)) != TTY_OK)
292  {
293  // Try 0xA as the stop character
294  if (tty_rc == TTY_OVERFLOW || tty_rc == TTY_TIME_OUT)
295  {
296  tcflush(PortFD, TCIOFLUSH);
297  tty_write_string(PortFD, command, &nbytes_written);
298  stopChar = 0xA;
299  tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read);
300  }
301 
302  if (tty_rc != TTY_OK)
303  {
304  char errorMessage[MAXRBUF];
305  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
306  LOGF_ERROR("Serial read error: %s", errorMessage);
307  return false;
308  }
309  }
310 
311  tcflush(PortFD, TCIOFLUSH);
312  response[nbytes_read - 1] = '\0';
313  LOGF_DEBUG("RES <%s>", response);
314 
315  setupComplete = false;
316 
317  return (!strcmp(response, "PPBA_OK") || !strcmp(response, "PPBM_OK"));
318 }
319 
320 bool PegasusPPBA::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
321 {
322  if (dev && !strcmp(dev, getDeviceName()))
323  {
324  // Quad 12V Power
325  if (!strcmp(name, QuadOutSP.name))
326  {
327  IUUpdateSwitch(&QuadOutSP, states, names, n);
328 
329  QuadOutSP.s = IPS_ALERT;
330  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
331  snprintf(cmd, PEGASUS_LEN, "P1:%d", QuadOutS[INDI_ENABLED].s == ISS_ON);
332  if (sendCommand(cmd, res))
333  {
334  QuadOutSP.s = !strcmp(cmd, res) ? IPS_OK : IPS_ALERT;
335  }
336 
337  IUResetSwitch(&QuadOutSP);
338  IDSetSwitch(&QuadOutSP, nullptr);
339  return true;
340  }
341 
342  // // Adjustable Power
343  // if (!strcmp(name, AdjOutSP.name))
344  // {
345  // IUUpdateSwitch(&AdjOutSP, states, names, n);
346 
347  // AdjOutSP.s = IPS_ALERT;
348  // char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
349  // snprintf(cmd, PEGASUS_LEN, "P2:%d", AdjOutS[INDI_ENABLED].s == ISS_ON);
350  // if (sendCommand(cmd, res))
351  // {
352  // AdjOutSP.s = !strcmp(cmd, res) ? IPS_OK : IPS_ALERT;
353  // }
354 
355  // IUResetSwitch(&AdjOutSP);
356  // IDSetSwitch(&AdjOutSP, nullptr);
357  // return true;
358  // }
359 
360  // Adjustable Voltage
361  if (!strcmp(name, AdjOutVoltSP.name))
362  {
363  int previous_index = IUFindOnSwitchIndex(&AdjOutVoltSP);
364  IUUpdateSwitch(&AdjOutVoltSP, states, names, n);
365  int target_index = IUFindOnSwitchIndex(&AdjOutVoltSP);
366  int adjv = 0;
367  switch(target_index)
368  {
369  case ADJOUT_OFF:
370  adjv = 0;
371  break;
372  case ADJOUT_3V:
373  adjv = 3;
374  break;
375  case ADJOUT_5V:
376  adjv = 5;
377  break;
378  case ADJOUT_8V:
379  adjv = 8;
380  break;
381  case ADJOUT_9V:
382  adjv = 9;
383  break;
384  case ADJOUT_12V:
385  adjv = 12;
386  break;
387  }
388 
389  AdjOutVoltSP.s = IPS_ALERT;
390  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
391  snprintf(cmd, PEGASUS_LEN, "P2:%d", adjv);
392  if (sendCommand(cmd, res))
393  AdjOutVoltSP.s = IPS_OK;
394  else
395  {
396  IUResetSwitch(&AdjOutVoltSP);
397  AdjOutVoltS[previous_index].s = ISS_ON;
398  AdjOutVoltSP.s = IPS_ALERT;
399  }
400 
401  IDSetSwitch(&AdjOutVoltSP, nullptr);
402  return true;
403  }
404 
405  // Reboot
406  if (!strcmp(name, RebootSP.name))
407  {
408  RebootSP.s = reboot() ? IPS_OK : IPS_ALERT;
409  IDSetSwitch(&RebootSP, nullptr);
410  LOG_INFO("Rebooting device...");
411  return true;
412  }
413 
414  // LED Indicator
415  if (!strcmp(name, LedIndicatorSP.name))
416  {
417  IUUpdateSwitch(&LedIndicatorSP, states, names, n);
418  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
419  snprintf(cmd, PEGASUS_LEN, "PL:%d", LedIndicatorS[INDI_ENABLED].s == ISS_ON);
420  if (sendCommand(cmd, res))
421  {
422  LedIndicatorSP.s = !strcmp(cmd, res) ? IPS_OK : IPS_ALERT;
423  }
424  IDSetSwitch(&LedIndicatorSP, nullptr);
425  saveConfig(true, LedIndicatorSP.name);
426  return true;
427  }
428 
429  // Power on boot
430  if (!strcmp(name, PowerOnBootSP.name))
431  {
432  IUUpdateSwitch(&PowerOnBootSP, states, names, n);
433  PowerOnBootSP.s = setPowerOnBoot() ? IPS_OK : IPS_ALERT;
434  IDSetSwitch(&PowerOnBootSP, nullptr);
435  saveConfig(true, PowerOnBootSP.name);
436  return true;
437  }
438 
439  // Auto Dew
440  if (!strcmp(name, AutoDewSP.name))
441  {
442  int prevIndex = IUFindOnSwitchIndex(&AutoDewSP);
443  IUUpdateSwitch(&AutoDewSP, states, names, n);
444  if (setAutoDewEnabled(AutoDewS[INDI_ENABLED].s == ISS_ON))
445  {
446  AutoDewSP.s = IPS_OK;
447  }
448  else
449  {
450  IUResetSwitch(&AutoDewSP);
451  AutoDewS[prevIndex].s = ISS_ON;
452  AutoDewSP.s = IPS_ALERT;
453  }
454 
455  IDSetSwitch(&AutoDewSP, nullptr);
456  return true;
457  }
458 
459  // Microstepping
460  if (!strcmp(name, FocuserDriveSP.name))
461  {
462  int prevIndex = IUFindOnSwitchIndex(&FocuserDriveSP);
463  IUUpdateSwitch(&FocuserDriveSP, states, names, n);
464  if (setFocuserMicrosteps(IUFindOnSwitchIndex(&FocuserDriveSP) + 1))
465  {
466  FocuserDriveSP.s = IPS_OK;
467  }
468  else
469  {
470  IUResetSwitch(&FocuserDriveSP);
471  FocuserDriveS[prevIndex].s = ISS_ON;
472  FocuserDriveSP.s = IPS_ALERT;
473  }
474 
475  IDSetSwitch(&FocuserDriveSP, nullptr);
476  return true;
477  }
478 
479  if (strstr(name, "FOCUS"))
480  return FI::processSwitch(dev, name, states, names, n);
481  }
482 
483  return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
484 }
485 
486 bool PegasusPPBA::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
487 {
488  if (dev && !strcmp(dev, getDeviceName()))
489  {
490  // Dew PWM
491  if (!strcmp(name, DewPWMNP.name))
492  {
493  bool rc1 = false, rc2 = false;
494  for (int i = 0; i < n; i++)
495  {
496  if (!strcmp(names[i], DewPWMN[DEW_PWM_A].name))
497  rc1 = setDewPWM(3, static_cast<uint8_t>(values[i] / 100.0 * 255.0));
498  else if (!strcmp(names[i], DewPWMN[DEW_PWM_B].name))
499  rc2 = setDewPWM(4, static_cast<uint8_t>(values[i] / 100.0 * 255.0));
500  }
501 
502  DewPWMNP.s = (rc1 && rc2) ? IPS_OK : IPS_ALERT;
503  if (DewPWMNP.s == IPS_OK)
504  IUUpdateNumber(&DewPWMNP, values, names, n);
505  IDSetNumber(&DewPWMNP, nullptr);
506  return true;
507  }
508 
509  // Focuser Settings
510  if (!strcmp(name, FocuserSettingsNP.name))
511  {
512  if (setFocuserMaxSpeed(values[0]))
513  {
514  FocuserSettingsN[0].value = values[0];
515  FocuserSettingsNP.s = IPS_OK;
516  }
517  else
518  {
519  FocuserSettingsNP.s = IPS_ALERT;
520  }
521 
522  IDSetNumber(&FocuserSettingsNP, nullptr);
523  return true;
524  }
525 
526  if (strstr(name, "FOCUS_"))
527  return FI::processNumber(dev, name, values, names, n);
528 
529  if (strstr(name, "WEATHER_"))
530  return WI::processNumber(dev, name, values, names, n);
531  }
532  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
533 }
534 
535 bool PegasusPPBA::sendCommand(const char * cmd, char * res)
536 {
537  int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
538  char command[PEGASUS_LEN] = {0};
539  LOGF_DEBUG("CMD <%s>", cmd);
540 
541  for (int i = 0; i < 2; i++)
542  {
543  tcflush(PortFD, TCIOFLUSH);
544  snprintf(command, PEGASUS_LEN, "%s\n", cmd);
545  if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
546  continue;
547 
548  if (!res)
549  {
550  tcflush(PortFD, TCIOFLUSH);
551  return true;
552  }
553 
554  if ( (tty_rc = tty_nread_section(PortFD, res, PEGASUS_LEN, stopChar, PEGASUS_TIMEOUT, &nbytes_read)) != TTY_OK
555  || nbytes_read == 1)
556  continue;
557 
558  tcflush(PortFD, TCIOFLUSH);
559  res[nbytes_read - 1] = '\0';
560  LOGF_DEBUG("RES <%s>", res);
561  return true;
562  }
563 
564  if (tty_rc != TTY_OK)
565  {
566  char errorMessage[MAXRBUF];
567  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
568  LOGF_ERROR("Serial error: %s", errorMessage);
569  }
570 
571  return false;
572 }
573 
574 bool PegasusPPBA::findExternalMotorController()
575 {
576  char res[PEGASUS_LEN] = {0};
577  if (!sendCommand("XS", res))
578  return false;
579 
580  // 200 XMC present
581  return strstr(res, "200");
582 }
583 
584 bool PegasusPPBA::setAutoDewEnabled(bool enabled)
585 {
586  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
587  snprintf(cmd, PEGASUS_LEN, "PD:%d", enabled ? 1 : 0);
588  if (sendCommand(cmd, res))
589  {
590  return (!strcmp(res, cmd));
591  }
592 
593  return false;
594 }
595 
596 bool PegasusPPBA::setPowerOnBoot()
597 {
598  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
599  snprintf(cmd, PEGASUS_LEN, "PE:%d%d%d%d", PowerOnBootS[0].s == ISS_ON ? 1 : 0,
600  PowerOnBootS[1].s == ISS_ON ? 1 : 0,
601  PowerOnBootS[2].s == ISS_ON ? 1 : 0,
602  PowerOnBootS[3].s == ISS_ON ? 1 : 0);
603  if (sendCommand(cmd, res))
604  {
605  return (!strcmp(res, "PE:1"));
606  }
607 
608  return false;
609 }
610 
611 bool PegasusPPBA::setDewPWM(uint8_t id, uint8_t value)
612 {
613  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
614  snprintf(cmd, PEGASUS_LEN, "P%d:%03d", id, value);
615  snprintf(expected, PEGASUS_LEN, "P%d:%d", id, value);
616  if (sendCommand(cmd, res))
617  {
618  return (!strcmp(res, expected));
619  }
620 
621  return false;
622 }
623 
625 {
627  if (m_HasExternalMotor)
628  {
630  IUSaveConfigNumber(fp, &FocuserSettingsNP);
631  IUSaveConfigSwitch(fp, &FocuserDriveSP);
632  }
634  IUSaveConfigSwitch(fp, &AutoDewSP);
635  return true;
636 }
637 
639 {
640  if (!isConnected() || setupComplete == false)
641  {
643  return;
644  }
645 
646  getSensorData();
647  getConsumptionData();
648  getMetricsData();
649 
650  if (m_HasExternalMotor)
651  queryXMC();
652 
654 }
655 
656 bool PegasusPPBA::sendFirmware()
657 {
658  char res[PEGASUS_LEN] = {0};
659  if (sendCommand("PV", res))
660  {
661  LOGF_INFO("Detected firmware %s", res);
662  IUSaveText(&FirmwareT[FIRMWARE_VERSION], res);
663  IDSetText(&FirmwareTP, nullptr);
664  return true;
665  }
666 
667  return false;
668 }
669 
670 bool PegasusPPBA::getSensorData()
671 {
672  char res[PEGASUS_LEN] = {0};
673  if (sendCommand("PA", res))
674  {
675  std::vector<std::string> result = split(res, ":");
676  if (result.size() < PA_N)
677  {
678  LOG_WARN("Received wrong number of detailed sensor data. Retrying...");
679  return false;
680  }
681 
682  if (result == lastSensorData)
683  return true;
684 
685  // Power Sensors
686  PowerSensorsN[SENSOR_VOLTAGE].value = std::stod(result[PA_VOLTAGE]);
687  PowerSensorsN[SENSOR_CURRENT].value = std::stod(result[PA_CURRENT]) / 65.0;
688  PowerSensorsNP.s = IPS_OK;
689  if (lastSensorData[PA_VOLTAGE] != result[PA_VOLTAGE] || lastSensorData[PA_CURRENT] != result[PA_CURRENT])
690  IDSetNumber(&PowerSensorsNP, nullptr);
691 
692  // Environment Sensors
693  setParameterValue("WEATHER_TEMPERATURE", std::stod(result[PA_TEMPERATURE]));
694  setParameterValue("WEATHER_HUMIDITY", std::stod(result[PA_HUMIDITY]));
695  setParameterValue("WEATHER_DEWPOINT", std::stod(result[PA_DEW_POINT]));
696  if (lastSensorData[PA_TEMPERATURE] != result[PA_TEMPERATURE] ||
697  lastSensorData[PA_HUMIDITY] != result[PA_HUMIDITY] ||
698  lastSensorData[PA_DEW_POINT] != result[PA_DEW_POINT])
699  {
701  IDSetLight(&critialParametersLP, nullptr);
703  IDSetNumber(&ParametersNP, nullptr);
704  }
705 
706  // Power Status
707  QuadOutS[INDI_ENABLED].s = (std::stoi(result[PA_PORT_STATUS]) == 1) ? ISS_ON : ISS_OFF;
708  QuadOutS[INDI_DISABLED].s = (std::stoi(result[PA_PORT_STATUS]) == 1) ? ISS_OFF : ISS_ON;
709  QuadOutSP.s = (std::stoi(result[6]) == 1) ? IPS_OK : IPS_IDLE;
710  if (lastSensorData[PA_PORT_STATUS] != result[PA_PORT_STATUS])
711  IDSetSwitch(&QuadOutSP, nullptr);
712 
713  // Adjustable Power Status
714  // AdjOutS[INDI_ENABLED].s = (std::stoi(result[PA_ADJ_STATUS]) == 1) ? ISS_ON : ISS_OFF;
715  // AdjOutS[INDI_DISABLED].s = (std::stoi(result[PA_ADJ_STATUS]) == 1) ? ISS_OFF : ISS_ON;
716  // AdjOutSP.s = (std::stoi(result[PA_ADJ_STATUS]) == 1) ? IPS_OK : IPS_IDLE;
717  // if (lastSensorData[PA_ADJ_STATUS] != result[PA_ADJ_STATUS])
718  // IDSetSwitch(&AdjOutSP, nullptr);
719 
720  // Adjustable Power Status
721  IUResetSwitch(&AdjOutVoltSP);
722  if (std::stoi(result[PA_ADJ_STATUS]) == 0)
723  AdjOutVoltS[ADJOUT_OFF].s = ISS_ON;
724  else
725  {
726  AdjOutVoltS[ADJOUT_3V].s = (std::stoi(result[PA_PWRADJ]) == 3) ? ISS_ON : ISS_OFF;
727  AdjOutVoltS[ADJOUT_5V].s = (std::stoi(result[PA_PWRADJ]) == 5) ? ISS_ON : ISS_OFF;
728  AdjOutVoltS[ADJOUT_8V].s = (std::stoi(result[PA_PWRADJ]) == 8) ? ISS_ON : ISS_OFF;
729  AdjOutVoltS[ADJOUT_9V].s = (std::stoi(result[PA_PWRADJ]) == 9) ? ISS_ON : ISS_OFF;
730  AdjOutVoltS[ADJOUT_12V].s = (std::stoi(result[PA_PWRADJ]) == 12) ? ISS_ON : ISS_OFF;
731  }
732  if (lastSensorData[PA_PWRADJ] != result[PA_PWRADJ] || lastSensorData[PA_ADJ_STATUS] != result[PA_ADJ_STATUS])
733  IDSetSwitch(&AdjOutVoltSP, nullptr);
734 
735  // Power Warn
736  PowerWarnL[0].s = (std::stoi(result[PA_PWR_WARN]) == 1) ? IPS_ALERT : IPS_OK;
737  PowerWarnLP.s = (std::stoi(result[PA_PWR_WARN]) == 1) ? IPS_ALERT : IPS_OK;
738  if (lastSensorData[PA_PWR_WARN] != result[PA_PWR_WARN])
739  IDSetLight(&PowerWarnLP, nullptr);
740 
741  // Dew PWM
742  DewPWMN[0].value = std::stod(result[PA_DEW_1]) / 255.0 * 100.0;
743  DewPWMN[1].value = std::stod(result[PA_DEW_2]) / 255.0 * 100.0;
744  if (lastSensorData[PA_DEW_1] != result[PA_DEW_1] || lastSensorData[PA_DEW_2] != result[PA_DEW_2])
745  IDSetNumber(&DewPWMNP, nullptr);
746 
747  // Auto Dew
748  AutoDewS[INDI_DISABLED].s = (std::stoi(result[PA_AUTO_DEW]) == 1) ? ISS_OFF : ISS_ON;
749  AutoDewS[INDI_ENABLED].s = (std::stoi(result[PA_AUTO_DEW]) == 1) ? ISS_ON : ISS_OFF;
750  AutoDewSP.s = (std::stoi(result[PA_AUTO_DEW]) == 1) ? IPS_OK : IPS_IDLE;
751  if (lastSensorData[PA_AUTO_DEW] != result[PA_AUTO_DEW])
752  IDSetSwitch(&AutoDewSP, nullptr);
753 
754  lastSensorData = result;
755 
756  return true;
757  }
758 
759  return false;
760 }
761 
762 bool PegasusPPBA::getConsumptionData()
763 {
764  char res[PEGASUS_LEN] = {0};
765  if (sendCommand("PS", res))
766  {
767  std::vector<std::string> result = split(res, ":");
768  if (result.size() < PS_N)
769  {
770  LOG_WARN("Received wrong number of detailed consumption data. Retrying...");
771  return false;
772  }
773 
774  if (result == lastConsumptionData)
775  return true;
776 
777  // Power Sensors
778  PowerSensorsN[SENSOR_AVG_AMPS].value = std::stod(result[PS_AVG_AMPS]);
779  PowerSensorsN[SENSOR_AMP_HOURS].value = std::stod(result[PS_AMP_HOURS]);
780  PowerSensorsN[SENSOR_WATT_HOURS].value = std::stod(result[PS_WATT_HOURS]);
781  PowerSensorsNP.s = IPS_OK;
782  if (lastConsumptionData[PS_AVG_AMPS] != result[PS_AVG_AMPS] || lastConsumptionData[PS_AMP_HOURS] != result[PS_AMP_HOURS]
783  || lastConsumptionData[PS_WATT_HOURS] != result[PS_WATT_HOURS])
784  IDSetNumber(&PowerSensorsNP, nullptr);
785 
786  lastConsumptionData = result;
787 
788  return true;
789  }
790 
791  return false;
792 }
793 
794 bool PegasusPPBA::getMetricsData()
795 {
796  char res[PEGASUS_LEN] = {0};
797  if (sendCommand("PC", res))
798  {
799  std::vector<std::string> result = split(res, ":");
800  if (result.size() < PC_N)
801  {
802  LOG_WARN("Received wrong number of detailed metrics data. Retrying...");
803  return false;
804  }
805 
806  if (result == lastMetricsData)
807  return true;
808 
809  // Power Sensors
810  PowerSensorsN[SENSOR_TOTAL_CURRENT].value = std::stod(result[PC_TOTAL_CURRENT]);
811  PowerSensorsN[SENSOR_12V_CURRENT].value = std::stod(result[PC_12V_CURRENT]);
812  PowerSensorsN[SENSOR_DEWA_CURRENT].value = std::stod(result[PC_DEWA_CURRENT]);
813  PowerSensorsN[SENSOR_DEWB_CURRENT].value = std::stod(result[PC_DEWB_CURRENT]);
814  PowerSensorsNP.s = IPS_OK;
815  if (lastMetricsData[PC_TOTAL_CURRENT] != result[PC_TOTAL_CURRENT] ||
816  lastMetricsData[PC_12V_CURRENT] != result[PC_12V_CURRENT] ||
817  lastMetricsData[PC_DEWA_CURRENT] != result[PC_DEWA_CURRENT] ||
818  lastMetricsData[PC_DEWB_CURRENT] != result[PC_DEWB_CURRENT])
819  IDSetNumber(&PowerSensorsNP, nullptr);
820 
821  std::chrono::milliseconds uptime(std::stol(result[PC_UPTIME]));
822  using dhours = std::chrono::duration<double, std::ratio<3600>>;
823  std::stringstream ss;
824  ss << std::fixed << std::setprecision(3) << dhours(uptime).count();
825  IUSaveText(&FirmwareT[FIRMWARE_UPTIME], ss.str().c_str());
826  IDSetText(&FirmwareTP, nullptr);
827 
828  lastMetricsData = result;
829 
830  return true;
831  }
832 
833  return false;
834 }
835 // Device Control
836 bool PegasusPPBA::reboot()
837 {
838  return sendCommand("PF", nullptr);
839 }
840 
845 {
846  char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
847  snprintf(cmd, PEGASUS_LEN, "XS:3#%u", targetTicks);
848  return (sendCommand(cmd, res) ? IPS_BUSY : IPS_ALERT);
849 }
850 
855 {
856  return MoveAbsFocuser(dir == FOCUS_INWARD ? FocusAbsPosN[0].value - ticks : FocusAbsPosN[0].value + ticks);
857 }
858 
863 {
864  return sendCommand("XS:6", nullptr);
865 }
866 
870 bool PegasusPPBA::ReverseFocuser(bool enabled)
871 {
872  char cmd[PEGASUS_LEN] = {0};
873  snprintf(cmd, PEGASUS_LEN, "XS:8#%d", enabled ? 1 : 0);
874  return sendCommand(cmd, nullptr);
875 }
876 
880 bool PegasusPPBA::SyncFocuser(uint32_t ticks)
881 {
882  char cmd[PEGASUS_LEN] = {0};
883  snprintf(cmd, PEGASUS_LEN, "XS:5#%u", ticks);
884  return sendCommand(cmd, nullptr);
885 }
886 
891 {
892  char cmd[PEGASUS_LEN] = {0};
893  snprintf(cmd, PEGASUS_LEN, "XS:10#%d", steps);
894  return sendCommand(cmd, nullptr);
895 }
896 
900 bool PegasusPPBA::setFocuserMaxSpeed(uint16_t maxSpeed)
901 {
902  char cmd[PEGASUS_LEN] = {0};
903  snprintf(cmd, PEGASUS_LEN, "XS:7#%d", maxSpeed);
904  return sendCommand(cmd, nullptr);
905 }
906 
907 bool PegasusPPBA::setFocuserMicrosteps(int value)
908 {
909  char cmd[PEGASUS_LEN] = {0};
910  snprintf(cmd, PEGASUS_LEN, "XS:9#%d", value);
911  return sendCommand(cmd, nullptr);
912 }
913 
918 {
919  char cmd[PEGASUS_LEN] = {0};
920  snprintf(cmd, PEGASUS_LEN, "XS:8#%d", enabled ? 1 : 0);
921  return sendCommand(cmd, nullptr);
922 }
923 
927 bool PegasusPPBA::getXMCStartupData()
928 {
929  char res[PEGASUS_LEN] = {0};
930 
931  // Position
932  if (sendCommand("XS:2", res))
933  {
934  uint32_t position = 0;
935  sscanf(res, "%*[^#]#%d", &position);
936  FocusAbsPosN[0].value = position;
937  }
938 
939  // Max speed
940  if (sendCommand("XS:7", res))
941  {
942  uint32_t speed = 0;
943  sscanf(res, "%*[^#]#%d", &speed);
944  FocuserSettingsN[0].value = speed;
945  }
946 
947  return true;
948 }
949 
953 void PegasusPPBA::queryXMC()
954 {
955  char res[PEGASUS_LEN] = {0};
956  uint32_t position = 0;
957  uint32_t motorRunning = 0;
958 
959  // Get Motor Status
960  if (sendCommand("XS:1", res))
961  sscanf(res, "%*[^#]#%d", &motorRunning);
962  // Get Position
963  if (sendCommand("XS:2", res))
964  sscanf(res, "%*[^#]#%d", &position);
965 
966  uint32_t lastPosition = FocusAbsPosN[0].value;
967  FocusAbsPosN[0].value = position;
968 
969  if (FocusAbsPosNP.s == IPS_BUSY && motorRunning == 0)
970  {
973  IDSetNumber(&FocusAbsPosNP, nullptr);
974  IDSetNumber(&FocusRelPosNP, nullptr);
975  }
976  else if (lastPosition != position)
977  IDSetNumber(&FocusAbsPosNP, nullptr);
978 
979 }
983 std::vector<std::string> PegasusPPBA::split(const std::string &input, const std::string &regex)
984 {
985  // passing -1 as the submatch index parameter performs splitting
986  std::regex re(regex);
987  std::sregex_token_iterator
988  first{input.begin(), input.end(), re, -1},
989  last;
990  return {first, last};
991 }
992 
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
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)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
void syncDriverInfo()
syncDriverInfo sends the current driver information to the client.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
uint16_t getDriverInterface() const
Provides interface to implement focuser functionality.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
void initProperties(const char *groupName)
Initilize focuser properties. It is recommended to call this function within initProperties() of your...
bool saveConfigItems(FILE *fp)
saveConfigItems save focuser properties defined in the interface in config file
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process focus number properties.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process focus switch properties.
Provides interface to implement weather reporting functionality.
bool syncCriticalParameters()
updateWeatherState Send update weather state to client
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
bool setCriticalParameter(std::string param)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
ILightVectorProperty critialParametersLP
INumberVectorProperty ParametersNP
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning)
addParameter Add a physical weather measurable parameter to the weather driver. The weather value has...
void initProperties(const char *statusGroup, const char *paramsGroup)
Initilize focuser properties. It is recommended to call this function within initProperties() of your...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
const char * getDefaultName() override
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
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_1OFMANY
Definition: indiapi.h:173
@ ISR_NOFMANY
Definition: indiapi.h:175
@ ISR_ATMOST1
Definition: indiapi.h:174
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
@ TTY_TIME_OUT
Definition: indicom.h:154
@ TTY_OVERFLOW
Definition: indicom.h:158
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
void IUFillLight(ILight *lp, const char *name, const char *label, IPState s)
Assign attributes for a light property. The light's auxiliary elements will be set to NULL.
Definition: indidevapi.c:169
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 IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char *dev, const char *name, const char *label, const char *group, IPState s)
Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:255
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
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 IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
Definition: indidriver.c:1251
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 IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:421
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250