@@ -22,6 +22,18 @@ pub const WEEK: Duration = Duration::from_secs(c_bindings::WEEK_SECS as u64);
2222#[ derive( Copy , Clone ) ]
2323pub struct GpsTime ( c_bindings:: gps_time_t ) ;
2424
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+
2537#[ derive( Debug , Copy , Clone , PartialOrd , PartialEq ) ]
2638pub enum InvalidGpsTime {
2739 InvalidWN ( i16 ) ,
@@ -58,7 +70,7 @@ impl GpsTime {
5870
5971 /// Makes a new GPS time object without checking the validity of the given
6072 /// values.
61- pub ( crate ) fn new_unchecked ( wn : i16 , tow : f64 ) -> GpsTime {
73+ pub ( crate ) const fn new_unchecked ( wn : i16 , tow : f64 ) -> GpsTime {
6274 GpsTime ( c_bindings:: gps_time_t { wn, tow } )
6375 }
6476
@@ -121,7 +133,7 @@ impl GpsTime {
121133 /// seconds.
122134 ///
123135 /// 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
125137 pub fn to_utc_hardcoded ( self ) -> UtcTime {
126138 let mut utc = UtcTime :: default ( ) ;
127139 unsafe {
@@ -139,7 +151,7 @@ impl GpsTime {
139151 /// list of leap seconds
140152 ///
141153 /// 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
143155 /// of UTC parameters
144156 pub fn utc_offset_hardcoded ( & self ) -> f64 {
145157 unsafe { c_bindings:: get_gps_utc_offset ( self . c_ptr ( ) , std:: ptr:: null ( ) ) }
@@ -154,7 +166,7 @@ impl GpsTime {
154166 /// hardcoded list of leap seconds
155167 ///
156168 /// 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
158170 /// set of UTC parameters
159171 pub fn is_leap_second_event_hardcoded ( & self ) -> bool {
160172 unsafe { c_bindings:: is_leap_second_event ( self . c_ptr ( ) , std:: ptr:: null ( ) ) }
@@ -169,6 +181,65 @@ impl GpsTime {
169181 pub fn floor_to_epoch ( & self , soln_freq : f64 ) -> GpsTime {
170182 GpsTime ( unsafe { c_bindings:: floor_to_epoch ( self . c_ptr ( ) , soln_freq) } )
171183 }
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+ }
172243}
173244
174245impl fmt:: Debug for GpsTime {
@@ -245,6 +316,176 @@ impl SubAssign<Duration> for GpsTime {
245316 }
246317}
247318
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+
248489/// Structure containing GPS UTC correction parameters
249490#[ derive( Clone ) ]
250491pub struct UtcParams ( c_bindings:: utc_params_t ) ;
@@ -1261,4 +1502,45 @@ mod tests {
12611502 assert_eq ! ( converted. minute( ) , swift_date. minute( ) as u32 ) ;
12621503 assert_eq ! ( converted. second( ) , swift_date. seconds( ) as u32 ) ;
12631504 }
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+ }
12641546}
0 commit comments