@@ -22,6 +22,18 @@ pub const WEEK: Duration = Duration::from_secs(c_bindings::WEEK_SECS as u64);
22
22
#[ derive( Copy , Clone ) ]
23
23
pub struct GpsTime ( c_bindings:: gps_time_t ) ;
24
24
25
+ /// GPS timestamp of the start of Galileo time
26
+ pub const GAL_TIME_START : GpsTime =
27
+ GpsTime :: new_unchecked ( c_bindings:: GAL_WEEK_TO_GPS_WEEK as i16 , 0.0 ) ;
28
+ /// GPS timestamp of the start of Beidou time
29
+ pub const BDS_TIME_START : GpsTime = GpsTime :: new_unchecked (
30
+ c_bindings:: BDS_WEEK_TO_GPS_WEEK as i16 ,
31
+ c_bindings:: BDS_SECOND_TO_GPS_SECOND as f64 ,
32
+ ) ;
33
+ /// GPS timestamp of the start of Glonass time
34
+ pub const GLO_TIME_START : GpsTime =
35
+ GpsTime :: new_unchecked ( c_bindings:: GLO_EPOCH_WN as i16 , c_bindings:: GLO_EPOCH_TOW ) ;
36
+
25
37
#[ derive( Debug , Copy , Clone , PartialOrd , PartialEq ) ]
26
38
pub enum InvalidGpsTime {
27
39
InvalidWN ( i16 ) ,
@@ -58,7 +70,7 @@ impl GpsTime {
58
70
59
71
/// Makes a new GPS time object without checking the validity of the given
60
72
/// values.
61
- pub ( crate ) fn new_unchecked ( wn : i16 , tow : f64 ) -> GpsTime {
73
+ pub ( crate ) const fn new_unchecked ( wn : i16 , tow : f64 ) -> GpsTime {
62
74
GpsTime ( c_bindings:: gps_time_t { wn, tow } )
63
75
}
64
76
@@ -121,7 +133,7 @@ impl GpsTime {
121
133
/// seconds.
122
134
///
123
135
/// Note: The hard coded list of leap seconds will get out of date, it is
124
- /// preferable to use `GpsTime::to_utc()` with the newest set of UTC parameters
136
+ /// preferable to use [ `GpsTime::to_utc()`] with the newest set of UTC parameters
125
137
pub fn to_utc_hardcoded ( self ) -> UtcTime {
126
138
let mut utc = UtcTime :: default ( ) ;
127
139
unsafe {
@@ -139,7 +151,7 @@ impl GpsTime {
139
151
/// list of leap seconds
140
152
///
141
153
/// Note: The hard coded list of leap seconds will get out of date, it is
142
- /// preferable to use `GpsTime::utc_offset_hardcoded()` with the newest set
154
+ /// preferable to use [ `GpsTime::utc_offset_hardcoded()`] with the newest set
143
155
/// of UTC parameters
144
156
pub fn utc_offset_hardcoded ( & self ) -> f64 {
145
157
unsafe { c_bindings:: get_gps_utc_offset ( self . c_ptr ( ) , std:: ptr:: null ( ) ) }
@@ -154,7 +166,7 @@ impl GpsTime {
154
166
/// hardcoded list of leap seconds
155
167
///
156
168
/// Note: The hard coded list of leap seconds will get out of date, it is
157
- /// preferable to use `GpsTime::is_leap_second_event_hardcoded()` with the newest
169
+ /// preferable to use [ `GpsTime::is_leap_second_event_hardcoded()`] with the newest
158
170
/// set of UTC parameters
159
171
pub fn is_leap_second_event_hardcoded ( & self ) -> bool {
160
172
unsafe { c_bindings:: is_leap_second_event ( self . c_ptr ( ) , std:: ptr:: null ( ) ) }
@@ -169,6 +181,65 @@ impl GpsTime {
169
181
pub fn floor_to_epoch ( & self , soln_freq : f64 ) -> GpsTime {
170
182
GpsTime ( unsafe { c_bindings:: floor_to_epoch ( self . c_ptr ( ) , soln_freq) } )
171
183
}
184
+
185
+ /// Converts the GPS time into Galileo time
186
+ ///
187
+ /// # Panics
188
+ /// This function will panic if the GPS time is before the start of Galileo
189
+ /// time, i.e. [`GAL_TIME_START`]
190
+ pub fn to_gal ( self ) -> GalTime {
191
+ assert ! ( self . is_valid( ) ) ;
192
+ assert ! ( self >= GAL_TIME_START ) ;
193
+ GalTime {
194
+ wn : self . wn ( ) - c_bindings:: GAL_WEEK_TO_GPS_WEEK as i16 ,
195
+ tow : self . tow ( ) ,
196
+ }
197
+ }
198
+
199
+ /// Converts the GPS time into Beidou time
200
+ ///
201
+ /// # Panics
202
+ /// This function will panic if the GPS time is before the start of Beidou
203
+ /// time, i.e. [`BDS_TIME_START`]
204
+ pub fn to_bds ( self ) -> BdsTime {
205
+ assert ! ( self . is_valid( ) ) ;
206
+ assert ! ( self >= BDS_TIME_START ) ;
207
+ let bds = GpsTime :: new_unchecked (
208
+ self . wn ( ) - c_bindings:: BDS_WEEK_TO_GPS_WEEK as i16 ,
209
+ self . tow ( ) ,
210
+ ) ;
211
+ let bds = bds - Duration :: from_secs ( c_bindings:: BDS_SECOND_TO_GPS_SECOND as u64 ) ;
212
+ BdsTime {
213
+ wn : bds. wn ( ) ,
214
+ tow : bds. tow ( ) ,
215
+ }
216
+ }
217
+
218
+ /// Converts a GPS time into a Glonass time
219
+ ///
220
+ /// # Panics
221
+ /// This function will panic if the GPS time is before the start of Glonass
222
+ /// time, i.e. [`GLO_TIME_START`]
223
+ pub fn to_glo ( self , utc_params : & UtcParams ) -> GloTime {
224
+ assert ! ( self . is_valid( ) ) ;
225
+ assert ! ( self >= GLO_TIME_START ) ;
226
+ GloTime ( unsafe { c_bindings:: gps2glo ( self . c_ptr ( ) , utc_params. c_ptr ( ) ) } )
227
+ }
228
+
229
+ /// Converts a GPS time into a Glonass time using the hardcoded list of leap
230
+ /// seconds.
231
+ ///
232
+ /// Note: The hard coded list of leap seconds will get out of date, it is
233
+ /// preferable to use [`GpsTime::to_glo()`] with the newest set of UTC parameters
234
+ ///
235
+ /// # Panics
236
+ /// This function will panic if the GPS time is before the start of Glonass
237
+ /// time, i.e. [`GLO_TIME_START`]
238
+ pub fn to_glo_hardcoded ( self ) -> GloTime {
239
+ assert ! ( self . is_valid( ) ) ;
240
+ assert ! ( self >= GLO_TIME_START ) ;
241
+ GloTime ( unsafe { c_bindings:: gps2glo ( self . c_ptr ( ) , std:: ptr:: null ( ) ) } )
242
+ }
172
243
}
173
244
174
245
impl fmt:: Debug for GpsTime {
@@ -245,6 +316,176 @@ impl SubAssign<Duration> for GpsTime {
245
316
}
246
317
}
247
318
319
+ impl From < GalTime > for GpsTime {
320
+ fn from ( gal : GalTime ) -> Self {
321
+ gal. to_gps ( )
322
+ }
323
+ }
324
+
325
+ impl From < BdsTime > for GpsTime {
326
+ fn from ( bds : BdsTime ) -> Self {
327
+ bds. to_gps ( )
328
+ }
329
+ }
330
+
331
+ /// Representation of Galileo Time
332
+ #[ derive( Debug , Copy , Clone ) ]
333
+ pub struct GalTime {
334
+ wn : i16 ,
335
+ tow : f64 ,
336
+ }
337
+
338
+ impl GalTime {
339
+ pub fn new ( wn : i16 , tow : f64 ) -> Result < GalTime , InvalidGpsTime > {
340
+ if wn < 0 {
341
+ Err ( InvalidGpsTime :: InvalidWN ( wn) )
342
+ } else if !tow. is_finite ( ) || tow < 0. || tow >= WEEK . as_secs_f64 ( ) {
343
+ Err ( InvalidGpsTime :: InvalidTOW ( tow) )
344
+ } else {
345
+ Ok ( GalTime { wn, tow } )
346
+ }
347
+ }
348
+
349
+ pub fn wn ( & self ) -> i16 {
350
+ self . wn
351
+ }
352
+
353
+ pub fn tow ( & self ) -> f64 {
354
+ self . tow
355
+ }
356
+
357
+ pub fn to_gps ( self ) -> GpsTime {
358
+ GpsTime :: new_unchecked ( self . wn + c_bindings:: GAL_WEEK_TO_GPS_WEEK as i16 , self . tow )
359
+ }
360
+
361
+ pub fn to_bds ( self ) -> BdsTime {
362
+ self . to_gps ( ) . to_bds ( )
363
+ }
364
+ }
365
+
366
+ impl From < GpsTime > for GalTime {
367
+ fn from ( gps : GpsTime ) -> Self {
368
+ gps. to_gal ( )
369
+ }
370
+ }
371
+
372
+ impl From < BdsTime > for GalTime {
373
+ fn from ( bds : BdsTime ) -> Self {
374
+ bds. to_gal ( )
375
+ }
376
+ }
377
+
378
+ /// Representation of Beidou Time
379
+ #[ derive( Debug , Copy , Clone ) ]
380
+ pub struct BdsTime {
381
+ wn : i16 ,
382
+ tow : f64 ,
383
+ }
384
+
385
+ impl BdsTime {
386
+ pub fn new ( wn : i16 , tow : f64 ) -> Result < BdsTime , InvalidGpsTime > {
387
+ if wn < 0 {
388
+ Err ( InvalidGpsTime :: InvalidWN ( wn) )
389
+ } else if !tow. is_finite ( ) || tow < 0. || tow >= WEEK . as_secs_f64 ( ) {
390
+ Err ( InvalidGpsTime :: InvalidTOW ( tow) )
391
+ } else {
392
+ Ok ( BdsTime { wn, tow } )
393
+ }
394
+ }
395
+
396
+ pub fn wn ( & self ) -> i16 {
397
+ self . wn
398
+ }
399
+
400
+ pub fn tow ( & self ) -> f64 {
401
+ self . tow
402
+ }
403
+
404
+ pub fn to_gps ( self ) -> GpsTime {
405
+ let gps = GpsTime :: new_unchecked (
406
+ self . wn ( ) + c_bindings:: BDS_WEEK_TO_GPS_WEEK as i16 ,
407
+ self . tow ( ) ,
408
+ ) ;
409
+ gps + Duration :: from_secs ( c_bindings:: BDS_SECOND_TO_GPS_SECOND as u64 )
410
+ }
411
+
412
+ pub fn to_gal ( self ) -> GalTime {
413
+ self . to_gps ( ) . to_gal ( )
414
+ }
415
+ }
416
+
417
+ impl From < GpsTime > for BdsTime {
418
+ fn from ( gps : GpsTime ) -> Self {
419
+ gps. to_bds ( )
420
+ }
421
+ }
422
+
423
+ impl From < GalTime > for BdsTime {
424
+ fn from ( gal : GalTime ) -> Self {
425
+ gal. to_bds ( )
426
+ }
427
+ }
428
+
429
+ /// Representation of Glonass Time
430
+ #[ derive( Copy , Clone ) ]
431
+ pub struct GloTime ( c_bindings:: glo_time_t ) ;
432
+
433
+ impl GloTime {
434
+ pub ( crate ) fn c_ptr ( & self ) -> * const c_bindings:: glo_time_t {
435
+ & self . 0
436
+ }
437
+
438
+ /// Creates a new GloTime
439
+ /// nt - Day number within the four-year interval [1-1461].
440
+ /// Comes from the field NT in the GLO string 4.
441
+ ///
442
+ /// n4 - Four-year interval number starting from 1996 [1- ].
443
+ /// Comes from the field N4 in the GLO string 5.
444
+ ///
445
+ /// h/m/s come either from the field tb in the GLO string 2
446
+ /// or the field tk in the GLO string 1
447
+ /// h - Hours [0-24]
448
+ /// m - Minutes [0-59]
449
+ /// s - Seconds [0-60]
450
+ pub fn new ( nt : u16 , n4 : u8 , h : u8 , m : u8 , s : f64 ) -> GloTime {
451
+ GloTime ( c_bindings:: glo_time_t { nt, n4, h, m, s } )
452
+ }
453
+
454
+ pub fn nt ( & self ) -> u16 {
455
+ self . 0 . nt
456
+ }
457
+
458
+ pub fn n4 ( & self ) -> u8 {
459
+ self . 0 . n4
460
+ }
461
+
462
+ pub fn h ( & self ) -> u8 {
463
+ self . 0 . h
464
+ }
465
+
466
+ pub fn m ( & self ) -> u8 {
467
+ self . 0 . m
468
+ }
469
+
470
+ pub fn s ( & self ) -> f64 {
471
+ self . 0 . s
472
+ }
473
+
474
+ /// Converts a Glonass time into a GPS time
475
+ pub fn to_gps ( self , utc_params : & UtcParams ) -> GpsTime {
476
+ GpsTime ( unsafe { c_bindings:: glo2gps ( self . c_ptr ( ) , utc_params. c_ptr ( ) ) } )
477
+ }
478
+
479
+ /// Converts a Glonass time into a GPS time using the hardcoded list of leap
480
+ /// seconds.
481
+ ///
482
+ /// Note: The hard coded list of leap seconds will get out of date, it is
483
+ /// preferable to use [`GloTime::to_gps()`] with the newest set of UTC parameters
484
+ pub fn to_gps_hardcoded ( self ) -> GpsTime {
485
+ GpsTime ( unsafe { c_bindings:: glo2gps ( self . c_ptr ( ) , std:: ptr:: null ( ) ) } )
486
+ }
487
+ }
488
+
248
489
/// Structure containing GPS UTC correction parameters
249
490
#[ derive( Clone ) ]
250
491
pub struct UtcParams ( c_bindings:: utc_params_t ) ;
@@ -1261,4 +1502,45 @@ mod tests {
1261
1502
assert_eq ! ( converted. minute( ) , swift_date. minute( ) as u32 ) ;
1262
1503
assert_eq ! ( converted. second( ) , swift_date. seconds( ) as u32 ) ;
1263
1504
}
1505
+
1506
+ #[ test]
1507
+ fn gps_to_gal ( ) {
1508
+ let gal = GAL_TIME_START . to_gal ( ) ;
1509
+ assert_eq ! ( gal. wn( ) , 0 ) ;
1510
+ assert ! ( gal. tow( ) . abs( ) < 1e-9 ) ;
1511
+ let gps = gal. to_gps ( ) ;
1512
+ assert_eq ! ( gps. wn( ) , c_bindings:: GAL_WEEK_TO_GPS_WEEK as i16 ) ;
1513
+ assert ! ( gps. tow( ) . abs( ) < 1e-9 ) ;
1514
+
1515
+ assert ! ( GalTime :: new( -1 , 0.0 ) . is_err( ) ) ;
1516
+ assert ! ( GalTime :: new( 0 , -1.0 ) . is_err( ) ) ;
1517
+ assert ! ( GalTime :: new( 0 , c_bindings:: WEEK_SECS as f64 + 1.0 ) . is_err( ) ) ;
1518
+ }
1519
+
1520
+ #[ test]
1521
+ fn gps_to_bds ( ) {
1522
+ let bds = BDS_TIME_START . to_bds ( ) ;
1523
+ assert_eq ! ( bds. wn( ) , 0 ) ;
1524
+ assert ! ( bds. tow( ) . abs( ) < 1e-9 ) ;
1525
+ let gps = bds. to_gps ( ) ;
1526
+ assert_eq ! ( gps. wn( ) , c_bindings:: BDS_WEEK_TO_GPS_WEEK as i16 ) ;
1527
+ assert ! ( ( gps. tow( ) - c_bindings:: BDS_SECOND_TO_GPS_SECOND as f64 ) . abs( ) < 1e-9 ) ;
1528
+
1529
+ assert ! ( BdsTime :: new( -1 , 0.0 ) . is_err( ) ) ;
1530
+ assert ! ( BdsTime :: new( 0 , -1.0 ) . is_err( ) ) ;
1531
+ assert ! ( BdsTime :: new( 0 , c_bindings:: WEEK_SECS as f64 + 1.0 ) . is_err( ) ) ;
1532
+ }
1533
+
1534
+ #[ test]
1535
+ fn gps_to_glo ( ) {
1536
+ let glo = GLO_TIME_START . to_glo_hardcoded ( ) ;
1537
+ assert_eq ! ( glo. nt( ) , 1 ) ;
1538
+ assert_eq ! ( glo. n4( ) , 1 ) ;
1539
+ assert_eq ! ( glo. h( ) , 0 ) ;
1540
+ assert_eq ! ( glo. m( ) , 0 ) ;
1541
+ assert ! ( glo. s( ) . abs( ) < 1e-9 ) ;
1542
+ let gps = glo. to_gps_hardcoded ( ) ;
1543
+ assert_eq ! ( gps. wn( ) , c_bindings:: GLO_EPOCH_WN as i16 ) ;
1544
+ assert ! ( ( gps. tow( ) - c_bindings:: GLO_EPOCH_TOW as f64 ) . abs( ) < 1e-9 ) ;
1545
+ }
1264
1546
}
0 commit comments