Instrument Neutral Distributed Interface INDI  2.0.2
uranusmeteo.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2022 Jasem Mutlaq. All rights reserved.
3 
4  Pegasus Uranus Meteo Sensor 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 "uranusmeteo.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 UranusMeteo.
35 static std::unique_ptr<UranusMeteo> ppba(new UranusMeteo());
36 
41 {
42  setVersion(1, 0);
43  m_SkyQualityUpdateTimer.setInterval(60000);
44  m_SkyQualityUpdateTimer.callOnTimeout(std::bind(&UranusMeteo::measureSkyQuality, this));
45 }
46 
51 {
53 
55 
56  WI::initProperties(MAIN_CONTROL_TAB, ENVIRONMENT_TAB);
57 
58  // To distinguish them from GPS properties.
59  WI::UpdatePeriodNP.setLabel("Weather Update");
60  WI::RefreshSP.setLabel("Weahter Refresh");
61 
63 
67  SensorNP[AmbientTemperature].fill("AmbientTemperature", "AmbientTemperature", "%.2f", -100, 100, 10, 0);
68  SensorNP[RelativeHumidity].fill("RelativeHumidity", "RelativeHumidity", "%.2f%", 0, 100, 10, 0);
69  SensorNP[DewPoint].fill("DewPoint", "DewPoint (C)", "%.2f", 0, 100, 10, 0);
70  SensorNP[AbsolutePressure].fill("AbsolutePressure", "AbsolutePressure (hPA)", "%.2f", 0, 100, 10, 0);
71  SensorNP[RelativePressure].fill("RelativePressure", "RelativePressure (hPA)", "%.2f", 0, 100, 10, 0);
72  SensorNP[BarometricAltitude].fill("BarometricAltitude", "BarometricAltitude (m)", "%.2f", 0, 100, 10, 0);
73  SensorNP[SkyTemperature].fill("SkyTemperature", "SkyTemperature (C)", "%.2f", 0, 100, 10, 0);
74  SensorNP[InfraredTemperature].fill("InfraredTemperature", "InfraredTemperature (C)", "%.2f", 0, 100, 10, 0);
75  SensorNP[BatteryUsage].fill("BatteryUsage", "BatteryUsage", "%.2f%", 0, 100, 10, 0);
76  SensorNP[BatteryVoltage].fill("BatteryVoltage", "BatteryVoltage", "%.2f", 0, 100, 10, 0);
77  SensorNP.fill(getDeviceName(), "SENSORS", "Sensors", SENSORS_TAB, IP_RO, 60, IPS_IDLE);
78 
82  CloudsNP[TemperatureDifference].fill("TemperatureDifference", "Temperature Difference (C)", "%.2f", -1000, 1000, 10, 0);
83  CloudsNP[CloudIndex].fill("CloudIndex", "Cloud Coverage (%)", "%.2f", 0, 100, 10, 0);
84  CloudsNP[CloudSkyTemperature].fill("CloudSkyTemperature", "Sky Temperature (C)", "%.2f", -1000, 1000, 10, 0);
85  CloudsNP[CloudAmbientTemperature].fill("CloudAmbientTemperature", "Ambient Temperature (C)", "%.2f", -1000, 1000, 10, 0);
86  CloudsNP[InfraredEmissivity].fill("InfraredEmissivity", "Infrared Emissivity", "%.2f", 0, 1, 0.1, 0);
87  CloudsNP.fill(getDeviceName(), "CLOUDS", "Clouds", CLOUDS_TAB, IP_RO, 60, IPS_IDLE);
88 
92  SkyQualityNP[MPAS].fill("MPAS", "MPAS (mag/arcsec^2)", "%.2f", 0, 30, 10, 0);
93  SkyQualityNP[NELM].fill("NELM", "Naked Eye Llimit (mag)", "%.2f", 0, 100, 10, 0);
94  SkyQualityNP[FullSpectrum].fill("FullSpectrum", "Full Spectrum", "%.2f", -1000, 1000, 10, 0);
95  SkyQualityNP[VisualSpectrum].fill("VisualSpectrum", "Visual Spectrum", "%.2f", -1000, 1000, 10, 0);
96  SkyQualityNP[InfraredSpectrum].fill("InfraredSpectrum", "Infrared Spectrum", "%.2f", 0, 1, 0.1, 0);
97  SkyQualityNP.fill(getDeviceName(), "SKYQUALITY", "Sky Quality", SKYQUALITY_TAB, IP_RO, 60, IPS_IDLE);
98 
99  SkyQualityUpdateNP[0].fill("VALUE", "Period (s)", "%.f", 0, 3600, 60, 60);
100  SkyQualityUpdateNP.fill(getDeviceName(), "SKYQUALITY_TIMER", "Update", SKYQUALITY_TAB, IP_RW, 60, IPS_IDLE);
101 
105  GPSNP[GPSFix].fill("GPSFix", "GPS Fix", "%.f", 0, 3, 1, 0);
106  GPSNP[GPSTime].fill("GPSTime", "Unix Time", "%.f", 0, 1e9, 10, 0);
107  GPSNP[UTCOffset].fill("UTCOffset", "UTC Offset", "%.2f", -12, 12, 1, 0);
108  GPSNP[Latitude].fill("Latitude", "Latitude", "%.2f", -90, 90, 10, 0);
109  GPSNP[Longitude].fill("Longitude", "Longitude", "%.2f", -180, 180, 10, 0);
110  GPSNP[SatelliteNumber].fill("SatelliteNumber", "Sat. #", "%.f", 0, 30, 10, 0);
111  GPSNP[GPSSpeed].fill("GPSSpeed", "Speed (kph)", "%.2f", 0, 30, 10, 0);
112  GPSNP[GPSBearing].fill("GPSBearing", "Bearing (deg)", "%.2f", 0, 360, 10, 0);
113  GPSNP.fill(getDeviceName(), "GPS", "GPS", GPS_TAB, IP_RO, 60, IPS_IDLE);
114 
118  addParameter("WEATHER_CLOUD", "Cloud (%)", 0, 85, 15);
119  addParameter("WEATHER_MPAS", "MPAS (mag/arcsec^2)", 1, 30, 15);
120  addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -20, 50, 15);
121  addParameter("WEATHER_HUMIDITY", "Humidity (%)", 0, 75, 15);
122 
123  setCriticalParameter("WEATHER_CLOUD");
124  setCriticalParameter("WEATHER_TEMPERATURE");
125  setCriticalParameter("WEATHER_HUMIDITY");
126 
131  serialConnection = new Connection::Serial(this);
133  serialConnection->registerHandshake([&]()
134  {
135  return Handshake();
136  });
137  registerConnection(serialConnection);
138 
139  return true;
140 }
141 
146 {
148 
149  if (isConnected())
150  {
151  defineProperty(SensorNP);
152  defineProperty(CloudsNP);
153 
154  defineProperty(SkyQualityNP);
155  defineProperty(SkyQualityUpdateNP);
156 
157  defineProperty(GPSNP);
158 
160  m_SetupComplete = true;
161 
162  readSensors();
163  readClouds();
164 
165  measureSkyQuality();
166  }
167  else
168  {
169 
170  deleteProperty(SensorNP);
171  deleteProperty(CloudsNP);
172 
173  deleteProperty(SkyQualityNP);
174  deleteProperty(SkyQualityUpdateNP);
175 
176  deleteProperty(GPSNP);
177 
179  m_SetupComplete = false;
180  }
181 
182  return true;
183 }
184 
189 {
190  return "Uranus Meteo Sensor";
191 }
192 
196 bool UranusMeteo::Handshake()
197 {
198  PortFD = serialConnection->getPortFD();
199  m_SetupComplete = false;
200  char response[PEGASUS_LEN] = {0};
201 
202  if (sendCommand("M#", response))
203  return (!strcmp(response, "MS_OK"));
204 
205  return false;
206 }
207 
212 {
213  char response[PEGASUS_LEN] = {0};
214 
215  if (sendCommand("GP", response))
216  {
217  std::vector<std::string> result = split(response + 3, ":");
218 
219  if (result == m_GPS)
220  return IPS_OK;
221 
222  m_Sensors = result;
223 
224  try
225  {
226  GPSNP[GPSFix].setValue(std::stod(result[GPSFix]));
227  GPSNP[GPSTime].setValue(std::stod(result[GPSTime]));
228  GPSNP[UTCOffset].setValue(std::stod(result[UTCOffset]));
229  GPSNP[Latitude].setValue(std::stod(result[Latitude]));
230  GPSNP[Longitude].setValue(std::stod(result[Longitude]));
231  GPSNP[SatelliteNumber].setValue(std::stod(result[SatelliteNumber]));
232  GPSNP[GPSSpeed].setValue(std::stod(result[GPSSpeed]));
233  GPSNP[GPSBearing].setValue(std::stod(result[GPSBearing]));
234 
235  GPSNP.setState(IPS_OK);
236  GPSNP.apply();
237 
238  if (GPSNP[GPSFix].getValue() < 3)
239  return IPS_BUSY;
240 
241  LocationNP[LOCATION_LATITUDE].value = GPSNP[Latitude].getValue();
242  LocationNP[LOCATION_LONGITUDE].value = GPSNP[Longitude].getValue();
243  // 2017-11-15 Jasem: INDI Longitude is 0 to 360 East+
244  if (LocationNP[LOCATION_LONGITUDE].value < 0)
245  LocationNP[LOCATION_LONGITUDE].value += 360;
246 
247  LocationNP[LOCATION_ELEVATION].value = SensorNP[BarometricAltitude].getValue();
248 
249  // Get GPS Time
250  char ts[32] = {0};
251  time_t raw_time = GPSNP[GPSTime].getValue();
252 
253  // Convert to UTC
254  // JM 2022.12.28: Uranus returns LOCAL TIME, not UTC.
255  struct tm *local = localtime(&raw_time);
256  // Get UTC Offset
257  auto utcOffset = local->tm_gmtoff / 3600.0;
258  // Convert to UTC time
259  time_t utcTime = raw_time - utcOffset * 3600.0;
260  // Get tm struct in UTC
261  struct tm *utc = gmtime(&utcTime);
262  // Format it
263  strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", utc);
264  IUSaveText(&TimeTP[0], ts);
265 
266  snprintf(ts, sizeof(ts), "%.2f", utcOffset);
267  IUSaveText(&TimeTP[1], ts);
268 
269  // Set UTC offset in device
270  char command[PEGASUS_LEN] = {0};
271  snprintf(command, PEGASUS_LEN, "C3:%d", static_cast<int>(utcOffset));
272  sendCommand(command, response);
273 
274  return IPS_OK;
275  }
276  catch(...)
277  {
278  LOGF_WARN("Failed to process sensor response: %s (%d bytes)", response, strlen(response));
279  return IPS_ALERT;
280  }
281  }
282 
283  return IPS_ALERT;
284 }
285 
290 {
291  setParameterValue("WEATHER_TEMPERATURE", SensorNP[AmbientTemperature].getValue());
292  setParameterValue("WEATHER_HUMIDITY", SensorNP[RelativeHumidity].getValue());
293  setParameterValue("WEATHER_CLOUD", CloudsNP[CloudIndex].getValue());
294  setParameterValue("WEATHER_MPAS", SkyQualityNP[MPAS].getValue());
295  return IPS_OK;
296 }
297 
301 bool UranusMeteo::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
302 {
303  if (dev && !strcmp(dev, getDeviceName()))
304  {
305  if (processSwitch(dev, name, states, names, n))
306  return true;
307  }
308 
309  return INDI::GPS::ISNewSwitch(dev, name, states, names, n);
310 }
311 
315 bool UranusMeteo::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
316 {
317  if (dev && !strcmp(dev, getDeviceName()))
318  {
319  // Sky Quality Update
320  if (SkyQualityUpdateNP.isNameMatch(name))
321  {
322  SkyQualityUpdateNP.update(values, names, n);
323  auto value = SkyQualityUpdateNP[0].getValue();
324  if (value > 0)
325  {
326  m_SkyQualityUpdateTimer.start(value * 1000);
327  SkyQualityUpdateNP.setState(IPS_OK);
328  }
329  else
330  {
331  LOG_INFO("Sky Quality Update is disabled.");
332  SkyQualityUpdateNP.setState(IPS_IDLE);
333  }
334  SkyQualityUpdateNP.apply();
335  return true;
336  }
337 
338  if (processNumber(dev, name, values, names, n))
339  return true;
340  }
341 
342  return INDI::GPS::ISNewNumber(dev, name, values, names, n);
343 }
344 
349 {
350  if (!isConnected() || m_SetupComplete == false)
351  {
353  return;
354  }
355 
356  readSensors();
357  readClouds();
358 
360 }
361 
366 {
369  SkyQualityUpdateNP.save(fp);
370  return true;
371 }
372 
376 bool UranusMeteo::readSensors()
377 {
378  char response[PEGASUS_LEN] = {0};
379 
380  if (sendCommand("MA", response))
381  {
382  std::vector<std::string> result = split(response + 6, ":");
383 
384  if (result == m_Sensors)
385  return true;
386 
387  m_Sensors = result;
388 
389  try
390  {
391  SensorNP[AmbientTemperature].setValue(std::stod(result[AmbientTemperature]));
392  SensorNP[RelativeHumidity].setValue(std::stod(result[RelativeHumidity]));
393  SensorNP[DewPoint].setValue(std::stod(result[DewPoint]));
394  SensorNP[AbsolutePressure].setValue(std::stod(result[AbsolutePressure]));
395  SensorNP[BarometricAltitude].setValue(std::stod(result[BarometricAltitude]));
396  SensorNP[SkyTemperature].setValue(std::stod(result[SkyTemperature]));
397  SensorNP[InfraredTemperature].setValue(std::stod(result[InfraredTemperature]));
398  SensorNP[BatteryUsage].setValue(std::stod(result[BatteryUsage]));
399  SensorNP[BatteryVoltage].setValue(std::stod(result[BatteryVoltage]));
400 
401  SensorNP.setState(IPS_OK);
402  SensorNP.apply();
403  return true;
404  }
405  catch(...)
406  {
407  LOGF_WARN("Failed to process sensor response: %s (%d bytes)", response, strlen(response));
408  return false;
409  }
410  }
411 
412  return false;
413 }
414 
418 bool UranusMeteo::readSkyQuality()
419 {
420  char response[PEGASUS_LEN] = {0};
421 
422  if (sendCommand("SQ", response))
423  {
424  std::vector<std::string> result = split(response + 3, ":");
425 
426  if (result == m_SkyQuality)
427  return true;
428 
429  m_SkyQuality = result;
430 
431  try
432  {
433  SkyQualityNP[MPAS].setValue(std::stod(result[MPAS]));
434  SkyQualityNP[NELM].setValue(std::stod(result[NELM]));
435  SkyQualityNP[FullSpectrum].setValue(std::stod(result[FullSpectrum]));
436  SkyQualityNP[VisualSpectrum].setValue(std::stod(result[VisualSpectrum]));
437  SkyQualityNP[InfraredSpectrum].setValue(std::stod(result[InfraredSpectrum]));
438 
439  SkyQualityNP.setState(IPS_OK);
440  SkyQualityNP.apply();
441  return true;
442  }
443  catch(...)
444  {
445  LOGF_WARN("Failed to process sky quality response: %s (%d bytes)", response, strlen(response));
446  return false;
447  }
448  }
449 
450  return false;
451 }
452 
456 bool UranusMeteo::readClouds()
457 {
458  char response[PEGASUS_LEN] = {0};
459 
460  if (sendCommand("CI", response))
461  {
462  std::vector<std::string> result = split(response + 3, ":");
463 
464  if (result == m_Clouds)
465  return true;
466 
467  m_Clouds = result;
468 
469  try
470  {
471  CloudsNP[TemperatureDifference].setValue(std::stod(result[TemperatureDifference]));
472  CloudsNP[CloudIndex].setValue(std::stod(result[CloudIndex]));
473  CloudsNP[CloudSkyTemperature].setValue(std::stod(result[CloudSkyTemperature]));
474  CloudsNP[CloudAmbientTemperature].setValue(std::stod(result[CloudAmbientTemperature]));
475  CloudsNP[InfraredEmissivity].setValue(std::stod(result[InfraredEmissivity]));
476 
477  CloudsNP.setState(IPS_OK);
478  CloudsNP.apply();
479  return true;
480  }
481  catch(...)
482  {
483  LOGF_WARN("Failed to process cloud response: %s (%d bytes)", response, strlen(response));
484  return false;
485  }
486  }
487 
488  return false;
489 }
490 
494 void UranusMeteo::measureSkyQuality()
495 {
496  char response[PEGASUS_LEN] = {0};
497  LOG_DEBUG("Measuring sky quality...");
498  if (sendCommand("SQ:1", response))
499  {
500  readSkyQuality();
501  if (SkyQualityUpdateNP[0].getValue() > 0)
502  m_SkyQualityUpdateTimer.start(SkyQualityUpdateNP[0].getValue() * 1000);
503  }
504 }
505 
509 bool UranusMeteo::readMoon()
510 {
511  return false;
512 }
513 
517 bool UranusMeteo::readTwilight()
518 {
519  return false;
520 }
521 
525 bool UranusMeteo::readConfig()
526 {
527  return false;
528 }
529 
533 bool UranusMeteo::sendCommand(const char * cmd, char * res)
534 {
535  int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
536  char command[PEGASUS_LEN] = {0};
537  LOGF_DEBUG("CMD <%s>", cmd);
538 
539  for (int i = 0; i < 2; i++)
540  {
541  tcflush(PortFD, TCIOFLUSH);
542  snprintf(command, PEGASUS_LEN, "%s\r\n", cmd);
543  if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
544  continue;
545 
546  if (!res)
547  {
548  tcflush(PortFD, TCIOFLUSH);
549  return true;
550  }
551 
552  if ( (tty_rc = tty_nread_section(PortFD, res, PEGASUS_LEN, PEGASUS_STOP_CHAR, PEGASUS_TIMEOUT, &nbytes_read)) != TTY_OK
553  || nbytes_read == 1)
554  continue;
555 
556  tcflush(PortFD, TCIOFLUSH);
557  res[nbytes_read - 2] = '\0';
558  LOGF_DEBUG("RES <%s>", res);
559  return true;
560  }
561 
562  if (tty_rc != TTY_OK)
563  {
564  char errorMessage[MAXRBUF];
565  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
566  LOGF_ERROR("Serial error: %s", errorMessage);
567  }
568 
569  return false;
570 }
571 
572 
576 std::vector<std::string> UranusMeteo::split(const std::string &input, const std::string &regex)
577 {
578  // passing -1 as the submatch index parameter performs splitting
579  std::regex re(regex);
580  std::sregex_token_iterator
581  first{input.begin(), input.end(), re, -1},
582  last;
583  return {first, last};
584 }
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 ...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
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.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indigps.cpp:59
@ LOCATION_LONGITUDE
Definition: indigps.h:53
@ LOCATION_LATITUDE
Definition: indigps.h:52
@ LOCATION_ELEVATION
Definition: indigps.h:54
INDI::PropertyNumber LocationNP
Definition: indigps.h:93
INDI::PropertyText TimeTP
Definition: indigps.h:96
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indigps.cpp:204
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indigps.cpp:186
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indigps.cpp:32
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save refresh period
Definition: indigps.cpp:241
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
void setLabel(const char *label)
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)
void callOnTimeout(const std::function< void()> &callback)
Definition: inditimer.cpp:76
void start()
Starts or restarts the timer with the timeout specified in interval.
Definition: inditimer.cpp:82
void setInterval(int msec)
Set the timeout interval in milliseconds.
Definition: inditimer.cpp:103
Provides interface to implement weather reporting functionality.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process weather switch properties.
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.
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...
INDI::PropertySwitch RefreshSP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyNumber UpdatePeriodNP
virtual void TimerHit() override
TimerHit Keep calling updateGPS() until it is successfull, if it fails upon first connection.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save refresh period
virtual IPState updateWeather() override
updateWeather Update weather conditions from device or service. The function should not change the st...
const char * getDefaultName() override
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: uranusmeteo.cpp:50
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual IPState updateGPS() override
updateGPS Retrieve Location & Time from GPS. Update LocationNP & TimeTP properties (value and state) ...
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition: indiapi.h:150
@ 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
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 IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOGF_WARN(fmt,...)
Definition: indilogger.h:81
#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
std::vector< std::string > split(const std::string &input, const std::string &regex)
__u8 cmd[4]
Definition: pwc-ioctl.h:2