packages feed

sbp-6.2.2: src/SwiftNav/SBP/Ssr.hs

{-# OPTIONS_GHC -fno-warn-unused-imports #-}
{-# LANGUAGE NoImplicitPrelude           #-}
{-# LANGUAGE TemplateHaskell             #-}
{-# LANGUAGE RecordWildCards             #-}

-- |
-- Module:      SwiftNav.SBP.Ssr
-- Copyright:   Copyright (C) 2015-2021 Swift Navigation, Inc.
-- License:     MIT
-- Contact:     https://support.swiftnav.com
-- Stability:   experimental
-- Portability: portable
--
-- \< Precise State Space Representation (SSR) corrections format \>

module SwiftNav.SBP.Ssr
  ( module SwiftNav.SBP.Ssr
  ) where

import BasicPrelude
import Control.Lens
import Control.Monad.Loops
import Data.Binary
import Data.Binary.Get
import Data.Binary.IEEE754
import Data.Binary.Put
import Data.ByteString.Lazy    hiding (ByteString)
import Data.Int
import Data.Word
import SwiftNav.SBP.TH
import SwiftNav.SBP.Types
import SwiftNav.SBP.Gnss

{-# ANN module ("HLint: ignore Use camelCase"::String) #-}
{-# ANN module ("HLint: ignore Redundant do"::String) #-}
{-# ANN module ("HLint: ignore Use newtype instead of data"::String) #-}


-- | CodeBiasesContent.
--
-- Code biases are to be added to pseudorange. The corrections conform with
-- RTCMv3 MT 1059 / 1065.
data CodeBiasesContent = CodeBiasesContent
  { _codeBiasesContent_code :: !Word8
    -- ^ Signal encoded following RTCM specifications (DF380, DF381, DF382 and
    -- DF467).
  , _codeBiasesContent_value :: !Int16
    -- ^ Code bias value
  } deriving ( Show, Read, Eq )

instance Binary CodeBiasesContent where
  get = do
    _codeBiasesContent_code <- getWord8
    _codeBiasesContent_value <- (fromIntegral <$> getWord16le)
    pure CodeBiasesContent {..}

  put CodeBiasesContent {..} = do
    putWord8 _codeBiasesContent_code
    (putWord16le . fromIntegral) _codeBiasesContent_value

$(makeJSON "_codeBiasesContent_" ''CodeBiasesContent)
$(makeLenses ''CodeBiasesContent)

-- | PhaseBiasesContent.
--
-- Phase biases are to be added to carrier phase measurements.
data PhaseBiasesContent = PhaseBiasesContent
  { _phaseBiasesContent_code                     :: !Word8
    -- ^ Signal encoded following RTCM specifications (DF380, DF381, DF382 and
    -- DF467)
  , _phaseBiasesContent_integer_indicator        :: !Word8
    -- ^ Indicator for integer property
  , _phaseBiasesContent_widelane_integer_indicator :: !Word8
    -- ^ Indicator for two groups of Wide-Lane(s) integer property
  , _phaseBiasesContent_discontinuity_counter    :: !Word8
    -- ^ Signal phase discontinuity counter. Increased for every discontinuity
    -- in phase.
  , _phaseBiasesContent_bias                     :: !Int32
    -- ^ Phase bias for specified signal
  } deriving ( Show, Read, Eq )

instance Binary PhaseBiasesContent where
  get = do
    _phaseBiasesContent_code <- getWord8
    _phaseBiasesContent_integer_indicator <- getWord8
    _phaseBiasesContent_widelane_integer_indicator <- getWord8
    _phaseBiasesContent_discontinuity_counter <- getWord8
    _phaseBiasesContent_bias <- (fromIntegral <$> getWord32le)
    pure PhaseBiasesContent {..}

  put PhaseBiasesContent {..} = do
    putWord8 _phaseBiasesContent_code
    putWord8 _phaseBiasesContent_integer_indicator
    putWord8 _phaseBiasesContent_widelane_integer_indicator
    putWord8 _phaseBiasesContent_discontinuity_counter
    (putWord32le . fromIntegral) _phaseBiasesContent_bias

$(makeJSON "_phaseBiasesContent_" ''PhaseBiasesContent)
$(makeLenses ''PhaseBiasesContent)

-- | STECHeader.
--
-- A full set of STEC information will likely span multiple SBP messages,
-- since SBP message a limited to 255 bytes.  The header is used to tie
-- multiple SBP messages into a sequence.
data STECHeader = STECHeader
  { _sTECHeader_tile_set_id   :: !Word16
    -- ^ Unique identifier of the tile set this tile belongs to.
  , _sTECHeader_tile_id       :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
  , _sTECHeader_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _sTECHeader_num_msgs      :: !Word8
    -- ^ Number of messages in the dataset
  , _sTECHeader_seq_num       :: !Word8
    -- ^ Position of this message in the dataset
  , _sTECHeader_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _sTECHeader_iod_atmo      :: !Word8
    -- ^ IOD of the SSR atmospheric correction
  } deriving ( Show, Read, Eq )

instance Binary STECHeader where
  get = do
    _sTECHeader_tile_set_id <- getWord16le
    _sTECHeader_tile_id <- getWord16le
    _sTECHeader_time <- get
    _sTECHeader_num_msgs <- getWord8
    _sTECHeader_seq_num <- getWord8
    _sTECHeader_update_interval <- getWord8
    _sTECHeader_iod_atmo <- getWord8
    pure STECHeader {..}

  put STECHeader {..} = do
    putWord16le _sTECHeader_tile_set_id
    putWord16le _sTECHeader_tile_id
    put _sTECHeader_time
    putWord8 _sTECHeader_num_msgs
    putWord8 _sTECHeader_seq_num
    putWord8 _sTECHeader_update_interval
    putWord8 _sTECHeader_iod_atmo

$(makeJSON "_sTECHeader_" ''STECHeader)
$(makeLenses ''STECHeader)

-- | GriddedCorrectionHeader.
--
-- The LPP message contains nested variable length arrays which are not
-- supported in SBP, so each grid point will be identified by the index.
data GriddedCorrectionHeader = GriddedCorrectionHeader
  { _griddedCorrectionHeader_tile_set_id           :: !Word16
    -- ^ Unique identifier of the tile set this tile belongs to.
  , _griddedCorrectionHeader_tile_id               :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
  , _griddedCorrectionHeader_time                  :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _griddedCorrectionHeader_num_msgs              :: !Word16
    -- ^ Number of messages in the dataset
  , _griddedCorrectionHeader_seq_num               :: !Word16
    -- ^ Position of this message in the dataset
  , _griddedCorrectionHeader_update_interval       :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _griddedCorrectionHeader_iod_atmo              :: !Word8
    -- ^ IOD of the SSR atmospheric correction
  , _griddedCorrectionHeader_tropo_quality_indicator :: !Word8
    -- ^ Quality of the troposphere data. Encoded following RTCM DF389
    -- specification in units of m.
  } deriving ( Show, Read, Eq )

instance Binary GriddedCorrectionHeader where
  get = do
    _griddedCorrectionHeader_tile_set_id <- getWord16le
    _griddedCorrectionHeader_tile_id <- getWord16le
    _griddedCorrectionHeader_time <- get
    _griddedCorrectionHeader_num_msgs <- getWord16le
    _griddedCorrectionHeader_seq_num <- getWord16le
    _griddedCorrectionHeader_update_interval <- getWord8
    _griddedCorrectionHeader_iod_atmo <- getWord8
    _griddedCorrectionHeader_tropo_quality_indicator <- getWord8
    pure GriddedCorrectionHeader {..}

  put GriddedCorrectionHeader {..} = do
    putWord16le _griddedCorrectionHeader_tile_set_id
    putWord16le _griddedCorrectionHeader_tile_id
    put _griddedCorrectionHeader_time
    putWord16le _griddedCorrectionHeader_num_msgs
    putWord16le _griddedCorrectionHeader_seq_num
    putWord8 _griddedCorrectionHeader_update_interval
    putWord8 _griddedCorrectionHeader_iod_atmo
    putWord8 _griddedCorrectionHeader_tropo_quality_indicator

$(makeJSON "_griddedCorrectionHeader_" ''GriddedCorrectionHeader)
$(makeLenses ''GriddedCorrectionHeader)

-- | STECSatElement.
--
-- STEC polynomial for the given satellite.
data STECSatElement = STECSatElement
  { _sTECSatElement_sv_id                :: !SvId
    -- ^ Unique space vehicle identifier
  , _sTECSatElement_stec_quality_indicator :: !Word8
    -- ^ Quality of the STEC data. Encoded following RTCM DF389 specification
    -- but in units of TECU instead of m.
  , _sTECSatElement_stec_coeff           :: ![Int16]
    -- ^ Coefficients of the STEC polynomial in the order of C00, C01, C10, C11.
    -- C00 = 0.05 TECU, C01/C10 = 0.02 TECU/deg, C11 0.02 TECU/deg^2
  } deriving ( Show, Read, Eq )

instance Binary STECSatElement where
  get = do
    _sTECSatElement_sv_id <- get
    _sTECSatElement_stec_quality_indicator <- getWord8
    _sTECSatElement_stec_coeff <- replicateM 4 (fromIntegral <$> getWord16le)
    pure STECSatElement {..}

  put STECSatElement {..} = do
    put _sTECSatElement_sv_id
    putWord8 _sTECSatElement_stec_quality_indicator
    mapM_ (putWord16le . fromIntegral) _sTECSatElement_stec_coeff

$(makeJSON "_sTECSatElement_" ''STECSatElement)
$(makeLenses ''STECSatElement)

-- | TroposphericDelayCorrectionNoStd.
--
-- Troposphere vertical delays at the grid point.
data TroposphericDelayCorrectionNoStd = TroposphericDelayCorrectionNoStd
  { _troposphericDelayCorrectionNoStd_hydro :: !Int16
    -- ^ Hydrostatic vertical delay
  , _troposphericDelayCorrectionNoStd_wet :: !Int8
    -- ^ Wet vertical delay
  } deriving ( Show, Read, Eq )

instance Binary TroposphericDelayCorrectionNoStd where
  get = do
    _troposphericDelayCorrectionNoStd_hydro <- (fromIntegral <$> getWord16le)
    _troposphericDelayCorrectionNoStd_wet <- (fromIntegral <$> getWord8)
    pure TroposphericDelayCorrectionNoStd {..}

  put TroposphericDelayCorrectionNoStd {..} = do
    (putWord16le . fromIntegral) _troposphericDelayCorrectionNoStd_hydro
    (putWord8 . fromIntegral) _troposphericDelayCorrectionNoStd_wet

$(makeJSON "_troposphericDelayCorrectionNoStd_" ''TroposphericDelayCorrectionNoStd)
$(makeLenses ''TroposphericDelayCorrectionNoStd)

-- | TroposphericDelayCorrection.
--
-- Troposphere vertical delays (mean and standard deviation) at the grid
-- point.
data TroposphericDelayCorrection = TroposphericDelayCorrection
  { _troposphericDelayCorrection_hydro :: !Int16
    -- ^ Hydrostatic vertical delay. Add 2.3 m to get actual value.
  , _troposphericDelayCorrection_wet  :: !Int8
    -- ^ Wet vertical delay. Add 0.252 m to get actual value.
  , _troposphericDelayCorrection_stddev :: !Word8
    -- ^ Standard deviation encoded using a similar method as RTCM DF389. The
    -- upper 3 bit are the class, the lower 5 bits are the value. Standard
    -- deviation [mm] = (3^class * (1 + value/16) - 1)
  } deriving ( Show, Read, Eq )

instance Binary TroposphericDelayCorrection where
  get = do
    _troposphericDelayCorrection_hydro <- (fromIntegral <$> getWord16le)
    _troposphericDelayCorrection_wet <- (fromIntegral <$> getWord8)
    _troposphericDelayCorrection_stddev <- getWord8
    pure TroposphericDelayCorrection {..}

  put TroposphericDelayCorrection {..} = do
    (putWord16le . fromIntegral) _troposphericDelayCorrection_hydro
    (putWord8 . fromIntegral) _troposphericDelayCorrection_wet
    putWord8 _troposphericDelayCorrection_stddev

$(makeJSON "_troposphericDelayCorrection_" ''TroposphericDelayCorrection)
$(makeLenses ''TroposphericDelayCorrection)

-- | STECResidualNoStd.
--
-- STEC residual for the given satellite at the grid point.
data STECResidualNoStd = STECResidualNoStd
  { _sTECResidualNoStd_sv_id  :: !SvId
    -- ^ space vehicle identifier
  , _sTECResidualNoStd_residual :: !Int16
    -- ^ STEC residual
  } deriving ( Show, Read, Eq )

instance Binary STECResidualNoStd where
  get = do
    _sTECResidualNoStd_sv_id <- get
    _sTECResidualNoStd_residual <- (fromIntegral <$> getWord16le)
    pure STECResidualNoStd {..}

  put STECResidualNoStd {..} = do
    put _sTECResidualNoStd_sv_id
    (putWord16le . fromIntegral) _sTECResidualNoStd_residual

$(makeJSON "_sTECResidualNoStd_" ''STECResidualNoStd)
$(makeLenses ''STECResidualNoStd)

-- | STECResidual.
--
-- STEC residual (mean and standard deviation) for the given satellite at the
-- grid point.
data STECResidual = STECResidual
  { _sTECResidual_sv_id  :: !SvId
    -- ^ space vehicle identifier
  , _sTECResidual_residual :: !Int16
    -- ^ STEC residual
  , _sTECResidual_stddev :: !Word8
    -- ^ Standard deviation encoded using a similar method as RTCM DF389. The
    -- upper 3 bit are the class, the lower 5 bits are the value. Standard
    -- deviation [TECU] = (3^class * (1 + value/16) - 1) * 0.1
  } deriving ( Show, Read, Eq )

instance Binary STECResidual where
  get = do
    _sTECResidual_sv_id <- get
    _sTECResidual_residual <- (fromIntegral <$> getWord16le)
    _sTECResidual_stddev <- getWord8
    pure STECResidual {..}

  put STECResidual {..} = do
    put _sTECResidual_sv_id
    (putWord16le . fromIntegral) _sTECResidual_residual
    putWord8 _sTECResidual_stddev

$(makeJSON "_sTECResidual_" ''STECResidual)
$(makeLenses ''STECResidual)

msgSsrOrbitClock :: Word16
msgSsrOrbitClock = 0x05DD

-- | SBP class for message MSG_SSR_ORBIT_CLOCK (0x05DD).
--
-- The precise orbit and clock correction message is to be applied as a delta
-- correction to broadcast ephemeris and is an equivalent to the 1060 /1066
-- RTCM message types.
data MsgSsrOrbitClock = MsgSsrOrbitClock
  { _msgSsrOrbitClock_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrOrbitClock_sid           :: !GnssSignal
    -- ^ GNSS signal identifier (16 bit)
  , _msgSsrOrbitClock_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrOrbitClock_iod_ssr       :: !Word8
    -- ^ IOD of the SSR correction. A change of Issue Of Data SSR is used to
    -- indicate a change in the SSR generating configuration
  , _msgSsrOrbitClock_iod           :: !Word32
    -- ^ Issue of broadcast ephemeris data or IODCRC (Beidou)
  , _msgSsrOrbitClock_radial        :: !Int32
    -- ^ Orbit radial delta correction
  , _msgSsrOrbitClock_along         :: !Int32
    -- ^ Orbit along delta correction
  , _msgSsrOrbitClock_cross         :: !Int32
    -- ^ Orbit along delta correction
  , _msgSsrOrbitClock_dot_radial    :: !Int32
    -- ^ Velocity of orbit radial delta correction
  , _msgSsrOrbitClock_dot_along     :: !Int32
    -- ^ Velocity of orbit along delta correction
  , _msgSsrOrbitClock_dot_cross     :: !Int32
    -- ^ Velocity of orbit cross delta correction
  , _msgSsrOrbitClock_c0            :: !Int32
    -- ^ C0 polynomial coefficient for correction of broadcast satellite clock
  , _msgSsrOrbitClock_c1            :: !Int32
    -- ^ C1 polynomial coefficient for correction of broadcast satellite clock
  , _msgSsrOrbitClock_c2            :: !Int32
    -- ^ C2 polynomial coefficient for correction of broadcast satellite clock
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrOrbitClock where
  get = do
    _msgSsrOrbitClock_time <- get
    _msgSsrOrbitClock_sid <- get
    _msgSsrOrbitClock_update_interval <- getWord8
    _msgSsrOrbitClock_iod_ssr <- getWord8
    _msgSsrOrbitClock_iod <- getWord32le
    _msgSsrOrbitClock_radial <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_along <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_cross <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_dot_radial <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_dot_along <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_dot_cross <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_c0 <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_c1 <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClock_c2 <- (fromIntegral <$> getWord32le)
    pure MsgSsrOrbitClock {..}

  put MsgSsrOrbitClock {..} = do
    put _msgSsrOrbitClock_time
    put _msgSsrOrbitClock_sid
    putWord8 _msgSsrOrbitClock_update_interval
    putWord8 _msgSsrOrbitClock_iod_ssr
    putWord32le _msgSsrOrbitClock_iod
    (putWord32le . fromIntegral) _msgSsrOrbitClock_radial
    (putWord32le . fromIntegral) _msgSsrOrbitClock_along
    (putWord32le . fromIntegral) _msgSsrOrbitClock_cross
    (putWord32le . fromIntegral) _msgSsrOrbitClock_dot_radial
    (putWord32le . fromIntegral) _msgSsrOrbitClock_dot_along
    (putWord32le . fromIntegral) _msgSsrOrbitClock_dot_cross
    (putWord32le . fromIntegral) _msgSsrOrbitClock_c0
    (putWord32le . fromIntegral) _msgSsrOrbitClock_c1
    (putWord32le . fromIntegral) _msgSsrOrbitClock_c2

$(makeSBP 'msgSsrOrbitClock ''MsgSsrOrbitClock)
$(makeJSON "_msgSsrOrbitClock_" ''MsgSsrOrbitClock)
$(makeLenses ''MsgSsrOrbitClock)

msgSsrCodeBiases :: Word16
msgSsrCodeBiases = 0x05E1

-- | SBP class for message MSG_SSR_CODE_BIASES (0x05E1).
--
-- The precise code biases message is to be added to the pseudorange of the
-- corresponding signal to get corrected pseudorange. It is an equivalent to
-- the 1059 / 1065 RTCM message types.
data MsgSsrCodeBiases = MsgSsrCodeBiases
  { _msgSsrCodeBiases_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrCodeBiases_sid           :: !GnssSignal
    -- ^ GNSS signal identifier (16 bit)
  , _msgSsrCodeBiases_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrCodeBiases_iod_ssr       :: !Word8
    -- ^ IOD of the SSR correction. A change of Issue Of Data SSR is used to
    -- indicate a change in the SSR generating configuration
  , _msgSsrCodeBiases_biases        :: ![CodeBiasesContent]
    -- ^ Code biases for the different satellite signals
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrCodeBiases where
  get = do
    _msgSsrCodeBiases_time <- get
    _msgSsrCodeBiases_sid <- get
    _msgSsrCodeBiases_update_interval <- getWord8
    _msgSsrCodeBiases_iod_ssr <- getWord8
    _msgSsrCodeBiases_biases <- whileM (not <$> isEmpty) get
    pure MsgSsrCodeBiases {..}

  put MsgSsrCodeBiases {..} = do
    put _msgSsrCodeBiases_time
    put _msgSsrCodeBiases_sid
    putWord8 _msgSsrCodeBiases_update_interval
    putWord8 _msgSsrCodeBiases_iod_ssr
    mapM_ put _msgSsrCodeBiases_biases

$(makeSBP 'msgSsrCodeBiases ''MsgSsrCodeBiases)
$(makeJSON "_msgSsrCodeBiases_" ''MsgSsrCodeBiases)
$(makeLenses ''MsgSsrCodeBiases)

msgSsrPhaseBiases :: Word16
msgSsrPhaseBiases = 0x05E6

-- | SBP class for message MSG_SSR_PHASE_BIASES (0x05E6).
--
-- The precise phase biases message contains the biases to be added to the
-- carrier phase of the corresponding signal to get corrected carrier phase
-- measurement, as well as the satellite yaw angle to be applied to compute
-- the phase wind-up correction. It is typically an equivalent to the 1265
-- RTCM message types.
data MsgSsrPhaseBiases = MsgSsrPhaseBiases
  { _msgSsrPhaseBiases_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrPhaseBiases_sid           :: !GnssSignal
    -- ^ GNSS signal identifier (16 bit)
  , _msgSsrPhaseBiases_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrPhaseBiases_iod_ssr       :: !Word8
    -- ^ IOD of the SSR correction. A change of Issue Of Data SSR is used to
    -- indicate a change in the SSR generating configuration
  , _msgSsrPhaseBiases_dispersive_bias :: !Word8
    -- ^ Indicator for the dispersive phase biases property.
  , _msgSsrPhaseBiases_mw_consistency :: !Word8
    -- ^ Consistency indicator for Melbourne-Wubbena linear combinations
  , _msgSsrPhaseBiases_yaw           :: !Word16
    -- ^ Satellite yaw angle
  , _msgSsrPhaseBiases_yaw_rate      :: !Int8
    -- ^ Satellite yaw angle rate
  , _msgSsrPhaseBiases_biases        :: ![PhaseBiasesContent]
    -- ^ Phase biases corrections for a satellite being tracked.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrPhaseBiases where
  get = do
    _msgSsrPhaseBiases_time <- get
    _msgSsrPhaseBiases_sid <- get
    _msgSsrPhaseBiases_update_interval <- getWord8
    _msgSsrPhaseBiases_iod_ssr <- getWord8
    _msgSsrPhaseBiases_dispersive_bias <- getWord8
    _msgSsrPhaseBiases_mw_consistency <- getWord8
    _msgSsrPhaseBiases_yaw <- getWord16le
    _msgSsrPhaseBiases_yaw_rate <- (fromIntegral <$> getWord8)
    _msgSsrPhaseBiases_biases <- whileM (not <$> isEmpty) get
    pure MsgSsrPhaseBiases {..}

  put MsgSsrPhaseBiases {..} = do
    put _msgSsrPhaseBiases_time
    put _msgSsrPhaseBiases_sid
    putWord8 _msgSsrPhaseBiases_update_interval
    putWord8 _msgSsrPhaseBiases_iod_ssr
    putWord8 _msgSsrPhaseBiases_dispersive_bias
    putWord8 _msgSsrPhaseBiases_mw_consistency
    putWord16le _msgSsrPhaseBiases_yaw
    (putWord8 . fromIntegral) _msgSsrPhaseBiases_yaw_rate
    mapM_ put _msgSsrPhaseBiases_biases

$(makeSBP 'msgSsrPhaseBiases ''MsgSsrPhaseBiases)
$(makeJSON "_msgSsrPhaseBiases_" ''MsgSsrPhaseBiases)
$(makeLenses ''MsgSsrPhaseBiases)

msgSsrStecCorrectionDep :: Word16
msgSsrStecCorrectionDep = 0x05FB

-- | SBP class for message MSG_SSR_STEC_CORRECTION_DEP (0x05FB).
--
-- Deprecated.
data MsgSsrStecCorrectionDep = MsgSsrStecCorrectionDep
  { _msgSsrStecCorrectionDep_header      :: !STECHeader
    -- ^ Header of a STEC polynomial coefficient message.
  , _msgSsrStecCorrectionDep_stec_sat_list :: ![STECSatElement]
    -- ^ Array of STEC polynomial coefficients for each space vehicle.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrStecCorrectionDep where
  get = do
    _msgSsrStecCorrectionDep_header <- get
    _msgSsrStecCorrectionDep_stec_sat_list <- whileM (not <$> isEmpty) get
    pure MsgSsrStecCorrectionDep {..}

  put MsgSsrStecCorrectionDep {..} = do
    put _msgSsrStecCorrectionDep_header
    mapM_ put _msgSsrStecCorrectionDep_stec_sat_list

$(makeSBP 'msgSsrStecCorrectionDep ''MsgSsrStecCorrectionDep)
$(makeJSON "_msgSsrStecCorrectionDep_" ''MsgSsrStecCorrectionDep)
$(makeLenses ''MsgSsrStecCorrectionDep)

data BoundsHeader = BoundsHeader
  { _boundsHeader_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the bound
  , _boundsHeader_num_msgs      :: !Word8
    -- ^ Number of messages in the dataset
  , _boundsHeader_seq_num       :: !Word8
    -- ^ Position of this message in the dataset
  , _boundsHeader_update_interval :: !Word8
    -- ^ Update interval between consecutive bounds. Similar to RTCM DF391.
  , _boundsHeader_sol_id        :: !Word8
    -- ^ SSR Solution ID.
  } deriving ( Show, Read, Eq )

instance Binary BoundsHeader where
  get = do
    _boundsHeader_time <- get
    _boundsHeader_num_msgs <- getWord8
    _boundsHeader_seq_num <- getWord8
    _boundsHeader_update_interval <- getWord8
    _boundsHeader_sol_id <- getWord8
    pure BoundsHeader {..}

  put BoundsHeader {..} = do
    put _boundsHeader_time
    putWord8 _boundsHeader_num_msgs
    putWord8 _boundsHeader_seq_num
    putWord8 _boundsHeader_update_interval
    putWord8 _boundsHeader_sol_id

$(makeJSON "_boundsHeader_" ''BoundsHeader)
$(makeLenses ''BoundsHeader)

msgSsrStecCorrection :: Word16
msgSsrStecCorrection = 0x05FD

data MsgSsrStecCorrection = MsgSsrStecCorrection
  { _msgSsrStecCorrection_header      :: !BoundsHeader
    -- ^ Header of a STEC correction with bounds message.
  , _msgSsrStecCorrection_ssr_iod_atmo :: !Word8
    -- ^ IOD of the SSR atmospheric correction
  , _msgSsrStecCorrection_tile_set_id :: !Word16
    -- ^ Tile set ID
  , _msgSsrStecCorrection_tile_id     :: !Word16
    -- ^ Tile ID
  , _msgSsrStecCorrection_n_sats      :: !Word8
    -- ^ Number of satellites.
  , _msgSsrStecCorrection_stec_sat_list :: ![STECSatElement]
    -- ^ Array of STEC polynomial coefficients for each space vehicle.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrStecCorrection where
  get = do
    _msgSsrStecCorrection_header <- get
    _msgSsrStecCorrection_ssr_iod_atmo <- getWord8
    _msgSsrStecCorrection_tile_set_id <- getWord16le
    _msgSsrStecCorrection_tile_id <- getWord16le
    _msgSsrStecCorrection_n_sats <- getWord8
    _msgSsrStecCorrection_stec_sat_list <- whileM (not <$> isEmpty) get
    pure MsgSsrStecCorrection {..}

  put MsgSsrStecCorrection {..} = do
    put _msgSsrStecCorrection_header
    putWord8 _msgSsrStecCorrection_ssr_iod_atmo
    putWord16le _msgSsrStecCorrection_tile_set_id
    putWord16le _msgSsrStecCorrection_tile_id
    putWord8 _msgSsrStecCorrection_n_sats
    mapM_ put _msgSsrStecCorrection_stec_sat_list

$(makeSBP 'msgSsrStecCorrection ''MsgSsrStecCorrection)
$(makeJSON "_msgSsrStecCorrection_" ''MsgSsrStecCorrection)
$(makeLenses ''MsgSsrStecCorrection)

msgSsrGriddedCorrection :: Word16
msgSsrGriddedCorrection = 0x05FC

-- | SBP class for message MSG_SSR_GRIDDED_CORRECTION (0x05FC).
--
-- STEC residuals are per space vehicle, troposphere is not.
--
-- It is typically equivalent to the QZSS CLAS Sub Type 9 messages.
data MsgSsrGriddedCorrection = MsgSsrGriddedCorrection
  { _msgSsrGriddedCorrection_header               :: !GriddedCorrectionHeader
    -- ^ Header of a gridded correction message
  , _msgSsrGriddedCorrection_index                :: !Word16
    -- ^ Index of the grid point.
  , _msgSsrGriddedCorrection_tropo_delay_correction :: !TroposphericDelayCorrection
    -- ^ Wet and hydrostatic vertical delays (mean, stddev).
  , _msgSsrGriddedCorrection_stec_residuals       :: ![STECResidual]
    -- ^ STEC residuals for each satellite (mean, stddev).
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrGriddedCorrection where
  get = do
    _msgSsrGriddedCorrection_header <- get
    _msgSsrGriddedCorrection_index <- getWord16le
    _msgSsrGriddedCorrection_tropo_delay_correction <- get
    _msgSsrGriddedCorrection_stec_residuals <- whileM (not <$> isEmpty) get
    pure MsgSsrGriddedCorrection {..}

  put MsgSsrGriddedCorrection {..} = do
    put _msgSsrGriddedCorrection_header
    putWord16le _msgSsrGriddedCorrection_index
    put _msgSsrGriddedCorrection_tropo_delay_correction
    mapM_ put _msgSsrGriddedCorrection_stec_residuals

$(makeSBP 'msgSsrGriddedCorrection ''MsgSsrGriddedCorrection)
$(makeJSON "_msgSsrGriddedCorrection_" ''MsgSsrGriddedCorrection)
$(makeLenses ''MsgSsrGriddedCorrection)

-- | STECSatElementIntegrity.
--
-- STEC polynomial and bounds for the given satellite.
data STECSatElementIntegrity = STECSatElementIntegrity
  { _sTECSatElementIntegrity_stec_residual    :: !STECResidual
    -- ^ STEC residuals (mean, stddev)
  , _sTECSatElementIntegrity_stec_bound_mu    :: !Word8
    -- ^ Error Bound Mean. See Note 1.
  , _sTECSatElementIntegrity_stec_bound_sig   :: !Word8
    -- ^ Error Bound StDev. See Note 1.
  , _sTECSatElementIntegrity_stec_bound_mu_dot :: !Word8
    -- ^ Error Bound Mean First derivative.
  , _sTECSatElementIntegrity_stec_bound_sig_dot :: !Word8
    -- ^ Error Bound StDev First derivative.
  } deriving ( Show, Read, Eq )

instance Binary STECSatElementIntegrity where
  get = do
    _sTECSatElementIntegrity_stec_residual <- get
    _sTECSatElementIntegrity_stec_bound_mu <- getWord8
    _sTECSatElementIntegrity_stec_bound_sig <- getWord8
    _sTECSatElementIntegrity_stec_bound_mu_dot <- getWord8
    _sTECSatElementIntegrity_stec_bound_sig_dot <- getWord8
    pure STECSatElementIntegrity {..}

  put STECSatElementIntegrity {..} = do
    put _sTECSatElementIntegrity_stec_residual
    putWord8 _sTECSatElementIntegrity_stec_bound_mu
    putWord8 _sTECSatElementIntegrity_stec_bound_sig
    putWord8 _sTECSatElementIntegrity_stec_bound_mu_dot
    putWord8 _sTECSatElementIntegrity_stec_bound_sig_dot

$(makeJSON "_sTECSatElementIntegrity_" ''STECSatElementIntegrity)
$(makeLenses ''STECSatElementIntegrity)

msgSsrGriddedCorrectionBounds :: Word16
msgSsrGriddedCorrectionBounds = 0x05FE

-- | SBP class for message MSG_SSR_GRIDDED_CORRECTION_BOUNDS (0x05FE).
--
-- Note 1: Range: 0-17.5 m. i<= 200, mean = 0.01i; 200<i<=230,
-- mean=2+0.1(i-200); i>230, mean=5+0.5(i-230).
data MsgSsrGriddedCorrectionBounds = MsgSsrGriddedCorrectionBounds
  { _msgSsrGriddedCorrectionBounds_header                :: !BoundsHeader
    -- ^ Header of a bounds message.
  , _msgSsrGriddedCorrectionBounds_ssr_iod_atmo          :: !Word8
    -- ^ IOD of the correction.
  , _msgSsrGriddedCorrectionBounds_tile_set_id           :: !Word16
    -- ^ Set this tile belongs to.
  , _msgSsrGriddedCorrectionBounds_tile_id               :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
  , _msgSsrGriddedCorrectionBounds_tropo_qi              :: !Word8
    -- ^ Tropo Quality Indicator. Similar to RTCM DF389.
  , _msgSsrGriddedCorrectionBounds_grid_point_id         :: !Word16
    -- ^ Index of the Grid Point.
  , _msgSsrGriddedCorrectionBounds_tropo_delay_correction :: !TroposphericDelayCorrection
    -- ^ Tropospheric delay at grid point.
  , _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_mu :: !Word8
    -- ^ Vertical Hydrostatic Error Bound Mean.
  , _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_sig :: !Word8
    -- ^ Vertical Hydrostatic Error Bound StDev.
  , _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_mu  :: !Word8
    -- ^ Vertical Wet Error Bound Mean.
  , _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_sig :: !Word8
    -- ^ Vertical Wet Error Bound StDev.
  , _msgSsrGriddedCorrectionBounds_n_sats                :: !Word8
    -- ^ Number of satellites.
  , _msgSsrGriddedCorrectionBounds_stec_sat_list         :: ![STECSatElementIntegrity]
    -- ^ Array of STEC polynomial coefficients and its bounds for each space
    -- vehicle.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrGriddedCorrectionBounds where
  get = do
    _msgSsrGriddedCorrectionBounds_header <- get
    _msgSsrGriddedCorrectionBounds_ssr_iod_atmo <- getWord8
    _msgSsrGriddedCorrectionBounds_tile_set_id <- getWord16le
    _msgSsrGriddedCorrectionBounds_tile_id <- getWord16le
    _msgSsrGriddedCorrectionBounds_tropo_qi <- getWord8
    _msgSsrGriddedCorrectionBounds_grid_point_id <- getWord16le
    _msgSsrGriddedCorrectionBounds_tropo_delay_correction <- get
    _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_mu <- getWord8
    _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_sig <- getWord8
    _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_mu <- getWord8
    _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_sig <- getWord8
    _msgSsrGriddedCorrectionBounds_n_sats <- getWord8
    _msgSsrGriddedCorrectionBounds_stec_sat_list <- whileM (not <$> isEmpty) get
    pure MsgSsrGriddedCorrectionBounds {..}

  put MsgSsrGriddedCorrectionBounds {..} = do
    put _msgSsrGriddedCorrectionBounds_header
    putWord8 _msgSsrGriddedCorrectionBounds_ssr_iod_atmo
    putWord16le _msgSsrGriddedCorrectionBounds_tile_set_id
    putWord16le _msgSsrGriddedCorrectionBounds_tile_id
    putWord8 _msgSsrGriddedCorrectionBounds_tropo_qi
    putWord16le _msgSsrGriddedCorrectionBounds_grid_point_id
    put _msgSsrGriddedCorrectionBounds_tropo_delay_correction
    putWord8 _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_mu
    putWord8 _msgSsrGriddedCorrectionBounds_tropo_v_hydro_bound_sig
    putWord8 _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_mu
    putWord8 _msgSsrGriddedCorrectionBounds_tropo_v_wet_bound_sig
    putWord8 _msgSsrGriddedCorrectionBounds_n_sats
    mapM_ put _msgSsrGriddedCorrectionBounds_stec_sat_list

$(makeSBP 'msgSsrGriddedCorrectionBounds ''MsgSsrGriddedCorrectionBounds)
$(makeJSON "_msgSsrGriddedCorrectionBounds_" ''MsgSsrGriddedCorrectionBounds)
$(makeLenses ''MsgSsrGriddedCorrectionBounds)

msgSsrTileDefinitionDepA :: Word16
msgSsrTileDefinitionDepA = 0x05F6

-- | SBP class for message MSG_SSR_TILE_DEFINITION_DEP_A (0x05F6).
--
-- Deprecated.
data MsgSsrTileDefinitionDepA = MsgSsrTileDefinitionDepA
  { _msgSsrTileDefinitionDepA_tile_set_id :: !Word16
    -- ^ Unique identifier of the tile set this tile belongs to.
  , _msgSsrTileDefinitionDepA_tile_id     :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
    -- See GNSS-SSR-ArrayOfCorrectionPoints field correctionPointSetID.
  , _msgSsrTileDefinitionDepA_corner_nw_lat :: !Int16
    -- ^ North-West corner correction point latitude.
    --
    -- The relation between the latitude X in the range [-90, 90] and the
    -- coded number N is:
    --
    -- N = floor((X / 90) * 2^14)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLatitude.
  , _msgSsrTileDefinitionDepA_corner_nw_lon :: !Int16
    -- ^ North-West corner correction point longitude.
    --
    -- The relation between the longitude X in the range [-180, 180] and the
    -- coded number N is:
    --
    -- N = floor((X / 180) * 2^15)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLongitude.
  , _msgSsrTileDefinitionDepA_spacing_lat :: !Word16
    -- ^ Spacing of the correction points in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLatitude.
  , _msgSsrTileDefinitionDepA_spacing_lon :: !Word16
    -- ^ Spacing of the correction points in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLongitude.
  , _msgSsrTileDefinitionDepA_rows        :: !Word16
    -- ^ Number of steps in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLatitude.
  , _msgSsrTileDefinitionDepA_cols        :: !Word16
    -- ^ Number of steps in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLongitude.
  , _msgSsrTileDefinitionDepA_bitmask     :: !Word64
    -- ^ Specifies the availability of correction data at the correction points
    -- in the array.
    --
    -- If a specific bit is enabled (set to 1), the correction is not
    -- available. Only the first rows * cols bits are used, the remainder are
    -- set to 0. If there are more then 64 correction points the remaining
    -- corrections are always available.
    --
    -- Starting with the northwest corner of the array (top left on a north
    -- oriented map) the correction points are enumerated with row precedence
    -- - first row west to east, second row west to east, until last row west
    -- to east - ending with the southeast corner of the array.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field bitmaskOfGrids but note the
    -- definition of the bits is inverted.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrTileDefinitionDepA where
  get = do
    _msgSsrTileDefinitionDepA_tile_set_id <- getWord16le
    _msgSsrTileDefinitionDepA_tile_id <- getWord16le
    _msgSsrTileDefinitionDepA_corner_nw_lat <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinitionDepA_corner_nw_lon <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinitionDepA_spacing_lat <- getWord16le
    _msgSsrTileDefinitionDepA_spacing_lon <- getWord16le
    _msgSsrTileDefinitionDepA_rows <- getWord16le
    _msgSsrTileDefinitionDepA_cols <- getWord16le
    _msgSsrTileDefinitionDepA_bitmask <- getWord64le
    pure MsgSsrTileDefinitionDepA {..}

  put MsgSsrTileDefinitionDepA {..} = do
    putWord16le _msgSsrTileDefinitionDepA_tile_set_id
    putWord16le _msgSsrTileDefinitionDepA_tile_id
    (putWord16le . fromIntegral) _msgSsrTileDefinitionDepA_corner_nw_lat
    (putWord16le . fromIntegral) _msgSsrTileDefinitionDepA_corner_nw_lon
    putWord16le _msgSsrTileDefinitionDepA_spacing_lat
    putWord16le _msgSsrTileDefinitionDepA_spacing_lon
    putWord16le _msgSsrTileDefinitionDepA_rows
    putWord16le _msgSsrTileDefinitionDepA_cols
    putWord64le _msgSsrTileDefinitionDepA_bitmask

$(makeSBP 'msgSsrTileDefinitionDepA ''MsgSsrTileDefinitionDepA)
$(makeJSON "_msgSsrTileDefinitionDepA_" ''MsgSsrTileDefinitionDepA)
$(makeLenses ''MsgSsrTileDefinitionDepA)

msgSsrTileDefinitionDepB :: Word16
msgSsrTileDefinitionDepB = 0x05F7

-- | SBP class for message MSG_SSR_TILE_DEFINITION_DEP_B (0x05F7).
--
-- Deprecated.
data MsgSsrTileDefinitionDepB = MsgSsrTileDefinitionDepB
  { _msgSsrTileDefinitionDepB_ssr_sol_id  :: !Word8
    -- ^ SSR Solution ID.
  , _msgSsrTileDefinitionDepB_tile_set_id :: !Word16
    -- ^ Unique identifier of the tile set this tile belongs to.
  , _msgSsrTileDefinitionDepB_tile_id     :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
    -- See GNSS-SSR-ArrayOfCorrectionPoints field correctionPointSetID.
  , _msgSsrTileDefinitionDepB_corner_nw_lat :: !Int16
    -- ^ North-West corner correction point latitude.
    --
    -- The relation between the latitude X in the range [-90, 90] and the
    -- coded number N is:
    --
    -- N = floor((X / 90) * 2^14)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLatitude.
  , _msgSsrTileDefinitionDepB_corner_nw_lon :: !Int16
    -- ^ North-West corner correction point longitude.
    --
    -- The relation between the longitude X in the range [-180, 180] and the
    -- coded number N is:
    --
    -- N = floor((X / 180) * 2^15)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLongitude.
  , _msgSsrTileDefinitionDepB_spacing_lat :: !Word16
    -- ^ Spacing of the correction points in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLatitude.
  , _msgSsrTileDefinitionDepB_spacing_lon :: !Word16
    -- ^ Spacing of the correction points in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLongitude.
  , _msgSsrTileDefinitionDepB_rows        :: !Word16
    -- ^ Number of steps in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLatitude.
  , _msgSsrTileDefinitionDepB_cols        :: !Word16
    -- ^ Number of steps in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLongitude.
  , _msgSsrTileDefinitionDepB_bitmask     :: !Word64
    -- ^ Specifies the availability of correction data at the correction points
    -- in the array.
    --
    -- If a specific bit is enabled (set to 1), the correction is not
    -- available. Only the first rows * cols bits are used, the remainder are
    -- set to 0. If there are more then 64 correction points the remaining
    -- corrections are always available.
    --
    -- Starting with the northwest corner of the array (top left on a north
    -- oriented map) the correction points are enumerated with row precedence
    -- - first row west to east, second row west to east, until last row west
    -- to east - ending with the southeast corner of the array.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field bitmaskOfGrids but note the
    -- definition of the bits is inverted.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrTileDefinitionDepB where
  get = do
    _msgSsrTileDefinitionDepB_ssr_sol_id <- getWord8
    _msgSsrTileDefinitionDepB_tile_set_id <- getWord16le
    _msgSsrTileDefinitionDepB_tile_id <- getWord16le
    _msgSsrTileDefinitionDepB_corner_nw_lat <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinitionDepB_corner_nw_lon <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinitionDepB_spacing_lat <- getWord16le
    _msgSsrTileDefinitionDepB_spacing_lon <- getWord16le
    _msgSsrTileDefinitionDepB_rows <- getWord16le
    _msgSsrTileDefinitionDepB_cols <- getWord16le
    _msgSsrTileDefinitionDepB_bitmask <- getWord64le
    pure MsgSsrTileDefinitionDepB {..}

  put MsgSsrTileDefinitionDepB {..} = do
    putWord8 _msgSsrTileDefinitionDepB_ssr_sol_id
    putWord16le _msgSsrTileDefinitionDepB_tile_set_id
    putWord16le _msgSsrTileDefinitionDepB_tile_id
    (putWord16le . fromIntegral) _msgSsrTileDefinitionDepB_corner_nw_lat
    (putWord16le . fromIntegral) _msgSsrTileDefinitionDepB_corner_nw_lon
    putWord16le _msgSsrTileDefinitionDepB_spacing_lat
    putWord16le _msgSsrTileDefinitionDepB_spacing_lon
    putWord16le _msgSsrTileDefinitionDepB_rows
    putWord16le _msgSsrTileDefinitionDepB_cols
    putWord64le _msgSsrTileDefinitionDepB_bitmask

$(makeSBP 'msgSsrTileDefinitionDepB ''MsgSsrTileDefinitionDepB)
$(makeJSON "_msgSsrTileDefinitionDepB_" ''MsgSsrTileDefinitionDepB)
$(makeLenses ''MsgSsrTileDefinitionDepB)

msgSsrTileDefinition :: Word16
msgSsrTileDefinition = 0x05F8

-- | SBP class for message MSG_SSR_TILE_DEFINITION (0x05F8).
--
-- Provides the correction point coordinates for the atmospheric correction
-- values in the MSG_SSR_STEC_CORRECTION and MSG_SSR_GRIDDED_CORRECTION
-- messages.
--
-- Based on ETSI TS 137 355 V16.1.0 (LTE Positioning Protocol) information
-- element GNSS-SSR-CorrectionPoints. SBP only supports gridded arrays of
-- correction points, not lists of points.
data MsgSsrTileDefinition = MsgSsrTileDefinition
  { _msgSsrTileDefinition_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrTileDefinition_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrTileDefinition_sol_id        :: !Word8
    -- ^ SSR Solution ID. Similar to RTCM DF415.
  , _msgSsrTileDefinition_iod_atmo      :: !Word8
    -- ^ IOD of the SSR atmospheric correction.
  , _msgSsrTileDefinition_tile_set_id   :: !Word16
    -- ^ Unique identifier of the tile set this tile belongs to.
  , _msgSsrTileDefinition_tile_id       :: !Word16
    -- ^ Unique identifier of this tile in the tile set.
    -- See GNSS-SSR-ArrayOfCorrectionPoints field correctionPointSetID.
  , _msgSsrTileDefinition_corner_nw_lat :: !Int16
    -- ^ North-West corner correction point latitude.
    --
    -- The relation between the latitude X in the range [-90, 90] and the
    -- coded number N is:  N = floor((X / 90) * 2^14)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLatitude.
  , _msgSsrTileDefinition_corner_nw_lon :: !Int16
    -- ^ North-West corner correction point longitude.
    --
    -- The relation between the longitude X in the range [-180, 180] and the
    -- coded number N is: N = floor((X / 180) * 2^15)
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field referencePointLongitude.
  , _msgSsrTileDefinition_spacing_lat   :: !Word16
    -- ^ Spacing of the correction points in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLatitude.
  , _msgSsrTileDefinition_spacing_lon   :: !Word16
    -- ^ Spacing of the correction points in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field stepOfLongitude.
  , _msgSsrTileDefinition_rows          :: !Word16
    -- ^ Number of steps in the latitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLatitude.
  , _msgSsrTileDefinition_cols          :: !Word16
    -- ^ Number of steps in the longitude direction.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field numberOfStepsLongitude.
  , _msgSsrTileDefinition_bitmask       :: !Word64
    -- ^ Specifies the absence of correction data at the correction points in
    -- the array (grid).
    --
    -- Only the first rows * cols bits are used, and if a specific bit is
    -- enabled (set to 1), the correction is not available. If there are more
    -- than 64 correction points the remaining corrections are always
    -- available.
    --
    -- The correction points are packed by rows, starting with the northwest
    -- corner of the array (top-left on a north oriented map), with each row
    -- spanning west to east, ending with the southeast corner of the array.
    --
    -- See GNSS-SSR-ArrayOfCorrectionPoints field bitmaskOfGrids but note the
    -- definition of the bits is inverted.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrTileDefinition where
  get = do
    _msgSsrTileDefinition_time <- get
    _msgSsrTileDefinition_update_interval <- getWord8
    _msgSsrTileDefinition_sol_id <- getWord8
    _msgSsrTileDefinition_iod_atmo <- getWord8
    _msgSsrTileDefinition_tile_set_id <- getWord16le
    _msgSsrTileDefinition_tile_id <- getWord16le
    _msgSsrTileDefinition_corner_nw_lat <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinition_corner_nw_lon <- (fromIntegral <$> getWord16le)
    _msgSsrTileDefinition_spacing_lat <- getWord16le
    _msgSsrTileDefinition_spacing_lon <- getWord16le
    _msgSsrTileDefinition_rows <- getWord16le
    _msgSsrTileDefinition_cols <- getWord16le
    _msgSsrTileDefinition_bitmask <- getWord64le
    pure MsgSsrTileDefinition {..}

  put MsgSsrTileDefinition {..} = do
    put _msgSsrTileDefinition_time
    putWord8 _msgSsrTileDefinition_update_interval
    putWord8 _msgSsrTileDefinition_sol_id
    putWord8 _msgSsrTileDefinition_iod_atmo
    putWord16le _msgSsrTileDefinition_tile_set_id
    putWord16le _msgSsrTileDefinition_tile_id
    (putWord16le . fromIntegral) _msgSsrTileDefinition_corner_nw_lat
    (putWord16le . fromIntegral) _msgSsrTileDefinition_corner_nw_lon
    putWord16le _msgSsrTileDefinition_spacing_lat
    putWord16le _msgSsrTileDefinition_spacing_lon
    putWord16le _msgSsrTileDefinition_rows
    putWord16le _msgSsrTileDefinition_cols
    putWord64le _msgSsrTileDefinition_bitmask

$(makeSBP 'msgSsrTileDefinition ''MsgSsrTileDefinition)
$(makeJSON "_msgSsrTileDefinition_" ''MsgSsrTileDefinition)
$(makeLenses ''MsgSsrTileDefinition)

-- | SatelliteAPC.
--
-- Contains phase center offset and elevation variation corrections for one
-- signal on a satellite.
data SatelliteAPC = SatelliteAPC
  { _satelliteAPC_sid    :: !GnssSignal
    -- ^ GNSS signal identifier (16 bit)
  , _satelliteAPC_sat_info :: !Word8
    -- ^ Additional satellite information
  , _satelliteAPC_svn    :: !Word16
    -- ^ Satellite Code, as defined by IGS. Typically the space vehicle number.
  , _satelliteAPC_pco    :: ![Int16]
    -- ^ Mean phase center offset, X Y and Z axes. See IGS ANTEX file format
    -- description for coordinate system definition.
  , _satelliteAPC_pcv    :: ![Int8]
    -- ^ Elevation dependent phase center variations. First element is 0 degrees
    -- separation from the Z axis, subsequent elements represent elevation
    -- variations in 1 degree increments.
  } deriving ( Show, Read, Eq )

instance Binary SatelliteAPC where
  get = do
    _satelliteAPC_sid <- get
    _satelliteAPC_sat_info <- getWord8
    _satelliteAPC_svn <- getWord16le
    _satelliteAPC_pco <- replicateM 3 (fromIntegral <$> getWord16le)
    _satelliteAPC_pcv <- replicateM 21 (fromIntegral <$> getWord8)
    pure SatelliteAPC {..}

  put SatelliteAPC {..} = do
    put _satelliteAPC_sid
    putWord8 _satelliteAPC_sat_info
    putWord16le _satelliteAPC_svn
    mapM_ (putWord16le . fromIntegral) _satelliteAPC_pco
    mapM_ (putWord8 . fromIntegral) _satelliteAPC_pcv

$(makeJSON "_satelliteAPC_" ''SatelliteAPC)
$(makeLenses ''SatelliteAPC)

msgSsrSatelliteApcDep :: Word16
msgSsrSatelliteApcDep = 0x0604

-- | SBP class for message MSG_SSR_SATELLITE_APC_DEP (0x0604).
--
-- Deprecated.
data MsgSsrSatelliteApcDep = MsgSsrSatelliteApcDep
  { _msgSsrSatelliteApcDep_apc :: ![SatelliteAPC]
    -- ^ Satellite antenna phase center corrections
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrSatelliteApcDep where
  get = do
    _msgSsrSatelliteApcDep_apc <- whileM (not <$> isEmpty) get
    pure MsgSsrSatelliteApcDep {..}

  put MsgSsrSatelliteApcDep {..} = do
    mapM_ put _msgSsrSatelliteApcDep_apc

$(makeSBP 'msgSsrSatelliteApcDep ''MsgSsrSatelliteApcDep)
$(makeJSON "_msgSsrSatelliteApcDep_" ''MsgSsrSatelliteApcDep)
$(makeLenses ''MsgSsrSatelliteApcDep)

msgSsrSatelliteApc :: Word16
msgSsrSatelliteApc = 0x0605

data MsgSsrSatelliteApc = MsgSsrSatelliteApc
  { _msgSsrSatelliteApc_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrSatelliteApc_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrSatelliteApc_sol_id        :: !Word8
    -- ^ SSR Solution ID. Similar to RTCM DF415.
  , _msgSsrSatelliteApc_iod_ssr       :: !Word8
    -- ^ IOD of the SSR correction. A change of Issue Of Data SSR is used to
    -- indicate a change in the SSR generating configuration
  , _msgSsrSatelliteApc_apc           :: ![SatelliteAPC]
    -- ^ Satellite antenna phase center corrections
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrSatelliteApc where
  get = do
    _msgSsrSatelliteApc_time <- get
    _msgSsrSatelliteApc_update_interval <- getWord8
    _msgSsrSatelliteApc_sol_id <- getWord8
    _msgSsrSatelliteApc_iod_ssr <- getWord8
    _msgSsrSatelliteApc_apc <- whileM (not <$> isEmpty) get
    pure MsgSsrSatelliteApc {..}

  put MsgSsrSatelliteApc {..} = do
    put _msgSsrSatelliteApc_time
    putWord8 _msgSsrSatelliteApc_update_interval
    putWord8 _msgSsrSatelliteApc_sol_id
    putWord8 _msgSsrSatelliteApc_iod_ssr
    mapM_ put _msgSsrSatelliteApc_apc

$(makeSBP 'msgSsrSatelliteApc ''MsgSsrSatelliteApc)
$(makeJSON "_msgSsrSatelliteApc_" ''MsgSsrSatelliteApc)
$(makeLenses ''MsgSsrSatelliteApc)

msgSsrOrbitClockDepA :: Word16
msgSsrOrbitClockDepA = 0x05DC

-- | SBP class for message MSG_SSR_ORBIT_CLOCK_DEP_A (0x05DC).
--
-- Deprecated.
data MsgSsrOrbitClockDepA = MsgSsrOrbitClockDepA
  { _msgSsrOrbitClockDepA_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _msgSsrOrbitClockDepA_sid           :: !GnssSignal
    -- ^ GNSS signal identifier (16 bit)
  , _msgSsrOrbitClockDepA_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _msgSsrOrbitClockDepA_iod_ssr       :: !Word8
    -- ^ IOD of the SSR correction. A change of Issue Of Data SSR is used to
    -- indicate a change in the SSR generating configuration
  , _msgSsrOrbitClockDepA_iod           :: !Word8
    -- ^ Issue of broadcast ephemeris data
  , _msgSsrOrbitClockDepA_radial        :: !Int32
    -- ^ Orbit radial delta correction
  , _msgSsrOrbitClockDepA_along         :: !Int32
    -- ^ Orbit along delta correction
  , _msgSsrOrbitClockDepA_cross         :: !Int32
    -- ^ Orbit along delta correction
  , _msgSsrOrbitClockDepA_dot_radial    :: !Int32
    -- ^ Velocity of orbit radial delta correction
  , _msgSsrOrbitClockDepA_dot_along     :: !Int32
    -- ^ Velocity of orbit along delta correction
  , _msgSsrOrbitClockDepA_dot_cross     :: !Int32
    -- ^ Velocity of orbit cross delta correction
  , _msgSsrOrbitClockDepA_c0            :: !Int32
    -- ^ C0 polynomial coefficient for correction of broadcast satellite clock
  , _msgSsrOrbitClockDepA_c1            :: !Int32
    -- ^ C1 polynomial coefficient for correction of broadcast satellite clock
  , _msgSsrOrbitClockDepA_c2            :: !Int32
    -- ^ C2 polynomial coefficient for correction of broadcast satellite clock
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrOrbitClockDepA where
  get = do
    _msgSsrOrbitClockDepA_time <- get
    _msgSsrOrbitClockDepA_sid <- get
    _msgSsrOrbitClockDepA_update_interval <- getWord8
    _msgSsrOrbitClockDepA_iod_ssr <- getWord8
    _msgSsrOrbitClockDepA_iod <- getWord8
    _msgSsrOrbitClockDepA_radial <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_along <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_cross <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_dot_radial <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_dot_along <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_dot_cross <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_c0 <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_c1 <- (fromIntegral <$> getWord32le)
    _msgSsrOrbitClockDepA_c2 <- (fromIntegral <$> getWord32le)
    pure MsgSsrOrbitClockDepA {..}

  put MsgSsrOrbitClockDepA {..} = do
    put _msgSsrOrbitClockDepA_time
    put _msgSsrOrbitClockDepA_sid
    putWord8 _msgSsrOrbitClockDepA_update_interval
    putWord8 _msgSsrOrbitClockDepA_iod_ssr
    putWord8 _msgSsrOrbitClockDepA_iod
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_radial
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_along
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_cross
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_dot_radial
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_dot_along
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_dot_cross
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_c0
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_c1
    (putWord32le . fromIntegral) _msgSsrOrbitClockDepA_c2

$(makeSBP 'msgSsrOrbitClockDepA ''MsgSsrOrbitClockDepA)
$(makeJSON "_msgSsrOrbitClockDepA_" ''MsgSsrOrbitClockDepA)
$(makeLenses ''MsgSsrOrbitClockDepA)

-- | STECHeaderDepA.
--
-- A full set of STEC information will likely span multiple SBP messages,
-- since SBP message a limited to 255 bytes.  The header is used to tie
-- multiple SBP messages into a sequence.
data STECHeaderDepA = STECHeaderDepA
  { _sTECHeaderDepA_time          :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _sTECHeaderDepA_num_msgs      :: !Word8
    -- ^ Number of messages in the dataset
  , _sTECHeaderDepA_seq_num       :: !Word8
    -- ^ Position of this message in the dataset
  , _sTECHeaderDepA_update_interval :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _sTECHeaderDepA_iod_atmo      :: !Word8
    -- ^ IOD of the SSR atmospheric correction
  } deriving ( Show, Read, Eq )

instance Binary STECHeaderDepA where
  get = do
    _sTECHeaderDepA_time <- get
    _sTECHeaderDepA_num_msgs <- getWord8
    _sTECHeaderDepA_seq_num <- getWord8
    _sTECHeaderDepA_update_interval <- getWord8
    _sTECHeaderDepA_iod_atmo <- getWord8
    pure STECHeaderDepA {..}

  put STECHeaderDepA {..} = do
    put _sTECHeaderDepA_time
    putWord8 _sTECHeaderDepA_num_msgs
    putWord8 _sTECHeaderDepA_seq_num
    putWord8 _sTECHeaderDepA_update_interval
    putWord8 _sTECHeaderDepA_iod_atmo

$(makeJSON "_sTECHeaderDepA_" ''STECHeaderDepA)
$(makeLenses ''STECHeaderDepA)

-- | GriddedCorrectionHeaderDepA.
--
-- The 3GPP message contains nested variable length arrays which are not
-- supported in SBP, so each grid point will be identified by the index.
data GriddedCorrectionHeaderDepA = GriddedCorrectionHeaderDepA
  { _griddedCorrectionHeaderDepA_time                  :: !GpsTimeSec
    -- ^ GNSS reference time of the correction
  , _griddedCorrectionHeaderDepA_num_msgs              :: !Word16
    -- ^ Number of messages in the dataset
  , _griddedCorrectionHeaderDepA_seq_num               :: !Word16
    -- ^ Position of this message in the dataset
  , _griddedCorrectionHeaderDepA_update_interval       :: !Word8
    -- ^ Update interval between consecutive corrections. Encoded following RTCM
    -- DF391 specification.
  , _griddedCorrectionHeaderDepA_iod_atmo              :: !Word8
    -- ^ IOD of the SSR atmospheric correction
  , _griddedCorrectionHeaderDepA_tropo_quality_indicator :: !Word8
    -- ^ Quality of the troposphere data. Encoded following RTCM DF389
    -- specification in units of m.
  } deriving ( Show, Read, Eq )

instance Binary GriddedCorrectionHeaderDepA where
  get = do
    _griddedCorrectionHeaderDepA_time <- get
    _griddedCorrectionHeaderDepA_num_msgs <- getWord16le
    _griddedCorrectionHeaderDepA_seq_num <- getWord16le
    _griddedCorrectionHeaderDepA_update_interval <- getWord8
    _griddedCorrectionHeaderDepA_iod_atmo <- getWord8
    _griddedCorrectionHeaderDepA_tropo_quality_indicator <- getWord8
    pure GriddedCorrectionHeaderDepA {..}

  put GriddedCorrectionHeaderDepA {..} = do
    put _griddedCorrectionHeaderDepA_time
    putWord16le _griddedCorrectionHeaderDepA_num_msgs
    putWord16le _griddedCorrectionHeaderDepA_seq_num
    putWord8 _griddedCorrectionHeaderDepA_update_interval
    putWord8 _griddedCorrectionHeaderDepA_iod_atmo
    putWord8 _griddedCorrectionHeaderDepA_tropo_quality_indicator

$(makeJSON "_griddedCorrectionHeaderDepA_" ''GriddedCorrectionHeaderDepA)
$(makeLenses ''GriddedCorrectionHeaderDepA)

-- | GridDefinitionHeaderDepA.
--
-- Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. Also includes an
-- RLE encoded validity list.
data GridDefinitionHeaderDepA = GridDefinitionHeaderDepA
  { _gridDefinitionHeaderDepA_region_size_inverse :: !Word8
    -- ^ region_size (deg) = 10 / region_size_inverse 0 is an invalid value.
  , _gridDefinitionHeaderDepA_area_width        :: !Word16
    -- ^ grid height (deg) = grid width (deg) = area_width / region_size 0 is an
    -- invalid value.
  , _gridDefinitionHeaderDepA_lat_nw_corner_enc :: !Word16
    -- ^ North-West corner latitude (deg) = region_size * lat_nw_corner_enc - 90
  , _gridDefinitionHeaderDepA_lon_nw_corner_enc :: !Word16
    -- ^ North-West corner longitude (deg) = region_size * lon_nw_corner_enc -
    -- 180
  , _gridDefinitionHeaderDepA_num_msgs          :: !Word8
    -- ^ Number of messages in the dataset
  , _gridDefinitionHeaderDepA_seq_num           :: !Word8
    -- ^ Position of this message in the dataset
  } deriving ( Show, Read, Eq )

instance Binary GridDefinitionHeaderDepA where
  get = do
    _gridDefinitionHeaderDepA_region_size_inverse <- getWord8
    _gridDefinitionHeaderDepA_area_width <- getWord16le
    _gridDefinitionHeaderDepA_lat_nw_corner_enc <- getWord16le
    _gridDefinitionHeaderDepA_lon_nw_corner_enc <- getWord16le
    _gridDefinitionHeaderDepA_num_msgs <- getWord8
    _gridDefinitionHeaderDepA_seq_num <- getWord8
    pure GridDefinitionHeaderDepA {..}

  put GridDefinitionHeaderDepA {..} = do
    putWord8 _gridDefinitionHeaderDepA_region_size_inverse
    putWord16le _gridDefinitionHeaderDepA_area_width
    putWord16le _gridDefinitionHeaderDepA_lat_nw_corner_enc
    putWord16le _gridDefinitionHeaderDepA_lon_nw_corner_enc
    putWord8 _gridDefinitionHeaderDepA_num_msgs
    putWord8 _gridDefinitionHeaderDepA_seq_num

$(makeJSON "_gridDefinitionHeaderDepA_" ''GridDefinitionHeaderDepA)
$(makeLenses ''GridDefinitionHeaderDepA)

msgSsrStecCorrectionDepA :: Word16
msgSsrStecCorrectionDepA = 0x05EB

-- | SBP class for message MSG_SSR_STEC_CORRECTION_DEP_A (0x05EB).
--
-- Deprecated.
data MsgSsrStecCorrectionDepA = MsgSsrStecCorrectionDepA
  { _msgSsrStecCorrectionDepA_header      :: !STECHeaderDepA
    -- ^ Header of a STEC message
  , _msgSsrStecCorrectionDepA_stec_sat_list :: ![STECSatElement]
    -- ^ Array of STEC information for each space vehicle
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrStecCorrectionDepA where
  get = do
    _msgSsrStecCorrectionDepA_header <- get
    _msgSsrStecCorrectionDepA_stec_sat_list <- whileM (not <$> isEmpty) get
    pure MsgSsrStecCorrectionDepA {..}

  put MsgSsrStecCorrectionDepA {..} = do
    put _msgSsrStecCorrectionDepA_header
    mapM_ put _msgSsrStecCorrectionDepA_stec_sat_list

$(makeSBP 'msgSsrStecCorrectionDepA ''MsgSsrStecCorrectionDepA)
$(makeJSON "_msgSsrStecCorrectionDepA_" ''MsgSsrStecCorrectionDepA)
$(makeLenses ''MsgSsrStecCorrectionDepA)

msgSsrGriddedCorrectionNoStdDepA :: Word16
msgSsrGriddedCorrectionNoStdDepA = 0x05F0

-- | SBP class for message MSG_SSR_GRIDDED_CORRECTION_NO_STD_DEP_A (0x05F0).
--
-- Deprecated.
data MsgSsrGriddedCorrectionNoStdDepA = MsgSsrGriddedCorrectionNoStdDepA
  { _msgSsrGriddedCorrectionNoStdDepA_header               :: !GriddedCorrectionHeaderDepA
    -- ^ Header of a Gridded Correction message
  , _msgSsrGriddedCorrectionNoStdDepA_index                :: !Word16
    -- ^ Index of the grid point
  , _msgSsrGriddedCorrectionNoStdDepA_tropo_delay_correction :: !TroposphericDelayCorrectionNoStd
    -- ^ Wet and hydrostatic vertical delays
  , _msgSsrGriddedCorrectionNoStdDepA_stec_residuals       :: ![STECResidualNoStd]
    -- ^ STEC residuals for each satellite
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrGriddedCorrectionNoStdDepA where
  get = do
    _msgSsrGriddedCorrectionNoStdDepA_header <- get
    _msgSsrGriddedCorrectionNoStdDepA_index <- getWord16le
    _msgSsrGriddedCorrectionNoStdDepA_tropo_delay_correction <- get
    _msgSsrGriddedCorrectionNoStdDepA_stec_residuals <- whileM (not <$> isEmpty) get
    pure MsgSsrGriddedCorrectionNoStdDepA {..}

  put MsgSsrGriddedCorrectionNoStdDepA {..} = do
    put _msgSsrGriddedCorrectionNoStdDepA_header
    putWord16le _msgSsrGriddedCorrectionNoStdDepA_index
    put _msgSsrGriddedCorrectionNoStdDepA_tropo_delay_correction
    mapM_ put _msgSsrGriddedCorrectionNoStdDepA_stec_residuals

$(makeSBP 'msgSsrGriddedCorrectionNoStdDepA ''MsgSsrGriddedCorrectionNoStdDepA)
$(makeJSON "_msgSsrGriddedCorrectionNoStdDepA_" ''MsgSsrGriddedCorrectionNoStdDepA)
$(makeLenses ''MsgSsrGriddedCorrectionNoStdDepA)

msgSsrGriddedCorrectionDepA :: Word16
msgSsrGriddedCorrectionDepA = 0x05FA

-- | SBP class for message MSG_SSR_GRIDDED_CORRECTION_DEP_A (0x05FA).
--
-- Deprecated.
data MsgSsrGriddedCorrectionDepA = MsgSsrGriddedCorrectionDepA
  { _msgSsrGriddedCorrectionDepA_header               :: !GriddedCorrectionHeaderDepA
    -- ^ Header of a Gridded Correction message
  , _msgSsrGriddedCorrectionDepA_index                :: !Word16
    -- ^ Index of the grid point
  , _msgSsrGriddedCorrectionDepA_tropo_delay_correction :: !TroposphericDelayCorrection
    -- ^ Wet and hydrostatic vertical delays (mean, stddev)
  , _msgSsrGriddedCorrectionDepA_stec_residuals       :: ![STECResidual]
    -- ^ STEC residuals for each satellite (mean, stddev)
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrGriddedCorrectionDepA where
  get = do
    _msgSsrGriddedCorrectionDepA_header <- get
    _msgSsrGriddedCorrectionDepA_index <- getWord16le
    _msgSsrGriddedCorrectionDepA_tropo_delay_correction <- get
    _msgSsrGriddedCorrectionDepA_stec_residuals <- whileM (not <$> isEmpty) get
    pure MsgSsrGriddedCorrectionDepA {..}

  put MsgSsrGriddedCorrectionDepA {..} = do
    put _msgSsrGriddedCorrectionDepA_header
    putWord16le _msgSsrGriddedCorrectionDepA_index
    put _msgSsrGriddedCorrectionDepA_tropo_delay_correction
    mapM_ put _msgSsrGriddedCorrectionDepA_stec_residuals

$(makeSBP 'msgSsrGriddedCorrectionDepA ''MsgSsrGriddedCorrectionDepA)
$(makeJSON "_msgSsrGriddedCorrectionDepA_" ''MsgSsrGriddedCorrectionDepA)
$(makeLenses ''MsgSsrGriddedCorrectionDepA)

msgSsrGridDefinitionDepA :: Word16
msgSsrGridDefinitionDepA = 0x05F5

-- | SBP class for message MSG_SSR_GRID_DEFINITION_DEP_A (0x05F5).
--
-- Deprecated.
data MsgSsrGridDefinitionDepA = MsgSsrGridDefinitionDepA
  { _msgSsrGridDefinitionDepA_header :: !GridDefinitionHeaderDepA
    -- ^ Header of a Gridded Correction message
  , _msgSsrGridDefinitionDepA_rle_list :: ![Word8]
    -- ^ Run Length Encode list of quadrants that contain valid data. The spec
    -- describes the encoding scheme in detail, but essentially the index of
    -- the quadrants that contain transitions between valid and invalid (and
    -- vice versa) are encoded as u8 integers.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrGridDefinitionDepA where
  get = do
    _msgSsrGridDefinitionDepA_header <- get
    _msgSsrGridDefinitionDepA_rle_list <- whileM (not <$> isEmpty) getWord8
    pure MsgSsrGridDefinitionDepA {..}

  put MsgSsrGridDefinitionDepA {..} = do
    put _msgSsrGridDefinitionDepA_header
    mapM_ putWord8 _msgSsrGridDefinitionDepA_rle_list

$(makeSBP 'msgSsrGridDefinitionDepA ''MsgSsrGridDefinitionDepA)
$(makeJSON "_msgSsrGridDefinitionDepA_" ''MsgSsrGridDefinitionDepA)
$(makeLenses ''MsgSsrGridDefinitionDepA)

-- | OrbitClockBound.
--
-- Orbit and clock bound.
data OrbitClockBound = OrbitClockBound
  { _orbitClockBound_sat_id             :: !Word8
    -- ^ Satellite ID. Similar to either RTCM DF068 (GPS), DF252 (Galileo), or
    -- DF488 (BDS) depending on the constellation.
  , _orbitClockBound_orb_radial_bound_mu :: !Word8
    -- ^ Mean Radial. See Note 1.
  , _orbitClockBound_orb_along_bound_mu :: !Word8
    -- ^ Mean Along-Track. See Note 1.
  , _orbitClockBound_orb_cross_bound_mu :: !Word8
    -- ^ Mean Cross-Track. See Note 1.
  , _orbitClockBound_orb_radial_bound_sig :: !Word8
    -- ^ Standard Deviation Radial. See Note 2.
  , _orbitClockBound_orb_along_bound_sig :: !Word8
    -- ^ Standard Deviation Along-Track. See Note 2.
  , _orbitClockBound_orb_cross_bound_sig :: !Word8
    -- ^ Standard Deviation Cross-Track. See Note 2.
  , _orbitClockBound_clock_bound_mu     :: !Word8
    -- ^ Clock Bound Mean. See Note 1.
  , _orbitClockBound_clock_bound_sig    :: !Word8
    -- ^ Clock Bound Standard Deviation. See Note 2.
  } deriving ( Show, Read, Eq )

instance Binary OrbitClockBound where
  get = do
    _orbitClockBound_sat_id <- getWord8
    _orbitClockBound_orb_radial_bound_mu <- getWord8
    _orbitClockBound_orb_along_bound_mu <- getWord8
    _orbitClockBound_orb_cross_bound_mu <- getWord8
    _orbitClockBound_orb_radial_bound_sig <- getWord8
    _orbitClockBound_orb_along_bound_sig <- getWord8
    _orbitClockBound_orb_cross_bound_sig <- getWord8
    _orbitClockBound_clock_bound_mu <- getWord8
    _orbitClockBound_clock_bound_sig <- getWord8
    pure OrbitClockBound {..}

  put OrbitClockBound {..} = do
    putWord8 _orbitClockBound_sat_id
    putWord8 _orbitClockBound_orb_radial_bound_mu
    putWord8 _orbitClockBound_orb_along_bound_mu
    putWord8 _orbitClockBound_orb_cross_bound_mu
    putWord8 _orbitClockBound_orb_radial_bound_sig
    putWord8 _orbitClockBound_orb_along_bound_sig
    putWord8 _orbitClockBound_orb_cross_bound_sig
    putWord8 _orbitClockBound_clock_bound_mu
    putWord8 _orbitClockBound_clock_bound_sig

$(makeJSON "_orbitClockBound_" ''OrbitClockBound)
$(makeLenses ''OrbitClockBound)

msgSsrOrbitClockBounds :: Word16
msgSsrOrbitClockBounds = 0x05DE

-- | SBP class for message MSG_SSR_ORBIT_CLOCK_BOUNDS (0x05DE).
--
-- Note 1: Range: 0-17.5 m. i<=200, mean=0.01i; 200<i<=230, mean=2+0.1(i-200);
-- i>230, mean=5+0.5(i-230).
--
-- Note 2: Range: 0-17.5 m. i<=200, std=0.01i; 200<i<=230, std=2+0.1(i-200)
-- i>230, std=5+0.5(i-230).
data MsgSsrOrbitClockBounds = MsgSsrOrbitClockBounds
  { _msgSsrOrbitClockBounds_header           :: !BoundsHeader
    -- ^ Header of a bounds message.
  , _msgSsrOrbitClockBounds_ssr_iod          :: !Word8
    -- ^ IOD of the SSR bound.
  , _msgSsrOrbitClockBounds_const_id         :: !Word8
    -- ^ Constellation ID to which the SVs belong.
  , _msgSsrOrbitClockBounds_n_sats           :: !Word8
    -- ^ Number of satellites.
  , _msgSsrOrbitClockBounds_orbit_clock_bounds :: ![OrbitClockBound]
    -- ^ Orbit and Clock Bounds per Satellite
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrOrbitClockBounds where
  get = do
    _msgSsrOrbitClockBounds_header <- get
    _msgSsrOrbitClockBounds_ssr_iod <- getWord8
    _msgSsrOrbitClockBounds_const_id <- getWord8
    _msgSsrOrbitClockBounds_n_sats <- getWord8
    _msgSsrOrbitClockBounds_orbit_clock_bounds <- whileM (not <$> isEmpty) get
    pure MsgSsrOrbitClockBounds {..}

  put MsgSsrOrbitClockBounds {..} = do
    put _msgSsrOrbitClockBounds_header
    putWord8 _msgSsrOrbitClockBounds_ssr_iod
    putWord8 _msgSsrOrbitClockBounds_const_id
    putWord8 _msgSsrOrbitClockBounds_n_sats
    mapM_ put _msgSsrOrbitClockBounds_orbit_clock_bounds

$(makeSBP 'msgSsrOrbitClockBounds ''MsgSsrOrbitClockBounds)
$(makeJSON "_msgSsrOrbitClockBounds_" ''MsgSsrOrbitClockBounds)
$(makeLenses ''MsgSsrOrbitClockBounds)

data CodePhaseBiasesSatSig = CodePhaseBiasesSatSig
  { _codePhaseBiasesSatSig_sat_id             :: !Word8
    -- ^ Satellite ID. Similar to either RTCM DF068 (GPS), DF252 (Galileo), or
    -- DF488 (BDS) depending on the constellation.
  , _codePhaseBiasesSatSig_signal_id          :: !Word8
    -- ^ Signal and Tracking Mode Identifier. Similar to either RTCM DF380
    -- (GPS), DF382 (Galileo) or DF467 (BDS) depending on the constellation.
  , _codePhaseBiasesSatSig_code_bias_bound_mu :: !Word8
    -- ^ Code Bias Mean. Range: 0-1.275 m
  , _codePhaseBiasesSatSig_code_bias_bound_sig :: !Word8
    -- ^ Code Bias Standard Deviation. Range: 0-1.275 m
  , _codePhaseBiasesSatSig_phase_bias_bound_mu :: !Word8
    -- ^ Phase Bias Mean. Range: 0-1.275 m
  , _codePhaseBiasesSatSig_phase_bias_bound_sig :: !Word8
    -- ^ Phase Bias Standard Deviation. Range: 0-1.275 m
  } deriving ( Show, Read, Eq )

instance Binary CodePhaseBiasesSatSig where
  get = do
    _codePhaseBiasesSatSig_sat_id <- getWord8
    _codePhaseBiasesSatSig_signal_id <- getWord8
    _codePhaseBiasesSatSig_code_bias_bound_mu <- getWord8
    _codePhaseBiasesSatSig_code_bias_bound_sig <- getWord8
    _codePhaseBiasesSatSig_phase_bias_bound_mu <- getWord8
    _codePhaseBiasesSatSig_phase_bias_bound_sig <- getWord8
    pure CodePhaseBiasesSatSig {..}

  put CodePhaseBiasesSatSig {..} = do
    putWord8 _codePhaseBiasesSatSig_sat_id
    putWord8 _codePhaseBiasesSatSig_signal_id
    putWord8 _codePhaseBiasesSatSig_code_bias_bound_mu
    putWord8 _codePhaseBiasesSatSig_code_bias_bound_sig
    putWord8 _codePhaseBiasesSatSig_phase_bias_bound_mu
    putWord8 _codePhaseBiasesSatSig_phase_bias_bound_sig

$(makeJSON "_codePhaseBiasesSatSig_" ''CodePhaseBiasesSatSig)
$(makeLenses ''CodePhaseBiasesSatSig)

msgSsrCodePhaseBiasesBounds :: Word16
msgSsrCodePhaseBiasesBounds = 0x05EC

data MsgSsrCodePhaseBiasesBounds = MsgSsrCodePhaseBiasesBounds
  { _msgSsrCodePhaseBiasesBounds_header           :: !BoundsHeader
    -- ^ Header of a bounds message.
  , _msgSsrCodePhaseBiasesBounds_ssr_iod          :: !Word8
    -- ^ IOD of the SSR bound.
  , _msgSsrCodePhaseBiasesBounds_const_id         :: !Word8
    -- ^ Constellation ID to which the SVs belong.
  , _msgSsrCodePhaseBiasesBounds_n_sats_signals   :: !Word8
    -- ^ Number of satellite-signal couples.
  , _msgSsrCodePhaseBiasesBounds_satellites_signals :: ![CodePhaseBiasesSatSig]
    -- ^ Code and Phase Biases Bounds per Satellite-Signal couple.
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrCodePhaseBiasesBounds where
  get = do
    _msgSsrCodePhaseBiasesBounds_header <- get
    _msgSsrCodePhaseBiasesBounds_ssr_iod <- getWord8
    _msgSsrCodePhaseBiasesBounds_const_id <- getWord8
    _msgSsrCodePhaseBiasesBounds_n_sats_signals <- getWord8
    _msgSsrCodePhaseBiasesBounds_satellites_signals <- whileM (not <$> isEmpty) get
    pure MsgSsrCodePhaseBiasesBounds {..}

  put MsgSsrCodePhaseBiasesBounds {..} = do
    put _msgSsrCodePhaseBiasesBounds_header
    putWord8 _msgSsrCodePhaseBiasesBounds_ssr_iod
    putWord8 _msgSsrCodePhaseBiasesBounds_const_id
    putWord8 _msgSsrCodePhaseBiasesBounds_n_sats_signals
    mapM_ put _msgSsrCodePhaseBiasesBounds_satellites_signals

$(makeSBP 'msgSsrCodePhaseBiasesBounds ''MsgSsrCodePhaseBiasesBounds)
$(makeJSON "_msgSsrCodePhaseBiasesBounds_" ''MsgSsrCodePhaseBiasesBounds)
$(makeLenses ''MsgSsrCodePhaseBiasesBounds)

-- | OrbitClockBoundDegradation.
--
-- Orbit and clock bound degradation.
data OrbitClockBoundDegradation = OrbitClockBoundDegradation
  { _orbitClockBoundDegradation_orb_radial_bound_mu_dot :: !Word8
    -- ^ Orbit Bound Mean Radial First derivative. Range: 0-0.255 m/s
  , _orbitClockBoundDegradation_orb_along_bound_mu_dot :: !Word8
    -- ^ Orbit Bound Mean Along-Track First derivative. Range: 0-0.255 m/s
  , _orbitClockBoundDegradation_orb_cross_bound_mu_dot :: !Word8
    -- ^ Orbit Bound Mean Cross-Track First derivative. Range: 0-0.255 m/s
  , _orbitClockBoundDegradation_orb_radial_bound_sig_dot :: !Word8
    -- ^ Orbit Bound Standard Deviation Radial First derivative. Range: 0-0.255
    -- m/s
  , _orbitClockBoundDegradation_orb_along_bound_sig_dot :: !Word8
    -- ^ Orbit Bound Standard Deviation Along-Track First derivative. Range:
    -- 0-0.255 m/s
  , _orbitClockBoundDegradation_orb_cross_bound_sig_dot :: !Word8
    -- ^ Orbit Bound Standard Deviation Cross-Track First derivative. Range:
    -- 0-0.255 m/s
  , _orbitClockBoundDegradation_clock_bound_mu_dot     :: !Word8
    -- ^ Clock Bound Mean First derivative. Range: 0-0.255 m/s
  , _orbitClockBoundDegradation_clock_bound_sig_dot    :: !Word8
    -- ^ Clock Bound Standard Deviation First derivative. Range: 0-0.255 m/s
  } deriving ( Show, Read, Eq )

instance Binary OrbitClockBoundDegradation where
  get = do
    _orbitClockBoundDegradation_orb_radial_bound_mu_dot <- getWord8
    _orbitClockBoundDegradation_orb_along_bound_mu_dot <- getWord8
    _orbitClockBoundDegradation_orb_cross_bound_mu_dot <- getWord8
    _orbitClockBoundDegradation_orb_radial_bound_sig_dot <- getWord8
    _orbitClockBoundDegradation_orb_along_bound_sig_dot <- getWord8
    _orbitClockBoundDegradation_orb_cross_bound_sig_dot <- getWord8
    _orbitClockBoundDegradation_clock_bound_mu_dot <- getWord8
    _orbitClockBoundDegradation_clock_bound_sig_dot <- getWord8
    pure OrbitClockBoundDegradation {..}

  put OrbitClockBoundDegradation {..} = do
    putWord8 _orbitClockBoundDegradation_orb_radial_bound_mu_dot
    putWord8 _orbitClockBoundDegradation_orb_along_bound_mu_dot
    putWord8 _orbitClockBoundDegradation_orb_cross_bound_mu_dot
    putWord8 _orbitClockBoundDegradation_orb_radial_bound_sig_dot
    putWord8 _orbitClockBoundDegradation_orb_along_bound_sig_dot
    putWord8 _orbitClockBoundDegradation_orb_cross_bound_sig_dot
    putWord8 _orbitClockBoundDegradation_clock_bound_mu_dot
    putWord8 _orbitClockBoundDegradation_clock_bound_sig_dot

$(makeJSON "_orbitClockBoundDegradation_" ''OrbitClockBoundDegradation)
$(makeLenses ''OrbitClockBoundDegradation)

msgSsrOrbitClockBoundsDegradation :: Word16
msgSsrOrbitClockBoundsDegradation = 0x05DF

data MsgSsrOrbitClockBoundsDegradation = MsgSsrOrbitClockBoundsDegradation
  { _msgSsrOrbitClockBoundsDegradation_header                       :: !BoundsHeader
    -- ^ Header of a bounds message.
  , _msgSsrOrbitClockBoundsDegradation_ssr_iod                      :: !Word8
    -- ^ IOD of the SSR bound degradation parameter.
  , _msgSsrOrbitClockBoundsDegradation_const_id                     :: !Word8
    -- ^ Constellation ID to which the SVs belong.
  , _msgSsrOrbitClockBoundsDegradation_sat_bitmask                  :: !Word64
    -- ^ Satellite Bit Mask. Put 1 for each satellite where the following
    -- degradation parameters are applicable, 0 otherwise. Encoded following
    -- RTCM DF394 specification.
  , _msgSsrOrbitClockBoundsDegradation_orbit_clock_bounds_degradation :: !OrbitClockBoundDegradation
    -- ^ Orbit and Clock Bounds Degradation Parameters
  } deriving ( Show, Read, Eq )

instance Binary MsgSsrOrbitClockBoundsDegradation where
  get = do
    _msgSsrOrbitClockBoundsDegradation_header <- get
    _msgSsrOrbitClockBoundsDegradation_ssr_iod <- getWord8
    _msgSsrOrbitClockBoundsDegradation_const_id <- getWord8
    _msgSsrOrbitClockBoundsDegradation_sat_bitmask <- getWord64le
    _msgSsrOrbitClockBoundsDegradation_orbit_clock_bounds_degradation <- get
    pure MsgSsrOrbitClockBoundsDegradation {..}

  put MsgSsrOrbitClockBoundsDegradation {..} = do
    put _msgSsrOrbitClockBoundsDegradation_header
    putWord8 _msgSsrOrbitClockBoundsDegradation_ssr_iod
    putWord8 _msgSsrOrbitClockBoundsDegradation_const_id
    putWord64le _msgSsrOrbitClockBoundsDegradation_sat_bitmask
    put _msgSsrOrbitClockBoundsDegradation_orbit_clock_bounds_degradation

$(makeSBP 'msgSsrOrbitClockBoundsDegradation ''MsgSsrOrbitClockBoundsDegradation)
$(makeJSON "_msgSsrOrbitClockBoundsDegradation_" ''MsgSsrOrbitClockBoundsDegradation)
$(makeLenses ''MsgSsrOrbitClockBoundsDegradation)