Instrument Neutral Distributed Interface INDI  2.0.2
indigps.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2015 Jasem Mutlaq. All rights reserved.
3 
4  INDI GPS Device Class
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 "indigps.h"
26 
27 #include <cstring>
28 
29 namespace INDI
30 {
31 
33 {
35 
36  PeriodNP[0].fill("PERIOD", "Period (s)", "%.f", 0, 3600, 60.0, 0);
37  PeriodNP.fill(getDeviceName(), "GPS_REFRESH_PERIOD", "Refresh", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE);
38 
39  RefreshSP[0].fill("REFRESH", "GPS", ISS_OFF);
40  RefreshSP.fill(getDeviceName(), "GPS_REFRESH", "Refresh", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
41 
42  LocationNP[LOCATION_LATITUDE].fill("LAT", "Lat (dd:mm:ss)", "%010.6m", -90, 90, 0, 0.0);
43  LocationNP[LOCATION_LONGITUDE].fill("LONG", "Lon (dd:mm:ss)", "%010.6m", 0, 360, 0, 0.0);
44  LocationNP[LOCATION_ELEVATION].fill("ELEV", "Elevation (m)", "%g", -200, 10000, 0, 0);
45  LocationNP.fill(getDeviceName(), "GEOGRAPHIC_COORD", "Location", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
46 
47  TimeTP[0].fill("UTC", "UTC Time", nullptr);
48  TimeTP[1].fill("OFFSET", "UTC Offset", nullptr);
49  TimeTP.fill(getDeviceName(), "TIME_UTC", "UTC", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
50 
52 
53  // Default interface, can be overridden by child
55 
56  return true;
57 }
58 
60 {
62 
63  if (isConnected())
64  {
65  // Update GPS and send values to client
66  IPState state = updateGPS();
67 
68  LocationNP.setState(state);
70  TimeTP.setState(state);
72  RefreshSP.setState(state);
75 
76  if (state != IPS_OK)
77  {
78  if (state == IPS_BUSY)
79  DEBUG(Logger::DBG_SESSION, "GPS fix is in progress...");
80 
82  }
83  else if (PeriodNP[0].getValue() > 0)
84  timerID = SetTimer(PeriodNP[0].getValue());
85  }
86  else
87  {
92 
93  if (timerID > 0)
94  {
96  timerID = -1;
97  }
98  }
99 
100  return true;
101 }
102 
104 {
105  if (!isConnected())
106  {
108  return;
109  }
110 
111  IPState state = updateGPS();
112 
113  LocationNP.setState(state);
114  TimeTP.setState(state);
115  RefreshSP.setState(state);
116 
117  switch (state)
118  {
119  // Ok
120  case IPS_OK:
121  LocationNP.apply();
122  TimeTP.apply();
123  // We got data OK, but if we are required to update once in a while, we'll call it.
124  if (PeriodNP[0].getValue() > 0)
125  timerID = SetTimer(PeriodNP[0].getValue() * 1000);
126 
127  // Update system time
128  // This ideally should be done only ONCE
129  {
130  std::tm utm;
131  if (strptime(TimeTP[0].getText(), "%Y-%m-%dT%H:%M:%S", &utm))
132  {
133  std::time_t raw_time = std::mktime(&utm);
134  setSystemTime(raw_time);
135  }
136  }
137  return;
138  break;
139 
140  // GPS fix is in progress or alert
141  case IPS_ALERT:
142  LocationNP.apply();
143  TimeTP.apply();
144  break;
145 
146  default:
147  break;
148  }
149 
151 }
152 
154 {
155  DEBUG(Logger::DBG_ERROR, "updateGPS() must be implemented in GPS device child class to update TIME_UTC and "
156  "GEOGRAPHIC_COORD properties.");
157  return IPS_ALERT;
158 }
159 
163 bool GPS::setSystemTime(time_t &raw_time)
164 {
165 #ifdef __linux__
166 #if defined(__GNU_LIBRARY__)
167 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ > 30)
168  timespec sTime = {};
169  sTime.tv_sec = raw_time;
170  auto rc = clock_settime(CLOCK_REALTIME, &sTime);
171  if (rc)
172  LOGF_WARN("Failed to update system time: %s", strerror(rc));
173 #else
174  stime(&raw_time);
175 #endif
176 #else
177  stime(&raw_time);
178 #endif
179 #else
180  INDI_UNUSED(raw_time);
181 #endif
182  return true;
183 }
184 
185 
186 bool GPS::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
187 {
188  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
189  {
190  if (RefreshSP.isNameMatch(name))
191  {
192  RefreshSP[0].s = ISS_OFF;
194  RefreshSP.apply();
195 
196  // Manual trigger
197  GPS::TimerHit();
198  }
199  }
200 
201  return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
202 }
203 
204 bool GPS::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
205 {
206  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
207  {
208  if (PeriodNP.isNameMatch(name))
209  {
210  double prevPeriod = PeriodNP[0].getValue();
211  PeriodNP.update(values, names, n);
212  // Do not remove timer if GPS update is still in progress
213  if (timerID > 0 && RefreshSP.getState() != IPS_BUSY)
214  {
216  timerID = -1;
217  }
218 
219  if (PeriodNP[0].getValue() == 0)
220  {
221  DEBUG(Logger::DBG_SESSION, "GPS Update Timer disabled.");
222  }
223  else
224  {
225  timerID = SetTimer(PeriodNP[0].value * 1000);
226  // Need to warn user this is not recommended. Startup values should be enough
227  if (prevPeriod == 0)
228  DEBUG(Logger::DBG_SESSION, "GPS Update Timer enabled. Warning: Updating system-wide time repeatedly may lead to undesirable side-effects.");
229  }
230 
232  PeriodNP.apply();
233 
234  return true;
235  }
236  }
237 
238  return DefaultDevice::ISNewNumber(dev, name, values, names, n);
239 }
240 
241 bool GPS::saveConfigItems(FILE *fp)
242 {
244 
245  PeriodNP.save(fp);
246  return true;
247 }
248 }
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
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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.
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....
void RemoveTimer(int id)
Remove timer added with SetTimer.
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
INDI::PropertySwitch RefreshSP
Definition: indigps.h:99
@ LOCATION_LONGITUDE
Definition: indigps.h:53
@ LOCATION_LATITUDE
Definition: indigps.h:52
@ LOCATION_ELEVATION
Definition: indigps.h:54
virtual IPState updateGPS()
updateGPS Retrieve Location & Time from GPS. Update LocationNP & TimeTP properties (value and state) ...
Definition: indigps.cpp:153
INDI::PropertyNumber LocationNP
Definition: indigps.h:93
INDI::PropertyText TimeTP
Definition: indigps.h:96
INDI::PropertyNumber PeriodNP
Definition: indigps.h:102
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
int timerID
Definition: indigps.h:104
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indigps.cpp:32
virtual void TimerHit() override
TimerHit Keep calling updateGPS() until it is successfull, if it fails upon first connection.
Definition: indigps.cpp:103
virtual bool setSystemTime(time_t &raw_time)
SetSystemTime Update system-wide time.
Definition: indigps.cpp:163
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
IPState getState() 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)
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.
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ 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
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
#define LOGF_WARN(fmt,...)
Definition: indilogger.h:81
Namespace to encapsulate INDI client, drivers, and mediator classes.