mbgtools-lx  4.2.8
nanotime.c
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: nanotime.c 1.6 2018/12/11 11:55:06 martin REL_M $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Meinberg Library module providing functions to handle NANO_TIME
10  * and NANO_TIME_64.
11  *
12  * -----------------------------------------------------------------------
13  * $Log: nanotime.c $
14  * Revision 1.6 2018/12/11 11:55:06 martin
15  * Fixed compiler warnings on Windows.
16  * Revision 1.5 2018/11/21 11:24:19Z martin
17  * Exclude non-essential header files and functions from firmware builds.
18  * Moved inclusion of stdlib.h to the header file.
19  * Revision 1.4 2018/09/20 09:46:57 martin
20  * Fixed build for some targets.
21  * Moved version dependencies to mbg:tgt.h.
22  * Revision 1.3 2018/07/16 12:39:42Z martin
23  * Functions nano_time_64_to_tm_gps() and tm_gps_to_nano_time_64()
24  * were moved here.
25  * Account for renamed library symbol NSEC_PER_SEC.
26  * Even VS2010 doesn't provide strtoll().
27  * Revision 1.2 2017/06/12 13:54:04 martin
28  * Fixed build under Windows.
29  * Revision 1.1 2017/06/12 08:49:09Z martin
30  * Initial revision.
31  *
32  **************************************************************************/
33 
34 #define _NANOTIME
35  #include <nanotime.h>
36 #undef _NANOTIME
37 
38 #include <mbgtime.h>
39 
40 #if !_IS_MBG_FIRMWARE
41  #include <mbgerror.h>
42  #include <mbgmktm.h>
43  #include <str_util.h>
44  #include <timeutil.h>
45 #endif
46 
47 
48 
49 /*HDR*/
59 double nano_time_to_double( const NANO_TIME *p )
60 {
61  double d = p->secs;
62 
63  d += ( (double) p->nano_secs ) / 1e9;
64 
65  return d;
66 
67 } // nano_time_to_double
68 
69 
70 
71 /*HDR*/
80 void double_to_nano_time( NANO_TIME *p, double d )
81 {
82  p->secs = (int32_t) d;
83 
84  d -= (double) p->secs;
85 
86  p->nano_secs = (int32_t) ( d * 1e9 );
87 
88 } // double_to_nano_time
89 
90 
91 
92 #if !_IS_MBG_FIRMWARE
93 
94 /*HDR*/
102 size_t snprint_nano_time( char *s, size_t max_len, const NANO_TIME *nt )
103 {
104  size_t n = snprintf_safe( s, max_len, "%c%li.%09li",
105  _nano_time_negative( nt ) ? '-' : '+',
106  labs( (long) nt->secs ),
107  labs( (long) nt->nano_secs ) );
108  return n;
109 
110 } // snprint_nano_time
111 
112 #endif
113 
114 
115 
116 #if !_IS_MBG_FIRMWARE && !defined( MBG_TGT_MISSING_64_BIT_TYPES )
117 
118 /*HDR*/
129 {
130  int64_t additional_secs;
131 
132  // Step 1: Make sure nano seconds are in the interval [-10^9 + 1, 10^9 - 1]
133  additional_secs = nt->nano_secs / NSEC_PER_SEC;
134  nt->nano_secs -= additional_secs * NSEC_PER_SEC;
135  nt->secs += additional_secs;
136 
137  // Step 2: Make sure seconds and nanoseconds have same sign if seconds is not 0
138  if ( nt->secs > 0 && nt->nano_secs < 0 )
139  {
140  nt->secs -= 1;
141  nt->nano_secs += NSEC_PER_SEC;
142  }
143  else if ( nt->secs < 0 && nt->nano_secs > 0 )
144  {
145  nt->secs += 1;
146  nt->nano_secs -= NSEC_PER_SEC;
147  }
148 
149 } // normalize_nano_time_64
150 
151 
152 
153 /*HDR*/
164 {
165  double d = (double) p->secs;
166 
167  d += ( (double) p->nano_secs ) / 1e9;
168 
169  return d;
170 
171 } // nano_time_64_to_double
172 
173 
174 
175 /*HDR*/
185 {
186  p->secs = (int32_t) d;
187 
188  d -= (double) p->secs;
189 
190  p->nano_secs = (int32_t) ( d * 1e9 );
191 
192 } // double_to_nano_time_64
193 
194 
195 
196 /*HDR*/
204 size_t snprint_nano_time_64( char *s, size_t max_len, const NANO_TIME_64 *nt )
205 {
206  size_t n = snprintf_safe( s, max_len, "%c%" PRId64 ".%09" PRId64,
207  _nano_time_negative( nt ) ? '-' : '+',
208  _abs64( nt->secs ),
209  _abs64( nt->nano_secs ) );
210  return n;
211 
212 } // snprint_nano_time_64
213 
214 
215 
216 static __mbg_inline /*HDR*/
224 void div_nano_time_64( NANO_TIME_64 *p, long div, long mul )
225 {
226  #if defined( MBG_TGT_MISSING_LLDIV_T )
227  //### TODO: Test this code
228  int64_t rem = p->secs % div;
229  p->secs /= div;
230  p->nano_secs = ( rem * mul ) + ( p->nano_secs / div );
231  #else
232  lldiv_t lldt = lldiv( p->secs, div );
233  p->secs = lldt.quot;
234  p->nano_secs = ( lldt.rem * mul ) + ( p->nano_secs / div );
235  #endif
236 
237 } // div_nano_time_64
238 
239 
240 
241 #if !defined( MBG_TGT_MISSING_STRTOLL )
242 
243 static __mbg_inline /*HDR*/
254 void str_to_nano_time_64( const char *s, NANO_TIME_64 *p, int base, int frac_digits )
255 {
256  char *cp = NULL;
257 
258  p->secs = strtoll( s, &cp, base );
259 
260  if ( *cp == '.' ) // fractions may follow
261  {
262  char *ep = NULL;
263 
264  cp++; // skip '.'
265 
266  p->nano_secs = strtoll( cp, &ep, base );
267 
268  if ( p->nano_secs ) // only if fractions not 0
269  {
270  int l = (int) ( ep - cp );
271 
272  while ( l < frac_digits )
273  {
274  p->nano_secs *= base;
275  l++;
276  }
277 
278  while ( l > frac_digits )
279  {
280  p->nano_secs /= base;
281  l--;
282  }
283 
284  if ( p->secs < 0 )
285  p->nano_secs = -p->nano_secs;
286  }
287  }
288 
289 } // str_to_nano_time_64
290 
291 
292 
293 /*HDR*/
300 void str_s_to_nano_time_64( const char *s, NANO_TIME_64 *p )
301 {
302  str_to_nano_time_64( s, p, 10, 9 );
303 
304 } // str_s_to_nano_time_64
305 
306 
307 
308 /*HDR*/
315 void str_ms_to_nano_time_64( const char *s, NANO_TIME_64 *p )
316 {
317  // First do the same conversion as for a string representing seconds
318  str_s_to_nano_time_64( s, p );
319 
320  // Now we have the value in milliseconds
321  // Divide by 1000 to get seconds
322  div_nano_time_64( p, 1000, 1000000UL );
323 
324 } // str_ms_to_nano_time_64
325 
326 #endif // !defined( MBG_TGT_MISSING_STRTOLL )
327 
328 
329 
330 /*HDR*/
341 int nano_time_64_to_tm_gps( TM_GPS *tm_gps, const NANO_TIME_64 *nt )
342 {
343  struct tm tm = { 0 };
344  time_t t = cvt_to_time_t( nt->secs );
345  int rc = mbg_gmtime( &tm, &t );
346 
347  if ( mbg_rc_is_success( rc ) )
348  {
349  tm_gps->year = tm.tm_year + 1900;
350  tm_gps->month = tm.tm_mon + 1;
351  tm_gps->mday = tm.tm_mday;
352  tm_gps->yday = tm.tm_yday;
353  tm_gps->wday = tm.tm_wday;
354  tm_gps->hour = tm.tm_hour;
355  tm_gps->min = tm.tm_min;
356  tm_gps->sec = tm.tm_sec;
357  tm_gps->frac = 0; //### TODO convert fractions
358 #if defined( MBG_TGT_POSIX )
359  tm_gps->offs_from_utc = tm.tm_gmtoff;
360 #endif
361  }
362 
363  return rc;
364 
365 } // nano_time_64_to_tm_gps
366 
367 
368 
369 /*HDR*/
381 {
382  time_t t = mbg_mktime( tm->year - 1900, tm->month - 1, tm->mday - 1, tm->hour, tm->min, tm->sec );
383 
384  if ( t != (time_t) -1 )
385  {
386  nt->secs = (uint64_t) t;
387  nt->nano_secs = 0; //### TODO: convert fractions
388  return 1;
389  }
390 
391  return 0;
392 
393 } // tm_gps_to_nano_time_64
394 
395 #endif // !_IS_MBG_FIRMWARE && !defined( MBG_TGT_MISSING_64_BIT_TYPES )
396 
397 
void str_s_to_nano_time_64(const char *s, NANO_TIME_64 *p)
Set up a NANO_TIME_64 structure from a string with a time in seconds and fractions.
Definition: nanotime.c:300
#define _nano_time_negative(_nt)
Definition: words.h:596
int32_t frac
fractions of a second, 1/RECEIVER_INFO::ticks_per_sec units
Definition: gpsdefs.h:2603
A timestamp with nanosecond resolution, but 64 bit size.
Definition: words.h:621
Local date and time computed from GPS time.
Definition: gpsdefs.h:2593
void str_ms_to_nano_time_64(const char *s, NANO_TIME_64 *p)
Set up a NANO_TIME_64 structure from a string with a time in milliseconds and fractions.
Definition: nanotime.c:315
int8_t sec
seconds, 0..59, or 60 in case of inserted leap second
Definition: gpsdefs.h:2602
double nano_time_to_double(const NANO_TIME *p)
Convert a NANO_TIME time to double.
Definition: nanotime.c:59
#define mbg_rc_is_success(_rc)
Definition: mbgerror.h:618
int8_t mday
day of month, 1..31
Definition: gpsdefs.h:2597
int16_t year
year number, 0..9999
Definition: gpsdefs.h:2595
static __mbg_inline void div_nano_time_64(NANO_TIME_64 *p, long div, long mul)
Generic function to divide NANO_TIME_64 value.
Definition: nanotime.c:224
int8_t hour
hours, 0..23
Definition: gpsdefs.h:2600
static __mbg_inline void str_to_nano_time_64(const char *s, NANO_TIME_64 *p, int base, int frac_digits)
Generic function to set up a NANO_TIME_64 structure from a string.
Definition: nanotime.c:254
int8_t min
minutes, 0..59
Definition: gpsdefs.h:2601
void normalize_nano_time_64(NANO_TIME_64 *nt)
Normalize a NANO_TIME_64 time.
Definition: nanotime.c:128
static __mbg_inline time_t cvt_to_time_t(mbg_time_t t)
Definition: timeutil.h:108
time_t mbg_mktime(int year, int month, int day, int hour, int min, int sec)
Compute a linear time_t value from broken down date and time.
Definition: mbgmktm.c:61
int tm_gps_to_nano_time_64(NANO_TIME_64 *nt, const TM_GPS *tm)
Convert TM_GPS to NANO_TIME_64.
Definition: nanotime.c:380
A timestamp with nanosecond resolution.
Definition: words.h:575
void double_to_nano_time_64(NANO_TIME_64 *p, double d)
Setup a NANO_TIME_64 structure from a time as double.
Definition: nanotime.c:184
size_t snprint_nano_time(char *s, size_t max_len, const NANO_TIME *nt)
Print nano time into string buffer.
Definition: nanotime.c:102
__int64 int64_t
Definition: words.h:249
int32_t secs
[seconds], usually since 1970-01-01 00:00:00
Definition: words.h:582
static int frac_digits
Definition: mbgsvcd.c:91
int32_t offs_from_utc
local time offset from UTC [sec]
Definition: gpsdefs.h:2604
int32_t nano_secs
[nanoseconds]
Definition: words.h:581
static __mbg_inline int mbg_gmtime(struct tm *p_tm, const time_t *p_time)
Definition: timeutil.h:118
Definition: myutil.h:117
int16_t yday
day of year, 1..365, or 366 in case of leap year
Definition: gpsdefs.h:2598
#define _abs64(_i)
Definition: words.h:267
void double_to_nano_time(NANO_TIME *p, double d)
Setup a NANO_TIME structure from a time provided as double.
Definition: nanotime.c:80
int8_t wday
day of week, 0..6 == Sun..Sat
Definition: gpsdefs.h:2599
#define NSEC_PER_SEC
Definition: mbgtime.h:264
int snprintf_safe(char *s, size_t max_len, const char *fmt,...)
A portable, safe implementation of snprintf()
Definition: str_util.c:156
int64_t nano_secs
[nanoseconds]
Definition: words.h:628
int64_t secs
[seconds], usually since 1970-01-01 00:00:00
Definition: words.h:627
unsigned __int64 uint64_t
Definition: words.h:250
double nano_time_64_to_double(const NANO_TIME_64 *p)
Convert a NANO_TIME_64 time to double.
Definition: nanotime.c:163
int8_t month
month, 1..12
Definition: gpsdefs.h:2596
int nano_time_64_to_tm_gps(TM_GPS *tm_gps, const NANO_TIME_64 *nt)
Convert NANO_TIME_64 to TM_GPS.
Definition: nanotime.c:341
size_t snprint_nano_time_64(char *s, size_t max_len, const NANO_TIME_64 *nt)
Print a normalized NANO_TIME_64 into a string buffer.
Definition: nanotime.c:204