gnss-converters 0.1.20 → 0.2.0
raw patch · 4 files changed
+153/−174 lines, 4 filesdep −random
Dependencies removed: random
Files
- gnss-converters.cabal +1/−2
- src/Data/RTCM3/SBP.hs +102/−94
- src/Data/RTCM3/SBP/Types.hs +1/−10
- test/Test/Data/RTCM3/SBP.hs +49/−68
gnss-converters.cabal view
@@ -1,5 +1,5 @@ name: gnss-converters-version: 0.1.20+version: 0.2.0 synopsis: GNSS Converters. description: Haskell bindings for GNSS converters. homepage: http://github.com/swift-nav/gnss-converters@@ -29,7 +29,6 @@ , lens , monad-control , mtl- , random , resourcet , rtcm , sbp
src/Data/RTCM3/SBP.hs view
@@ -19,7 +19,6 @@ , toWn , mjdEpoch , updateGpsTime- , updateLock , convert , newStore ) where@@ -36,7 +35,6 @@ import Data.Time import Data.Word import SwiftNav.SBP-import System.Random --------------------------------------------------------------------------------@@ -173,25 +171,26 @@ fromEcefVal :: Int64 -> Double fromEcefVal x = fromIntegral x / 10000 -newGpsTime :: MonadStore e m => Word32 -> m GpsTime+newGpsTime :: MonadStore e m => Word32 -> m GpsTimeNano newGpsTime tow = do wn <- view storeWn >>= liftIO . readIORef- return GpsTime- { _gpsTime_tow = tow- , _gpsTime_wn = wn+ return GpsTimeNano+ { _gpsTimeNano_tow = tow+ , _gpsTimeNano_ns = 0+ , _gpsTimeNano_wn = wn } -- | If incoming TOW is less than stored TOW, rollover WN. ---updateGpsTime :: Word32 -> GpsTime -> GpsTime+updateGpsTime :: Word32 -> GpsTimeNano -> GpsTimeNano updateGpsTime tow gpsTime =- gpsTime & gpsTime_tow .~ tow &- if tow >= gpsTime ^. gpsTime_tow then id else- gpsTime_wn %~ (+ 1)+ gpsTime & gpsTimeNano_tow .~ tow &+ if tow >= gpsTime ^. gpsTimeNano_tow then id else+ gpsTimeNano_wn %~ (+ 1) -- | Produce GPS Time from Observation header, handling WN rollover. ---toGpsTime :: MonadStore e m => GpsObservationHeader -> m GpsTime+toGpsTime :: MonadStore e m => GpsObservationHeader -> m GpsTimeNano toGpsTime hdr = do let tow = hdr ^. gpsObservationHeader_tow station = hdr ^. gpsObservationHeader_station@@ -296,30 +295,37 @@ toCn0_L2 :: GpsL2ExtObservation -> Word8 toCn0_L2 = (^. gpsL2ExtObservation_cnr) -newLock :: IO Lock-newLock = do- counter <- randomIO- return Lock- { _lockTime = 0- , _lockCounter = counter- }---- | If incoming time is less than stored time, increment lock counter.----updateLock :: Word8 -> Lock -> Lock-updateLock time lock =- lock & lockTime .~ time &- if time >= lock ^. lockTime then id else- lockCounter %~ (+1)---- | Produce Lock Counter from Lock Time, handling cycle slips.+-- | Convert between DF013 and DF019 lock time to DF402 lock time ---toLock :: MonadStore e m => Word16 -> GnssSignal -> Word8 -> m Word16-toLock station sid time = do- lockMap <- view storeLockMap- lock <- liftIO $ newLock- liftIO $ fmap (^. lockCounter) $- modifyMap lockMap lock (station, sid) $ updateLock time+toLock :: Word8 -> Word8+toLock t =+ if t' < 32 then 0 else+ if t' < 64 then 1 else+ if t' < 128 then 2 else+ if t' < 256 then 3 else+ if t' < 512 then 4 else+ if t' < 1024 then 5 else+ if t' < 2048 then 6 else+ if t' < 4096 then 7 else+ if t' < 8192 then 8 else+ if t' < 16384 then 9 else+ if t' < 32768 then 10 else+ if t' < 65536 then 11 else+ if t' < 131072 then 12 else+ if t' < 262144 then 13 else+ if t' < 524288 then 14 else+ 15+ where+ t' :: Word32+ t' =+ 1000 *+ if t <= 23 then fromIntegral t else+ if t <= 47 then fromIntegral t * 2 - 24 else+ if t <= 71 then fromIntegral t * 4 - 120 else+ if t <= 95 then fromIntegral t * 8 - 408 else+ if t <= 119 then fromIntegral t * 16 - 1176 else+ if t <= 126 then fromIntegral t * 32 - 3096 else+ 937 -- | Construct sequenced SBP observation header --@@ -327,81 +333,85 @@ => Word8 -- ^ Total messages -> Word8 -- ^ Message in sequence -> GpsObservationHeader -- ^ RTCM observation header- -> m ObservationHeaderDep+ -> m ObservationHeader fromGpsObservationHeader totalMsgs n hdr = do t <- toGpsTime hdr- return ObservationHeaderDep- { _observationHeaderDep_t = t+ return ObservationHeader+ { _observationHeader_t = t -- First nibble is the size of the sequence (n), second nibble is the -- zero-indexed counter (ith packet of n). See observation header packing -- https://github.com/swift-nav/libsbp/blob/master/spec/yaml/swiftnav/sbp/observation.yaml#L63- , _observationHeaderDep_n_obs = totalMsgs `shiftL` 4 .|. n+ , _observationHeader_n_obs = totalMsgs `shiftL` 4 .|. n } -- | Construct an L1 GnssSignal ---toL1GnssSignal :: Word8 -> GpsL1Observation -> GnssSignal+toL1GnssSignal :: Word8 -> GpsL1Observation -> GnssSignal16 toL1GnssSignal sat l1 =- GnssSignal- { _gnssSignal_sat = fromIntegral $ sat - 1- , _gnssSignal_code = if l1 ^. gpsL1Observation_code then l1PSidCode else l1CSidCode- , _gnssSignal_reserved = 0+ GnssSignal16+ { _gnssSignal16_sat = sat+ , _gnssSignal16_code = if l1 ^. gpsL1Observation_code then l1PSidCode else l1CSidCode } -- | Construct an L1 SBP PackedObsContent an RTCM satellite vehicle observation -- fromL1SatelliteObservation :: MonadStore e m- => Word16 -- ^ Station ID- -> Word8 -- ^ Satellite PRN+ => Word8 -- ^ Satellite PRN -> GpsL1Observation -> GpsL1ExtObservation- -> m PackedObsContentDepC-fromL1SatelliteObservation station sat l1 l1e = do+ -> m PackedObsContent+fromL1SatelliteObservation sat l1 l1e = do -- Checks GPS L1 code indicator for RTCM message 1002. -- See DF010, pg. 3-17 of the RTCM3 spec. let sid = toL1GnssSignal sat l1- lock <- toLock station sid $ l1 ^. gpsL1Observation_lockTime- return PackedObsContentDepC- { _packedObsContentDepC_P = toP_L1 l1 l1e- , _packedObsContentDepC_L = toL_L1 l1 l1e- , _packedObsContentDepC_cn0 = toCn0_L1 l1e- , _packedObsContentDepC_lock = lock- , _packedObsContentDepC_sid = sid+ return PackedObsContent+ { _packedObsContent_P = toP_L1 l1 l1e+ , _packedObsContent_L = toL_L1 l1 l1e+ , _packedObsContent_D = Doppler 0 0+ , _packedObsContent_cn0 = toCn0_L1 l1e+ , _packedObsContent_lock = toLock $ l1 ^. gpsL1Observation_lockTime+ , _packedObsContent_sid = sid+ , _packedObsContent_flags = 0x7 -- Doppler Invalid+ -- 1/2 cycle phase ambiguity resolved+ -- carrier valid+ -- pseudorange valid } -- | Construct an L2 GnssSignal ---toL2GnssSignal :: Word8 -> GpsL2Observation -> Maybe GnssSignal+toL2GnssSignal :: Word8 -> GpsL2Observation -> Maybe GnssSignal16 toL2GnssSignal sat l2 = do code <- M.lookup (l2 ^. gpsL2Observation_code) l2codeToSBPSignalCode- return GnssSignal- { _gnssSignal_sat = fromIntegral $ sat - 1- , _gnssSignal_code = code- , _gnssSignal_reserved = 0+ return GnssSignal16+ { _gnssSignal16_sat = fromIntegral sat+ , _gnssSignal16_code = code } -- | Construct an L2 SBP PackedObsContent an RTCM satellite vehicle observation -- fromL2SatelliteObservation :: MonadStore e m- => Word16 -- ^ Station ID- -> Word8 -- ^ Satellite PRN+ => Word8 -- ^ Satellite PRN -> GpsL1Observation -> GpsL1ExtObservation -> GpsL2Observation -> GpsL2ExtObservation- -> m (Maybe PackedObsContentDepC)-fromL2SatelliteObservation station sat l1 l1e l2 l2e =+ -> m (Maybe PackedObsContent)+fromL2SatelliteObservation sat l1 l1e l2 l2e = -- Checks GPS L2 code indicator. -- See DF016, pg. 3-17 of the RTCM3 spec. maybe' (toL2GnssSignal sat l2) (return Nothing) $ \sid -> do- lock <- toLock station sid $ l2 ^. gpsL2Observation_lockTime- return $ Just PackedObsContentDepC- { _packedObsContentDepC_P = toP_L2 l1 l1e l2- , _packedObsContentDepC_L = toL_L2 l1 l1e l2 l2e- , _packedObsContentDepC_cn0 = toCn0_L2 l2e- , _packedObsContentDepC_lock = lock- , _packedObsContentDepC_sid = sid- }+ return $ Just PackedObsContent+ { _packedObsContent_P = toP_L2 l1 l1e l2+ , _packedObsContent_L = toL_L2 l1 l1e l2 l2e+ , _packedObsContent_D = Doppler 0 0+ , _packedObsContent_cn0 = toCn0_L2 l2e+ , _packedObsContent_lock = toLock $ l2 ^. gpsL2Observation_lockTime+ , _packedObsContent_sid = sid+ , _packedObsContent_flags = 0x7 -- Doppler Invalid+ -- 1/2 cycle phase ambiguity resolved+ -- carrier valid+ -- pseudorange valid+ } -- | Construct SBP GPS observation message (possibly chunked). --@@ -409,13 +419,13 @@ => GpsObservationHeader -- ^ RTCM observation header -> Word8 -- ^ Total messages -> Word8 -- ^ Message in sequence- -> [PackedObsContentDepC]- -> m MsgObsDepC+ -> [PackedObsContent]+ -> m MsgObs chunkToMsgObs hdr totalMsgs n packed = do header <- fromGpsObservationHeader totalMsgs n hdr- return MsgObsDepC- { _msgObsDepC_header = header- , _msgObsDepC_obs = packed+ return MsgObs+ { _msgObs_header = header+ , _msgObs_obs = packed } -- | 16 bit SBP Sender Id is 12 bit RTCM Station Id with high nibble or'd in@@ -431,9 +441,9 @@ -- | Construct an L1 SBP PackedObsContent from an RTCM Msg 1002. ---fromObservation1002 :: MonadStore e m => Word16 -> Observation1002 -> m [PackedObsContentDepC]-fromObservation1002 station obs = do- obs1 <- fromL1SatelliteObservation station sat l1 l1e+fromObservation1002 :: MonadStore e m => Observation1002 -> m [PackedObsContent]+fromObservation1002 obs = do+ obs1 <- fromL1SatelliteObservation sat l1 l1e return $ -- Only lower set of PRN numbers (1-32) are supported if sat > maxSats then mempty else@@ -449,21 +459,20 @@ -- -- This chunking takes places because the number of observations in a given 1002 -- may very well exceed the maximum SBP supported payload size of 255 bytes.-fromMsg1002 :: MonadStore e m => Msg1002 -> m [MsgObsDepC]+fromMsg1002 :: MonadStore e m => Msg1002 -> m [MsgObs] fromMsg1002 m = do- let hdr = m ^. msg1002_header- station = hdr ^. gpsObservationHeader_station- obs <- concatMapM (fromObservation1002 station) $ m ^. msg1002_observations+ let hdr = m ^. msg1002_header+ obs <- concatMapM fromObservation1002 $ m ^. msg1002_observations let chunks = zip [0..] $ chunksOf maxObsPerMessage obs totalMsgs = fromIntegral $ length chunks forM chunks $ uncurry $ chunkToMsgObs hdr totalMsgs -- | Construct an L1/L2 SBP PackedObsContent from an RTCM Msg 1004. ---fromObservation1004 :: MonadStore e m => Word16 -> Observation1004 -> m [PackedObsContentDepC]-fromObservation1004 station obs = do- obs1 <- fromL1SatelliteObservation station sat l1 l1e- obs2 <- fromL2SatelliteObservation station sat l1 l1e l2 l2e+fromObservation1004 :: MonadStore e m => Observation1004 -> m [PackedObsContent]+fromObservation1004 obs = do+ obs1 <- fromL1SatelliteObservation sat l1 l1e+ obs2 <- fromL2SatelliteObservation sat l1 l1e l2 l2e return $ -- Only lower set of PRN numbers (1-32) are supported if sat > maxSats then mempty else@@ -483,11 +492,10 @@ -- -- This chunking takes places because the number of observations in a given 1004 -- may very well exceed the maximum SBP supported payload size of 255 bytes.-fromMsg1004 :: MonadStore e m => Msg1004 -> m [MsgObsDepC]+fromMsg1004 :: MonadStore e m => Msg1004 -> m [MsgObs] fromMsg1004 m = do- let hdr = m ^. msg1004_header- station = hdr ^. gpsObservationHeader_station- obs <- concatMapM (fromObservation1004 station) $ m ^. msg1004_observations+ let hdr = m ^. msg1004_header+ obs <- concatMapM fromObservation1004 $ m ^. msg1004_observations let chunks = zip [0..] $ chunksOf maxObsPerMessage obs totalMsgs = fromIntegral $ length chunks forM chunks $ uncurry $ chunkToMsgObs hdr totalMsgs@@ -519,11 +527,11 @@ (RTCM3Msg1002 m _rtcm3) -> do let sender = m ^. msg1002_header ^. gpsObservationHeader_station m' <- fromMsg1002 m- return $ flip fmap m' $ \x -> SBPMsgObsDepC x $ toSBP x $ toSender sender+ return $ flip fmap m' $ \x -> SBPMsgObs x $ toSBP x $ toSender sender (RTCM3Msg1004 m _rtcm3) -> do let sender = m ^. msg1004_header ^. gpsObservationHeader_station m' <- fromMsg1004 m- return $ flip fmap m' $ \x -> SBPMsgObsDepC x $ toSBP x $ toSender sender+ return $ flip fmap m' $ \x -> SBPMsgObs x $ toSBP x $ toSender sender (RTCM3Msg1005 m _rtcm3) -> do let sender = m ^. msg1005_reference ^. antennaReference_station m' <- fromMsg1005 m@@ -542,4 +550,4 @@ newStore = do day <- utctDay <$> getCurrentTime let wn = fromIntegral $ div (diffDays day (fromGregorian 1980 1 6)) 7- Store <$> newIORef wn <*> newIORef mempty <*> newIORef mempty+ Store <$> newIORef wn <*> newIORef mempty
src/Data/RTCM3/SBP/Types.hs view
@@ -30,15 +30,7 @@ import Data.Word import SwiftNav.SBP -data Lock = Lock- { _lockTime :: Word8- , _lockCounter :: Word16- } deriving ( Eq )--$(makeLenses ''Lock)--type GpsTimeMap = HashMap Word16 GpsTime-type LockMap = HashMap (Word16, GnssSignal) Lock+type GpsTimeMap = HashMap Word16 GpsTimeNano instance Hashable GnssSignal where hashWithSalt s g = hashWithSalt s (g ^. gnssSignal_sat, g ^. gnssSignal_code, g ^. gnssSignal_reserved)@@ -74,7 +66,6 @@ data Store = Store { _storeWn :: IORef Word16- , _storeLockMap :: IORef LockMap , _storeGpsTimeMap :: IORef GpsTimeMap } deriving ( Eq )
test/Test/Data/RTCM3/SBP.hs view
@@ -23,7 +23,6 @@ import Data.IORef import Data.RTCM3.SBP import Data.RTCM3.SBP.Types-import Data.Word import SwiftNav.SBP import Test.HUnit.Approx import Test.Tasty@@ -31,7 +30,7 @@ decodeRTCMFile :: FilePath -> IO [SBPMsg] decodeRTCMFile filename = do- s <- Store <$> newIORef 1906 <*> newIORef mempty <*> newIORef mempty+ s <- Store <$> newIORef 1906 <*> newIORef mempty runResourceT $ runConvertT s $ runConduit $ sourceFile filename =$= conduitDecode =$=@@ -44,27 +43,27 @@ , msg' ^. msgBasePosEcef_z ) -isL1 :: PackedObsContentDepC -> Bool-isL1 obs = (obs ^. packedObsContentDepC_sid ^. gnssSignal_code) == l1CSidCode+isL1 :: PackedObsContent -> Bool+isL1 obs = (obs ^. packedObsContent_sid ^. gnssSignal16_code) == l1CSidCode -isL2 :: PackedObsContentDepC -> Bool+isL2 :: PackedObsContent -> Bool isL2 obs = code == l2CMSidCode || code == l2PSidCode where- code = obs ^. packedObsContentDepC_sid ^. gnssSignal_code+ code = obs ^. packedObsContent_sid ^. gnssSignal16_code -sat :: PackedObsContentDepC -> Word16-sat obs = obs ^. packedObsContentDepC_sid ^. gnssSignal_sat+sat :: PackedObsContent -> Word8+sat obs = obs ^. packedObsContent_sid ^. gnssSignal16_sat -cn0 :: PackedObsContentDepC -> Double-cn0 obs = 0.25 * fromIntegral (obs ^. packedObsContentDepC_cn0)+cn0 :: PackedObsContent -> Double+cn0 obs = 0.25 * fromIntegral (obs ^. packedObsContent_cn0) -pseudorange :: PackedObsContentDepC -> Double-pseudorange obs = fromIntegral (obs ^. packedObsContentDepC_P) / sbpCMinM+pseudorange :: PackedObsContent -> Double+pseudorange obs = fromIntegral (obs ^. packedObsContent_P) / sbpCMinM -carrierPhase :: PackedObsContentDepC -> Double+carrierPhase :: PackedObsContent -> Double carrierPhase obs = whole + fraction where- phase = obs ^. packedObsContentDepC_L+ phase = obs ^. packedObsContent_L whole = fromIntegral (phase ^. carrierPhase_i) fraction = fromIntegral (phase ^. carrierPhase_f) / q32Width @@ -73,22 +72,22 @@ assertEqual "Base station position error!" pos $ basePosition posEcef assertExpectedBase _ _ = assertFailure "Invalid message type!" -assertObsHeader :: SBPMsg -> ObservationHeaderDep -> Assertion-assertObsHeader (SBPMsgObsDepC obs _) header =- assertEqual "Observation header is not equal" header $ obs ^. msgObsDepC_header+assertObsHeader :: SBPMsg -> ObservationHeader -> Assertion+assertObsHeader (SBPMsgObs obs _) header =+ assertEqual "Observation header is not equal" header $ obs ^. msgObs_header assertObsHeader _ _ = assertFailure "Invalid message type!" -assertObs :: HashMap Word16 (Double, Double, Double)- -> PackedObsContentDepC+assertObs :: HashMap Word8 (Double, Double, Double)+ -> PackedObsContent -> Double -- ^ Pseudorange tolerance (meters) -> Double -- ^ Carrier phase tolerance (cycles) -> Word8 -- ^ Satellite band code -> Assertion assertObs truth obs ptol ctol sig = do- let prn = 1 + sat obs+ let prn = sat obs def = (0, 0, 0) (p, c, snr) = lookupDefault def prn truth- code = obs ^. packedObsContentDepC_sid ^. gnssSignal_code+ code = obs ^. packedObsContent_sid ^. gnssSignal16_code msg' = textToString $ "PRN=" ++ show prn ++ " CODE=" ++ show code -- Pseudorange representation error assertApproxEqual ("Incorrect pseudorange" ++ msg') ptol p $ pseudorange obs@@ -99,11 +98,11 @@ assertEqual ("Incorrect code" ++ msg') sig code assertMsgObs :: SBPMsg -> Assertion-assertMsgObs (SBPMsgObsDepC obs' _) = do+assertMsgObs (SBPMsgObs obs' _) = do let ptol = 0.020 -- 2cm representation errorn ctol_L1 = 0.005 -- carrier phase / L1 wavelength = 0.001m/0.190m cycles ctol_L2 = 0.004 -- carrier phase / L2 wavelength = 0.001m/0.250m cycles- forM_ (obs' ^. msgObsDepC_obs) $ \packed ->+ forM_ (obs' ^. msgObs_obs) $ \packed -> case () of _ | isL1 packed -> assertObs testObs_L1 packed ptol ctol_L1 l1CSidCode | isL2 packed -> assertObs testObs_L2 packed ptol ctol_L2 l2PSidCode@@ -111,13 +110,13 @@ assertMsgObs _ = assertFailure "Invalid message type!" assertMsgObsLength :: SBPMsg -> Int -> Assertion-assertMsgObsLength (SBPMsgObsDepC obs' _) len = length (obs' ^. msgObsDepC_obs) @?= len+assertMsgObsLength (SBPMsgObs obs' _) len = length (obs' ^. msgObs_obs) @?= len assertMsgObsLength _ _ = assertFailure "Invalid message type!" -- | L1 observations: PRN => Pseudorange, Carrier Phase, SNR -- -- From fixtures/rinex/ucsf_bard_four_seconds.obs RINEX-testObs_L1 :: HashMap Word16 (Double, Double, Double)+testObs_L1 :: HashMap Word8 (Double, Double, Double) testObs_L1 = fromList [ (5, (20982568.242, 110264218.428, 50.500)) , (31, (24390286.418, 128171817.525, 43.000)) , (25, (20560669.144, 108047101.226, 51.750))@@ -131,7 +130,7 @@ -- | L2 observations: PRN => Pseudorange, Carrier Phase, SNR -- -- From fixtures/rinex/ucsf_bard_four_seconds.obs RINEX-testObs_L2 :: HashMap Word16 (Double, Double, Double)+testObs_L2 :: HashMap Word8 (Double, Double, Double) testObs_L2 = fromList [ (5, (20982564.742, 85920194.806, 40.000)) , (31, (24390281.338, 99874145.710, 22.750)) , (25, (20560668.244, 84192554.659, 42.750))@@ -155,41 +154,41 @@ assertExpectedBase (msgs !! 0) expectedBasePos assertExpectedBase (msgs !! 5) expectedBasePos -- Message 1- assertObsHeader (msgs !! 1) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86354000 1906- , _observationHeaderDep_n_obs = 32+ assertObsHeader (msgs !! 1) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86354000 0 1906+ , _observationHeader_n_obs = 32 } assertMsgObsLength (msgs !! 1) 15 assertMsgObs (msgs !! 1) -- Message 2- assertObsHeader (msgs !! 2) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86354000 1906- , _observationHeaderDep_n_obs = 33+ assertObsHeader (msgs !! 2) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86354000 0 1906+ , _observationHeader_n_obs = 33 } assertMsgObs (msgs !! 2) assertMsgObsLength (msgs !! 2) 1 -- Message 3- assertObsHeader (msgs !! 3) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86355000 1906- , _observationHeaderDep_n_obs = 32+ assertObsHeader (msgs !! 3) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86355000 0 1906+ , _observationHeader_n_obs = 32 } assertMsgObsLength (msgs !! 3) 15 -- Message 4- assertObsHeader (msgs !! 4) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86355000 1906- , _observationHeaderDep_n_obs = 33+ assertObsHeader (msgs !! 4) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86355000 0 1906+ , _observationHeader_n_obs = 33 } assertMsgObsLength (msgs !! 4) 1 -- Message 6- assertObsHeader (msgs !! 6) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86356000 1906- , _observationHeaderDep_n_obs = 32+ assertObsHeader (msgs !! 6) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86356000 0 1906+ , _observationHeader_n_obs = 32 } assertMsgObsLength (msgs !! 6) 15 -- Message 7- assertObsHeader (msgs !! 7) ObservationHeaderDep {- _observationHeaderDep_t = GpsTime 86356000 1906- , _observationHeaderDep_n_obs = 33+ assertObsHeader (msgs !! 7) ObservationHeader {+ _observationHeader_t = GpsTimeNano 86356000 0 1906+ , _observationHeader_n_obs = 33 } assertMsgObsLength (msgs !! 7) 1 ]@@ -215,34 +214,17 @@ testUpdateGpsTime = testGroup "Update GPS Time" [ testCase "old TOW < new TOW" $ do- let old = GpsTime 1 10+ let old = GpsTimeNano 1 0 10 new = updateGpsTime 2 old- new ^. gpsTime_wn @?= 10+ new ^. gpsTimeNano_wn @?= 10 , testCase "old TOW = new TOW" $ do- let old = GpsTime 1 10+ let old = GpsTimeNano 1 0 10 new = updateGpsTime 1 old- new ^. gpsTime_wn @?= 10+ new ^. gpsTimeNano_wn @?= 10 , testCase "old TOW > new TOW" $ do- let old = GpsTime 1 10+ let old = GpsTimeNano 1 0 10 new = updateGpsTime 0 old- new ^. gpsTime_wn @?= 11- ]--testUpdateLock :: TestTree-testUpdateLock =- testGroup "Update Lock"- [ testCase "old time < new time" $ do- let old = Lock 1 10- new = updateLock 2 old- new ^. lockCounter @?= 10- , testCase "old time = new time" $ do- let old = Lock 1 10- new = updateLock 1 old- new ^. lockCounter @?= 10- , testCase "old time > new time" $ do- let old = Lock 1 10- new = updateLock 0 old- new ^. lockCounter @?= 11+ new ^. gpsTimeNano_wn @?= 11 ] tests :: TestTree@@ -251,5 +233,4 @@ [ testMsg1004 , testToWn , testUpdateGpsTime- , testUpdateLock ]