gnss-converters 0.3.25 → 0.3.28
raw patch · 4 files changed
+242/−139 lines, 4 filesdep ~aesondep ~aeson-prettydep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: aeson, aeson-pretty, base, basic-prelude, binary-conduit, bytestring, conduit, conduit-extra, exceptions, extra, lens, monad-control, mtl, resourcet, rtcm, sbp, tasty, tasty-golden, tasty-hunit, time, transformers-base, vector
API changes (from Hackage documentation)
- Data.RTCM3.SBP.Ephemerides: converter :: MonadStore e m => Msg1019 -> Conduit i m [SBPMsg]
+ Data.RTCM3.SBP.Ephemerides: glonassConverter :: MonadStore e m => Msg1020 -> Conduit i m [SBPMsg]
+ Data.RTCM3.SBP.Ephemerides: gpsConverter :: MonadStore e m => Msg1019 -> Conduit i m [SBPMsg]
+ Data.RTCM3.SBP.Time: minuteMillis :: Integer
- Data.RTCM3.SBP.Types: class HasStore c_apdl where storeCurrentGpsTime = (.) store storeCurrentGpsTime storeGpsTimeMap = (.) store storeGpsTimeMap storeObservations = (.) store storeObservations
+ Data.RTCM3.SBP.Types: class HasStore c_auhn
- Data.RTCM3.SBP.Types: store :: HasStore c_apdl => Lens' c_apdl Store
+ Data.RTCM3.SBP.Types: store :: HasStore c_auhn => Lens' c_auhn Store
- Data.RTCM3.SBP.Types: storeCurrentGpsTime :: HasStore c_apdl => Lens' c_apdl (IO GpsTime)
+ Data.RTCM3.SBP.Types: storeCurrentGpsTime :: HasStore c_auhn => Lens' c_auhn (IO GpsTime)
- Data.RTCM3.SBP.Types: storeGpsTimeMap :: HasStore c_apdl => Lens' c_apdl (IORef GpsTimeMap)
+ Data.RTCM3.SBP.Types: storeGpsTimeMap :: HasStore c_auhn => Lens' c_auhn (IORef GpsTimeMap)
- Data.RTCM3.SBP.Types: storeObservations :: HasStore c_apdl => Lens' c_apdl (IORef (Vector PackedObsContent))
+ Data.RTCM3.SBP.Types: storeObservations :: HasStore c_auhn => Lens' c_auhn (IORef (Vector PackedObsContent))
Files
- gnss-converters.cabal +92/−100
- src/Data/RTCM3/SBP.hs +2/−1
- src/Data/RTCM3/SBP/Ephemerides.hs +137/−38
- src/Data/RTCM3/SBP/Time.hs +11/−0
gnss-converters.cabal view
@@ -1,112 +1,104 @@-name: gnss-converters-version: 0.3.25-cabal-version: >=1.22-build-type: Simple-license: BSD3-copyright: Copyright (C) 2016, 2017 Swift Navigation, Inc.-maintainer: Swift Navigation <dev@swiftnav.com>-homepage: http://github.com/swift-nav/gnss-converters-synopsis: GNSS Converters.-description:- Haskell bindings for GNSS converters.-category: Network-author: Mark Fine <mark@swiftnav.com>, Joshua Gross <josh@swiftnav.com>+name: gnss-converters+version: 0.3.28+synopsis: GNSS Converters.+description: Haskell bindings for GNSS converters.+homepage: http://github.com/swift-nav/gnss-converters+license: BSD3+author: Mark Fine <mark@swiftnav.com>, Joshua Gross <josh@swiftnav.com>+maintainer: Swift Navigation <dev@swiftnav.com>+copyright: Copyright (C) 2016, 2017 Swift Navigation, Inc.+category: Network+build-type: Simple+cabal-version: >= 1.22 source-repository head- type: git- location: https://github.com/swift-nav/gnss-converters+ type: git+ location: https://github.com/swift-nav/gnss-converters library- exposed-modules:- Data.RTCM3.Replay- Data.RTCM3.SBP- Data.RTCM3.SBP.Biases- Data.RTCM3.SBP.Ephemerides- Data.RTCM3.SBP.Observations- Data.RTCM3.SBP.Positions- Data.RTCM3.SBP.Time- Data.RTCM3.SBP.Types- SwiftNav.SBP.RTCM3- build-depends:- base >=4.8 && <5,- basic-prelude >=0.5.2,- conduit >=1.2.10,- exceptions >=0.8.3,- extra >=1.4.10,- lens >=4.13,- monad-control >=1.0.1.0,- mtl >=2.2.1,- resourcet >=1.1.9,- rtcm >=0.2.11,- sbp >=2.3.2,- time >=1.5.0.1,- transformers-base >=0.4.4,- vector >=0.11.0.0- default-language: Haskell2010- hs-source-dirs: src- ghc-options: -Wall+ hs-source-dirs: src+ exposed-modules: Data.RTCM3.Replay+ , Data.RTCM3.SBP+ , Data.RTCM3.SBP.Biases+ , Data.RTCM3.SBP.Ephemerides+ , Data.RTCM3.SBP.Observations+ , Data.RTCM3.SBP.Positions+ , Data.RTCM3.SBP.Time+ , Data.RTCM3.SBP.Types+ , SwiftNav.SBP.RTCM3+ ghc-options: -Wall+ build-depends: base >= 4.8 && < 5+ , basic-prelude+ , conduit+ , exceptions+ , extra+ , lens+ , monad-control+ , mtl+ , resourcet+ , rtcm+ , sbp+ , time+ , transformers-base+ , vector+ default-language: Haskell2010 executable sbp2rtcm3- main-is: SBP2RTCM3.hs- build-depends:- base >=4.8.2.0,- basic-prelude >=0.5.2,- binary-conduit >=1.2.4.1,- conduit >=1.2.10,- conduit-extra >=1.1.16,- gnss-converters- default-language: Haskell2010- hs-source-dirs: main- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ hs-source-dirs: main+ main-is: SBP2RTCM3.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ build-depends: base+ , basic-prelude+ , binary-conduit+ , conduit+ , conduit-extra+ , gnss-converters+ default-language: Haskell2010 executable rtcm32sbp- main-is: RTCM32SBP.hs- build-depends:- base >=4.8.2.0,- basic-prelude >=0.5.2,- binary-conduit >=1.2.4.1,- conduit >=1.2.10,- conduit-extra >=1.1.16,- gnss-converters- default-language: Haskell2010- hs-source-dirs: main- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ hs-source-dirs: main+ main-is: RTCM32SBP.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ build-depends: base+ , basic-prelude+ , binary-conduit+ , conduit+ , conduit-extra+ , gnss-converters+ default-language: Haskell2010 executable rtcm32rtcm3- main-is: RTCM32RTCM3.hs- build-depends:- base >=4.8.2.0,- basic-prelude >=0.5.2,- binary-conduit >=1.2.4.1,- conduit >=1.2.10,- conduit-extra >=1.1.16,- gnss-converters- default-language: Haskell2010- hs-source-dirs: main- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ hs-source-dirs: main+ main-is: RTCM32RTCM3.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ build-depends: base+ , basic-prelude+ , binary-conduit+ , conduit+ , conduit-extra+ , gnss-converters+ default-language: Haskell2010 test-suite test- type: exitcode-stdio-1.0- main-is: Test.hs- build-depends:- aeson >=0.11.3.0,- aeson-pretty >=0.7.2,- base >=4.8.2.0,- basic-prelude >=0.5.2,- binary-conduit >=1.2.4.1,- bytestring >=0.10.6.0,- conduit >=1.2.10,- conduit-extra >=1.1.16,- gnss-converters,- lens >=4.13,- sbp >=2.3.2,- tasty >=0.11.2.1,- tasty-golden >=2.3.1.1,- tasty-hunit >=0.9.2,- time >=1.5.0.1- default-language: Haskell2010- hs-source-dirs: test- other-modules:- Test.Data.RTCM3.SBP- Test.Data.RTCM3.SBP.Time- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Test.hs+ other-modules: Test.Data.RTCM3.SBP+ , Test.Data.RTCM3.SBP.Time+ build-depends: aeson+ , aeson-pretty+ , base+ , basic-prelude+ , binary-conduit+ , bytestring+ , conduit+ , conduit-extra+ , gnss-converters+ , lens+ , sbp+ , tasty+ , tasty-golden+ , tasty-hunit+ , time+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ default-language: Haskell2010
src/Data/RTCM3/SBP.hs view
@@ -41,7 +41,8 @@ (RTCM3Msg1012 m _rtcm3) -> Observations.converter m (RTCM3Msg1005 m _rtcm3) -> Positions.converter m (RTCM3Msg1006 m _rtcm3) -> Positions.converter m- (RTCM3Msg1019 m _rtcm3) -> Ephemerides.converter m+ (RTCM3Msg1019 m _rtcm3) -> Ephemerides.gpsConverter m+ (RTCM3Msg1020 m _rtcm3) -> Ephemerides.glonassConverter m (RTCM3Msg1230 m _rtcm3) -> Biases.converter m _rtcm3Msg -> mempty
src/Data/RTCM3/SBP/Ephemerides.hs view
@@ -11,7 +11,8 @@ -- RTCMv3 to SBP Ephemerides Conversions. module Data.RTCM3.SBP.Ephemerides- ( converter+ ( gpsConverter+ , glonassConverter ) where import BasicPrelude@@ -19,6 +20,7 @@ import Data.Bits import Data.Conduit import Data.RTCM3+import Data.RTCM3.SBP.Time import Data.RTCM3.SBP.Types import Data.Word import SwiftNav.SBP@@ -38,6 +40,22 @@ , _gpsTimeSec_wn = wn' `shiftR` 10 `shiftL` 10 + wn } +-- | Produce GPS time from GLONASS RTCM time.+--+toGlonassTimeSec :: MonadStore e m => Word8 -> m GpsTimeSec+toGlonassTimeSec epoch = do+ time <- view storeCurrentGpsTime+ t <- liftIO time+ let epoch' = fromIntegral epoch * 15 * minuteMillis - 3 * hourMillis + gpsLeapMillis+ epoch''+ | epoch' < 0 = epoch' + dayMillis+ | otherwise = epoch'+ dow = fromIntegral (t ^. gpsTime_tow) `div` dayMillis+ pure GpsTimeSec+ { _gpsTimeSec_tow = fromIntegral $ (dow * dayMillis + epoch'') `div` 1000+ , _gpsTimeSec_wn = t ^. gpsTime_wn+ }+ -- | Validate IODE/IODC flags. The IODC and IODE flags (least significant bits) should be -- equal. IODC is Word16 while IODE is Word8, so we shift IODC to drop the most significant bits. -- We return a 1 if valid, 0 if invalid.@@ -51,21 +69,41 @@ -- See section 2.5.3, "User Range Accuracy", in the GPS signal specification. -- Indices 1, 3, and 5 are hard-coded according to spec, and 15 is hard-coded according -- to SBP/Piksi convention.-uriToUra :: Double -> Double+uriToUra :: Word8 -> Double uriToUra uri- | uri < 0 = -1 | uri == 1 = 2.8 | uri == 3 = 5.7 | uri == 5 = 11.3 | uri == 15 = 6144- | uri <= 6 = 2 ** (1 + (uri / 2))- | uri > 6 && uri < 15 = 2 ** (uri - 2)+ | uri <= 6 = 2 ** (1 + (fromIntegral uri / 2))+ | uri > 6 && uri < 15 = 2 ** (fromIntegral uri - 2) | otherwise = -1 +-- | Lookup Table 4.4 from GLONASS ICD: convert F_T word to accuracy in meters+--+ftToUra :: Word8 -> Double+ftToUra ft+ | ft == 0 = 1+ | ft == 1 = 2+ | ft == 2 = 2.5+ | ft == 3 = 4+ | ft == 4 = 5+ | ft == 5 = 7+ | ft == 6 = 10+ | ft == 7 = 12+ | ft == 8 = 14+ | ft == 9 = 16+ | ft == 10 = 32+ | ft == 11 = 64+ | ft == 12 = 128+ | ft == 13 = 256+ | ft == 14 = 512+ | otherwise = -1+ -- | Decode SBP 'fitInterval' from RTCM/GPS 'fitIntervalFlag' and IODC. -- Implementation adapted from libswiftnav/ephemeris.c.-fitInterval :: Bool -> Word16 -> Word32-fitInterval fitInt iodc+gpsFitInterval :: Bool -> Word16 -> Word32+gpsFitInterval fitInt iodc | not fitInt = 4 * 60 * 60 | iodc >= 240 && iodc <= 247 = 8 * 60 * 60 | (iodc >= 248 && iodc <= 255) || iodc == 496 = 14 * 60 * 60@@ -75,7 +113,18 @@ | iodc == 757 = 98 * 60 * 60 | otherwise = 6 * 60 * 60 +-- | Convert GLONASS fit interval - Table 4.3 from GLONASS ICD.+--+glonassFitInterval :: Word8 -> Word32+glonassFitInterval fi+ | fi == 0 = (60 + 10) * 60+ | fi == 1 = (30 + 10) * 60+ | fi == 2 = (45 + 10) * 60+ | fi == 3 = (60 + 10) * 60+ | otherwise = (60 + 10) * 60+ -- | Construct an EphemerisCommonContent from an RTCM 1019 message.+-- toGpsEphemerisCommonContent :: MonadStore e m => Msg1019 -> m EphemerisCommonContent toGpsEphemerisCommonContent m = do toe <- toGpsTimeSec (m ^. msg1019_ephemeris ^. gpsEphemeris_wn) (m ^. msg1019_ephemeris ^. gpsEphemeris_toe)@@ -85,46 +134,96 @@ , _gnssSignal_code = 0 -- there is an L2P status flag in msg 1019, but I don't think that applies } , _ephemerisCommonContent_toe = toe- , _ephemerisCommonContent_ura = uriToUra (fromIntegral $ m ^. msg1019_ephemeris ^. gpsEphemeris_svHealth)- , _ephemerisCommonContent_fit_interval = fitInterval (m ^. msg1019_ephemeris ^. gpsEphemeris_fitInterval) (m ^. msg1019_ephemeris ^. gpsEphemeris_iodc)+ , _ephemerisCommonContent_ura = uriToUra (m ^. msg1019_ephemeris ^. gpsEphemeris_svHealth)+ , _ephemerisCommonContent_fit_interval = gpsFitInterval (m ^. msg1019_ephemeris ^. gpsEphemeris_fitInterval) (m ^. msg1019_ephemeris ^. gpsEphemeris_iodc) , _ephemerisCommonContent_valid = validateIodcIode (m ^. msg1019_ephemeris ^. gpsEphemeris_iodc) (m ^. msg1019_ephemeris ^. gpsEphemeris_iode) , _ephemerisCommonContent_health_bits = m ^. msg1019_ephemeris ^. gpsEphemeris_svHealth } +-- | Construct an EphemerisCommonContent from an RTCM 1020 message.+--+toGlonassEphemerisCommonContent :: MonadStore e m => Msg1020 -> m EphemerisCommonContent+toGlonassEphemerisCommonContent m = do+ toe <- toGlonassTimeSec (m ^. msg1020_ephemeris ^. glonassEphemeris_tb)+ pure EphemerisCommonContent+ { _ephemerisCommonContent_sid = GnssSignal+ { _gnssSignal_sat = m ^. msg1020_header ^. glonassEphemerisHeader_sat+ , _gnssSignal_code = 3+ }+ , _ephemerisCommonContent_toe = toe+ , _ephemerisCommonContent_ura = ftToUra (m ^. msg1020_ephemeris ^. glonassEphemeris_mft)+ , _ephemerisCommonContent_fit_interval = glonassFitInterval (m ^. msg1020_ephemeris ^. glonassEphemeris_p1)+ , _ephemerisCommonContent_valid = 1+ , _ephemerisCommonContent_health_bits = bool 0 1 $ (m ^. msg1020_ephemeris ^. glonassEphemeris_mln5) || (m ^. msg1020_ephemeris ^. glonassEphemeris_mi3)+ }++(##) :: (Floating a1, Integral a2) => a1 -> a2 -> a1+(##) p x = (2 ** p) * fromIntegral x+ -------------------------------------------------------------------------------- -- RTCM to SBP conversion utilities: RTCM Msgs. 1002 (L1 RTK), 1004 (L1+L2 RTK), -- 1005 (antenna position), 1006 (antenna position). -- | Convert an RTCM 1019 GPS ephemeris message into an SBP MsgEphemerisGps.-converter :: MonadStore e m => Msg1019 -> Conduit i m [SBPMsg]-converter m = do+--+gpsConverter :: MonadStore e m => Msg1019 -> Conduit i m [SBPMsg]+gpsConverter m = do common <- toGpsEphemerisCommonContent m toc <- toGpsTimeSec (m ^. msg1019_ephemeris ^. gpsEphemeris_wn) (m ^. msg1019_ephemeris ^. gpsEphemeris_toc)- let pi' = 3.1415926535898- p ## x = (2 ** p) * fromIntegral x- m' = MsgEphemerisGps- { _msgEphemerisGps_common = common- , _msgEphemerisGps_tgd = (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_tgd)- , _msgEphemerisGps_c_rs = (-5) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_rs)- , _msgEphemerisGps_c_rc = (-5) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_rc)- , _msgEphemerisGps_c_uc = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_uc)- , _msgEphemerisGps_c_us = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_us)- , _msgEphemerisGps_c_ic = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_ic)- , _msgEphemerisGps_c_is = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_is)- , _msgEphemerisGps_dn = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_dn)- , _msgEphemerisGps_m0 = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_m0)- , _msgEphemerisGps_ecc = (-33) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_ecc)- , _msgEphemerisGps_sqrta = (-19) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_sqrta)- , _msgEphemerisGps_omega0 = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_omega0)- , _msgEphemerisGps_omegadot = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_omegadot)- , _msgEphemerisGps_w = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_w)- , _msgEphemerisGps_inc = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_i0)- , _msgEphemerisGps_inc_dot = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_idot)- , _msgEphemerisGps_af0 = (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af0)- , _msgEphemerisGps_af1 = (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af1)- , _msgEphemerisGps_af2 = (-55) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af2)- , _msgEphemerisGps_iodc = m ^. msg1019_ephemeris ^. gpsEphemeris_iodc- , _msgEphemerisGps_iode = m ^. msg1019_ephemeris ^. gpsEphemeris_iode- , _msgEphemerisGps_toc = toc- }+ let pi' = 3.1415926535898+ m' = MsgEphemerisGps+ { _msgEphemerisGps_common = common+ , _msgEphemerisGps_tgd = (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_tgd)+ , _msgEphemerisGps_c_rs = (-5) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_rs)+ , _msgEphemerisGps_c_rc = (-5) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_rc)+ , _msgEphemerisGps_c_uc = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_uc)+ , _msgEphemerisGps_c_us = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_us)+ , _msgEphemerisGps_c_ic = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_ic)+ , _msgEphemerisGps_c_is = (-29) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_c_is)+ , _msgEphemerisGps_dn = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_dn)+ , _msgEphemerisGps_m0 = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_m0)+ , _msgEphemerisGps_ecc = (-33) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_ecc)+ , _msgEphemerisGps_sqrta = (-19) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_sqrta)+ , _msgEphemerisGps_omega0 = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_omega0)+ , _msgEphemerisGps_omegadot = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_omegadot)+ , _msgEphemerisGps_w = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_w)+ , _msgEphemerisGps_inc = pi' * (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_i0)+ , _msgEphemerisGps_inc_dot = pi' * (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_idot)+ , _msgEphemerisGps_af0 = (-31) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af0)+ , _msgEphemerisGps_af1 = (-43) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af1)+ , _msgEphemerisGps_af2 = (-55) ## (m ^. msg1019_ephemeris ^. gpsEphemeris_af2)+ , _msgEphemerisGps_iodc = m ^. msg1019_ephemeris ^. gpsEphemeris_iodc+ , _msgEphemerisGps_iode = m ^. msg1019_ephemeris ^. gpsEphemeris_iode+ , _msgEphemerisGps_toc = toc+ } yield [SBPMsgEphemerisGps m' $ toSBP m' 61440]++-- | Convert an RTCM 1020 GLONASS ephemeris message into an SBP MsgEphemerisGlo.+--+glonassConverter :: MonadStore e m => Msg1020 -> Conduit i m [SBPMsg]+glonassConverter m = do+ common <- toGlonassEphemerisCommonContent m+ let m' = MsgEphemerisGlo+ { _msgEphemerisGlo_common = common+ , _msgEphemerisGlo_gamma = (-40) ## (m ^. msg1020_ephemeris ^. glonassEphemeris_gammaN)+ , _msgEphemerisGlo_tau = (-30) ## (m ^. msg1020_ephemeris ^. glonassEphemeris_tauN)+ , _msgEphemerisGlo_d_tau = (-30) ## (m ^. msg1020_ephemeris ^. glonassEphemeris_mdeltatau)+ , _msgEphemerisGlo_pos = (* 1000) . ((-11) ##) <$>+ [ m ^. msg1020_ephemeris ^. glonassEphemeris_xn+ , m ^. msg1020_ephemeris ^. glonassEphemeris_yn+ , m ^. msg1020_ephemeris ^. glonassEphemeris_zn+ ]+ , _msgEphemerisGlo_vel = (* 1000) . ((-20) ##) <$>+ [ m ^. msg1020_ephemeris ^. glonassEphemeris_xndot+ , m ^. msg1020_ephemeris ^. glonassEphemeris_yndot+ , m ^. msg1020_ephemeris ^. glonassEphemeris_zndot+ ]+ , _msgEphemerisGlo_acc = (* 1000) . ((-30) ##) <$>+ [ m ^. msg1020_ephemeris ^. glonassEphemeris_xndotdot+ , m ^. msg1020_ephemeris ^. glonassEphemeris_yndotdot+ , m ^. msg1020_ephemeris ^. glonassEphemeris_zndotdot+ ]+ , _msgEphemerisGlo_fcn = (m ^. msg1020_header ^. glonassEphemerisHeader_channel) + 1+ , _msgEphemerisGlo_iod = ((m ^. msg1020_ephemeris ^. glonassEphemeris_tb) * 15 * 60) .&. 127+ }+ yield [SBPMsgEphemerisGlo m' $ toSBP m' 61440]
src/Data/RTCM3/SBP/Time.hs view
@@ -13,6 +13,7 @@ module Data.RTCM3.SBP.Time ( gpsLeapMillis+ , minuteMillis , hourMillis , dayMillis , weekMillis@@ -45,6 +46,16 @@ -- gpsLeapMillis :: Integer gpsLeapMillis = 1000 * gpsLeapSeconds++-- | Minute seconds+--+minuteSeconds :: Integer+minuteSeconds = 60++-- | Minute milliseconds+--+minuteMillis :: Integer+minuteMillis = 1000 * minuteSeconds -- | Hour seconds --