Setting system time with gps timestamp_t structure in Linux
Hi Everyone,
I'm trying to write code that as soon as I get a succesfull GPS lock (Adafruit Ultimate GPS w/ GPSD) I set the system time. Right now, I can see that 'timestamp_t':
typedef double timestamp_t; /* Unix time in seconds with fractional part */
is a part of my "gps_data_t*" structure. This is a good start, however, the function I planned on using to set the system time in Linux is:
int settimeofday(const struct timeval *tv, const struct timezone *tz);
I've found information on how to convert time_t to *timeval, but how should I handle this double to convert it to *timeval?
Code:
gpsmm gps_rec("localhost", DEFAULT_GPSD_PORT);
if (gps_rec.stream(WATCH_ENABLE|WATCH_JSON) == NULL) {
std::cout << "No GPSD running. exiting GPS thread." << std::endl;
return;
}
//Data structure
struct gps_data_t* newdata;
//Loop until first GPS lock to set system time
while ((newdata = gps_rec.read()) == NULL) {
//Wait for a valid read
}
//Set system time - timestamp_t vs timeval?
timeval *tv{?? newdata->time ??};
timezone *tz{ timezone(300, DST_USA)};
settimeofday(tv, tz);
Some comments and links have helped me. The confusion is differentiating between timeval, time_t, and timestamp_t. As I understand it here are the differences, please correct if not the case:
All are time in seconds after Jan 1st, 1970, but...
timeval is a structure of (2) long values, tv_sec is seconds after 1/1/1970, tv_usec is microseconds after that.
time_t is a long? that is also seconds after 1/1/1970
timestamp_t is a double that is seconds after 1/1/1970, so the decimal part could calculate the microseconds to get 'roughly' the same precision of timeval.
So conversion between all of them could go as such:
timeval time;
time_t timet;
timestamp_t timestampt;
timet = time.tv_sec; //usec dropped
timet = timestampt; //usec dropped
timestampt = timet; //usec not given
timestampt = time.tv_sec;
timestampt += (time.tv_usec / 1000000) //Denominator may be off by a few 0's
Is this painting a clearer picture?
To go the opposite way, which is what is needed for my application:
//Convert gps_data_t* member 'time' to timeval
timeval tv;
double wholeseconds, decimalseconds;
decimalseconds = modf(newdata->time, &wholeseconds);
tv.sec = static_cast<int32_t>(wholeseconds);
tv.usec = static_cast<int32_t>(decimalseconds * 1000000.0);
//Create timezone
timezone tz{ timezone(300, DST_USA)};
//Set system time
settimeofday(&tv, &tz);