{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NoImplicitPrelude #-} module Data.RTCM3.Replay ( replayer ) where import BasicPrelude import Control.Concurrent hiding (yield) import Control.Lens import Data.Conduit import Data.RTCM3 import Data.Time import Data.Time.Calendar.WeekDate -- | Produce GPS time of week from a GPS UTC time. -- toTow :: UTCTime -> Word32 toTow t = floor since where (y, w, _d) = toWeekDate (utctDay t) begin = addDays (-1) $ fromWeekDate y w 1 since = 1000 * diffUTCTime t (UTCTime begin 0) -- | Produce current GPS time of week. -- currentTow :: MonadIO m => m Word32 currentTow = liftIO $ toTow . addUTCTime (fromIntegral gpsLeapSeconds) <$> getCurrentTime where gpsLeapSeconds = 18 :: Int -- | Delay between two time of week values - differences over 15 seconds are ignored. -- delayTow :: MonadIO m => Word32 -> Word32 -> m () delayTow tow tow' = when (tow' > tow) $ do let diff = tow' - tow unless (diff > diffMilliseconds) $ liftIO $ threadDelay $ fromIntegral $ diff * 1000 where diffMilliseconds = 15 * 1000 -- | Replay observations. -- replay :: MonadIO m => Word32 -> RTCM3Msg -> ConduitM i RTCM3Msg m Word32 replay tow = \case (RTCM3Msg1002 m _rtcm3) -> do let tow' = m ^. msg1002_header . gpsObservationHeader_tow delayTow tow tow' tow'' <- currentTow let n = set (msg1002_header . gpsObservationHeader_tow) tow'' m yield (RTCM3Msg1002 n (toRTCM3 n)) pure tow' (RTCM3Msg1004 m _rtcm3) -> do let tow' = m ^. msg1004_header . gpsObservationHeader_tow delayTow tow tow' tow'' <- currentTow let n = set (msg1004_header . gpsObservationHeader_tow) tow'' m yield (RTCM3Msg1004 n (toRTCM3 n)) pure tow' rtcm3Msg -> do yield rtcm3Msg pure tow replayer :: MonadIO m => Conduit RTCM3Msg m RTCM3Msg replayer = loop maxBound where loop tow = await >>= maybe (pure ()) ((>>= loop) . replay tow)