packages feed

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

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

-- |
-- Module:      SwiftNav.SBP.System
-- Copyright:   Copyright (C) 2015-2021 Swift Navigation, Inc.
-- License:     MIT
-- Contact:     https://support.swiftnav.com
-- Stability:   experimental
-- Portability: portable
--
-- \< Standardized system messages from Swift Navigation devices. \>

module SwiftNav.SBP.System
  ( module SwiftNav.SBP.System
  ) 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

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


msgStartup :: Word16
msgStartup = 0xFF00

-- | SBP class for message MSG_STARTUP (0xFF00).
--
-- The system start-up message is sent once on system start-up. It notifies
-- the host or other attached devices that the system has started and is now
-- ready to respond to commands or configuration requests.
data MsgStartup = MsgStartup
  { _msgStartup_cause      :: !Word8
    -- ^ Cause of startup
  , _msgStartup_startup_type :: !Word8
    -- ^ Startup type
  , _msgStartup_reserved   :: !Word16
    -- ^ Reserved
  } deriving ( Show, Read, Eq )

instance Binary MsgStartup where
  get = do
    _msgStartup_cause <- getWord8
    _msgStartup_startup_type <- getWord8
    _msgStartup_reserved <- getWord16le
    pure MsgStartup {..}

  put MsgStartup {..} = do
    putWord8 _msgStartup_cause
    putWord8 _msgStartup_startup_type
    putWord16le _msgStartup_reserved

$(makeSBP 'msgStartup ''MsgStartup)
$(makeJSON "_msgStartup_" ''MsgStartup)
$(makeLenses ''MsgStartup)

msgDgnssStatus :: Word16
msgDgnssStatus = 0xFF02

-- | SBP class for message MSG_DGNSS_STATUS (0xFF02).
--
-- This message provides information about the receipt of Differential
-- corrections.  It is expected to be sent with each receipt of a complete
-- corrections packet.
data MsgDgnssStatus = MsgDgnssStatus
  { _msgDgnssStatus_flags     :: !Word8
    -- ^ Status flags
  , _msgDgnssStatus_latency   :: !Word16
    -- ^ Latency of observation receipt
  , _msgDgnssStatus_num_signals :: !Word8
    -- ^ Number of signals from base station
  , _msgDgnssStatus_source    :: !Text
    -- ^ Corrections source string
  } deriving ( Show, Read, Eq )

instance Binary MsgDgnssStatus where
  get = do
    _msgDgnssStatus_flags <- getWord8
    _msgDgnssStatus_latency <- getWord16le
    _msgDgnssStatus_num_signals <- getWord8
    _msgDgnssStatus_source <- decodeUtf8 . toStrict <$> getRemainingLazyByteString
    pure MsgDgnssStatus {..}

  put MsgDgnssStatus {..} = do
    putWord8 _msgDgnssStatus_flags
    putWord16le _msgDgnssStatus_latency
    putWord8 _msgDgnssStatus_num_signals
    putByteString $ encodeUtf8 _msgDgnssStatus_source

$(makeSBP 'msgDgnssStatus ''MsgDgnssStatus)
$(makeJSON "_msgDgnssStatus_" ''MsgDgnssStatus)
$(makeLenses ''MsgDgnssStatus)

msgHeartbeat :: Word16
msgHeartbeat = 0xFFFF

-- | SBP class for message MSG_HEARTBEAT (0xFFFF).
--
-- The heartbeat message is sent periodically to inform the host or other
-- attached devices that the system is running. It is used to monitor system
-- malfunctions. It also contains status flags that indicate to the host the
-- status of the system and whether it is operating correctly. Currently, the
-- expected heartbeat interval is 1 sec.
--
-- The system error flag is used to indicate that an error has occurred in the
-- system. To determine the source of the error, the remaining error flags
-- should be inspected.
data MsgHeartbeat = MsgHeartbeat
  { _msgHeartbeat_flags :: !Word32
    -- ^ Status flags
  } deriving ( Show, Read, Eq )

instance Binary MsgHeartbeat where
  get = do
    _msgHeartbeat_flags <- getWord32le
    pure MsgHeartbeat {..}

  put MsgHeartbeat {..} = do
    putWord32le _msgHeartbeat_flags

$(makeSBP 'msgHeartbeat ''MsgHeartbeat)
$(makeJSON "_msgHeartbeat_" ''MsgHeartbeat)
$(makeLenses ''MsgHeartbeat)

-- | SubSystemReport.
--
-- Report the general and specific state of a subsystem.  If the generic state
-- is reported as initializing, the specific state should be ignored.
data SubSystemReport = SubSystemReport
  { _subSystemReport_component :: !Word16
    -- ^ Identity of reporting subsystem
  , _subSystemReport_generic :: !Word8
    -- ^ Generic form status report
  , _subSystemReport_specific :: !Word8
    -- ^ Subsystem specific status code
  } deriving ( Show, Read, Eq )

instance Binary SubSystemReport where
  get = do
    _subSystemReport_component <- getWord16le
    _subSystemReport_generic <- getWord8
    _subSystemReport_specific <- getWord8
    pure SubSystemReport {..}

  put SubSystemReport {..} = do
    putWord16le _subSystemReport_component
    putWord8 _subSystemReport_generic
    putWord8 _subSystemReport_specific

$(makeJSON "_subSystemReport_" ''SubSystemReport)
$(makeLenses ''SubSystemReport)

msgStatusReport :: Word16
msgStatusReport = 0xFFFE

-- | SBP class for message MSG_STATUS_REPORT (0xFFFE).
--
-- The status report is sent periodically to inform the host or other attached
-- devices that the system is running. It is used to monitor system
-- malfunctions. It contains status reports that indicate to the host the
-- status of each subsystem and whether it is operating correctly.
--
-- Interpretation of the subsystem specific status code is product dependent,
-- but if the generic status code is initializing, it should be ignored.
-- Refer to product documentation for details.
data MsgStatusReport = MsgStatusReport
  { _msgStatusReport_reporting_system :: !Word16
    -- ^ Identity of reporting system
  , _msgStatusReport_sbp_version    :: !Word16
    -- ^ SBP protocol version
  , _msgStatusReport_sequence       :: !Word32
    -- ^ Increments on each status report sent
  , _msgStatusReport_uptime         :: !Word32
    -- ^ Number of seconds since system start-up
  , _msgStatusReport_status         :: ![SubSystemReport]
    -- ^ Reported status of individual subsystems
  } deriving ( Show, Read, Eq )

instance Binary MsgStatusReport where
  get = do
    _msgStatusReport_reporting_system <- getWord16le
    _msgStatusReport_sbp_version <- getWord16le
    _msgStatusReport_sequence <- getWord32le
    _msgStatusReport_uptime <- getWord32le
    _msgStatusReport_status <- whileM (not <$> isEmpty) get
    pure MsgStatusReport {..}

  put MsgStatusReport {..} = do
    putWord16le _msgStatusReport_reporting_system
    putWord16le _msgStatusReport_sbp_version
    putWord32le _msgStatusReport_sequence
    putWord32le _msgStatusReport_uptime
    mapM_ put _msgStatusReport_status

$(makeSBP 'msgStatusReport ''MsgStatusReport)
$(makeJSON "_msgStatusReport_" ''MsgStatusReport)
$(makeLenses ''MsgStatusReport)

-- | StatusJournalItem.
--
-- Reports the uptime and the state of a subsystem via generic and specific
-- status codes.  If the generic state is reported as initializing, the
-- specific state should be ignored.
data StatusJournalItem = StatusJournalItem
  { _statusJournalItem_uptime :: !Word32
    -- ^ Milliseconds since system startup
  , _statusJournalItem_report :: !SubSystemReport
  } deriving ( Show, Read, Eq )

instance Binary StatusJournalItem where
  get = do
    _statusJournalItem_uptime <- getWord32le
    _statusJournalItem_report <- get
    pure StatusJournalItem {..}

  put StatusJournalItem {..} = do
    putWord32le _statusJournalItem_uptime
    put _statusJournalItem_report

$(makeJSON "_statusJournalItem_" ''StatusJournalItem)
$(makeLenses ''StatusJournalItem)

msgStatusJournal :: Word16
msgStatusJournal = 0xFFFD

-- | SBP class for message MSG_STATUS_JOURNAL (0xFFFD).
--
-- The status journal message contains past status reports (see
-- MSG_STATUS_REPORT) and functions as a error/event storage for telemetry
-- purposes.
data MsgStatusJournal = MsgStatusJournal
  { _msgStatusJournal_reporting_system   :: !Word16
    -- ^ Identity of reporting system
  , _msgStatusJournal_sbp_version        :: !Word16
    -- ^ SBP protocol version
  , _msgStatusJournal_total_status_reports :: !Word32
    -- ^ Total number of status reports sent since system startup
  , _msgStatusJournal_sequence_descriptor :: !Word8
    -- ^ Index and number of messages in this sequence. First nibble is the size
    -- of the sequence (n), second nibble is the zero-indexed counter (ith
    -- packet of n)
  , _msgStatusJournal_journal            :: ![StatusJournalItem]
    -- ^ Status journal
  } deriving ( Show, Read, Eq )

instance Binary MsgStatusJournal where
  get = do
    _msgStatusJournal_reporting_system <- getWord16le
    _msgStatusJournal_sbp_version <- getWord16le
    _msgStatusJournal_total_status_reports <- getWord32le
    _msgStatusJournal_sequence_descriptor <- getWord8
    _msgStatusJournal_journal <- whileM (not <$> isEmpty) get
    pure MsgStatusJournal {..}

  put MsgStatusJournal {..} = do
    putWord16le _msgStatusJournal_reporting_system
    putWord16le _msgStatusJournal_sbp_version
    putWord32le _msgStatusJournal_total_status_reports
    putWord8 _msgStatusJournal_sequence_descriptor
    mapM_ put _msgStatusJournal_journal

$(makeSBP 'msgStatusJournal ''MsgStatusJournal)
$(makeJSON "_msgStatusJournal_" ''MsgStatusJournal)
$(makeLenses ''MsgStatusJournal)

msgInsStatus :: Word16
msgInsStatus = 0xFF03

-- | SBP class for message MSG_INS_STATUS (0xFF03).
--
-- The INS status message describes the state of the operation and
-- initialization of the inertial navigation system.
data MsgInsStatus = MsgInsStatus
  { _msgInsStatus_flags :: !Word32
    -- ^ Status flags
  } deriving ( Show, Read, Eq )

instance Binary MsgInsStatus where
  get = do
    _msgInsStatus_flags <- getWord32le
    pure MsgInsStatus {..}

  put MsgInsStatus {..} = do
    putWord32le _msgInsStatus_flags

$(makeSBP 'msgInsStatus ''MsgInsStatus)
$(makeJSON "_msgInsStatus_" ''MsgInsStatus)
$(makeLenses ''MsgInsStatus)

msgCsacTelemetry :: Word16
msgCsacTelemetry = 0xFF04

-- | SBP class for message MSG_CSAC_TELEMETRY (0xFF04).
--
-- The CSAC telemetry message has an implementation defined telemetry string
-- from a device. It is not produced or available on general Swift Products.
-- It is intended to be a low rate message for status purposes.
data MsgCsacTelemetry = MsgCsacTelemetry
  { _msgCsacTelemetry_id      :: !Word8
    -- ^ Index representing the type of telemetry in use.  It is implementation
    -- defined.
  , _msgCsacTelemetry_telemetry :: !Text
    -- ^ Comma separated list of values as defined by the index
  } deriving ( Show, Read, Eq )

instance Binary MsgCsacTelemetry where
  get = do
    _msgCsacTelemetry_id <- getWord8
    _msgCsacTelemetry_telemetry <- decodeUtf8 . toStrict <$> getRemainingLazyByteString
    pure MsgCsacTelemetry {..}

  put MsgCsacTelemetry {..} = do
    putWord8 _msgCsacTelemetry_id
    putByteString $ encodeUtf8 _msgCsacTelemetry_telemetry

$(makeSBP 'msgCsacTelemetry ''MsgCsacTelemetry)
$(makeJSON "_msgCsacTelemetry_" ''MsgCsacTelemetry)
$(makeLenses ''MsgCsacTelemetry)

msgCsacTelemetryLabels :: Word16
msgCsacTelemetryLabels = 0xFF05

-- | SBP class for message MSG_CSAC_TELEMETRY_LABELS (0xFF05).
--
-- The CSAC telemetry message provides labels for each member of the string
-- produced by MSG_CSAC_TELEMETRY. It should be provided by a device at a
-- lower rate than the MSG_CSAC_TELEMETRY.
data MsgCsacTelemetryLabels = MsgCsacTelemetryLabels
  { _msgCsacTelemetryLabels_id             :: !Word8
    -- ^ Index representing the type of telemetry in use.  It is implementation
    -- defined.
  , _msgCsacTelemetryLabels_telemetry_labels :: !Text
    -- ^ Comma separated list of telemetry field values
  } deriving ( Show, Read, Eq )

instance Binary MsgCsacTelemetryLabels where
  get = do
    _msgCsacTelemetryLabels_id <- getWord8
    _msgCsacTelemetryLabels_telemetry_labels <- decodeUtf8 . toStrict <$> getRemainingLazyByteString
    pure MsgCsacTelemetryLabels {..}

  put MsgCsacTelemetryLabels {..} = do
    putWord8 _msgCsacTelemetryLabels_id
    putByteString $ encodeUtf8 _msgCsacTelemetryLabels_telemetry_labels

$(makeSBP 'msgCsacTelemetryLabels ''MsgCsacTelemetryLabels)
$(makeJSON "_msgCsacTelemetryLabels_" ''MsgCsacTelemetryLabels)
$(makeLenses ''MsgCsacTelemetryLabels)

msgInsUpdates :: Word16
msgInsUpdates = 0xFF06

-- | SBP class for message MSG_INS_UPDATES (0xFF06).
--
-- The INS update status message contains information about executed and
-- rejected INS updates. This message is expected to be extended in the future
-- as new types of measurements are being added.
data MsgInsUpdates = MsgInsUpdates
  { _msgInsUpdates_tow      :: !Word32
    -- ^ GPS Time of Week
  , _msgInsUpdates_gnsspos  :: !Word8
    -- ^ GNSS position update status flags
  , _msgInsUpdates_gnssvel  :: !Word8
    -- ^ GNSS velocity update status flags
  , _msgInsUpdates_wheelticks :: !Word8
    -- ^ Wheelticks update status flags
  , _msgInsUpdates_speed    :: !Word8
    -- ^ Wheelticks update status flags
  , _msgInsUpdates_nhc      :: !Word8
    -- ^ NHC update status flags
  , _msgInsUpdates_zerovel  :: !Word8
    -- ^ Zero velocity update status flags
  } deriving ( Show, Read, Eq )

instance Binary MsgInsUpdates where
  get = do
    _msgInsUpdates_tow <- getWord32le
    _msgInsUpdates_gnsspos <- getWord8
    _msgInsUpdates_gnssvel <- getWord8
    _msgInsUpdates_wheelticks <- getWord8
    _msgInsUpdates_speed <- getWord8
    _msgInsUpdates_nhc <- getWord8
    _msgInsUpdates_zerovel <- getWord8
    pure MsgInsUpdates {..}

  put MsgInsUpdates {..} = do
    putWord32le _msgInsUpdates_tow
    putWord8 _msgInsUpdates_gnsspos
    putWord8 _msgInsUpdates_gnssvel
    putWord8 _msgInsUpdates_wheelticks
    putWord8 _msgInsUpdates_speed
    putWord8 _msgInsUpdates_nhc
    putWord8 _msgInsUpdates_zerovel

$(makeSBP 'msgInsUpdates ''MsgInsUpdates)
$(makeJSON "_msgInsUpdates_" ''MsgInsUpdates)
$(makeLenses ''MsgInsUpdates)

msgGnssTimeOffset :: Word16
msgGnssTimeOffset = 0xFF07

-- | SBP class for message MSG_GNSS_TIME_OFFSET (0xFF07).
--
-- The GNSS time offset message contains the information that is needed to
-- translate messages tagged with a local timestamp (e.g. IMU or wheeltick
-- messages) to GNSS time for the sender producing this message.
data MsgGnssTimeOffset = MsgGnssTimeOffset
  { _msgGnssTimeOffset_weeks      :: !Int16
    -- ^ Weeks portion of the time offset
  , _msgGnssTimeOffset_milliseconds :: !Int32
    -- ^ Milliseconds portion of the time offset
  , _msgGnssTimeOffset_microseconds :: !Int16
    -- ^ Microseconds portion of the time offset
  , _msgGnssTimeOffset_flags      :: !Word8
    -- ^ Status flags
  } deriving ( Show, Read, Eq )

instance Binary MsgGnssTimeOffset where
  get = do
    _msgGnssTimeOffset_weeks <- (fromIntegral <$> getWord16le)
    _msgGnssTimeOffset_milliseconds <- (fromIntegral <$> getWord32le)
    _msgGnssTimeOffset_microseconds <- (fromIntegral <$> getWord16le)
    _msgGnssTimeOffset_flags <- getWord8
    pure MsgGnssTimeOffset {..}

  put MsgGnssTimeOffset {..} = do
    (putWord16le . fromIntegral) _msgGnssTimeOffset_weeks
    (putWord32le . fromIntegral) _msgGnssTimeOffset_milliseconds
    (putWord16le . fromIntegral) _msgGnssTimeOffset_microseconds
    putWord8 _msgGnssTimeOffset_flags

$(makeSBP 'msgGnssTimeOffset ''MsgGnssTimeOffset)
$(makeJSON "_msgGnssTimeOffset_" ''MsgGnssTimeOffset)
$(makeLenses ''MsgGnssTimeOffset)

msgPpsTime :: Word16
msgPpsTime = 0xFF08

-- | SBP class for message MSG_PPS_TIME (0xFF08).
--
-- The PPS time message contains the value of the sender's local time in
-- microseconds at the moment a pulse is detected on the PPS input. This is to
-- be used for synchronisation of sensor data sampled with a local timestamp
-- (e.g. IMU or wheeltick messages) where GNSS time is unknown to the sender.
--
-- The local time used to timestamp the PPS pulse must be generated by the
-- same clock which is used to timestamp the IMU/wheel sensor data and should
-- follow the same roll-over rules (i.e. it should roll over to zero after
-- 604800 seconds). A separate MSG_PPS_TIME message should be sent for each
-- source of sensor data which uses local timestamping.  The sender ID for
-- each of these MSG_PPS_TIME messages should match the sender ID of the
-- respective sensor data.
data MsgPpsTime = MsgPpsTime
  { _msgPpsTime_time :: !Word64
    -- ^ Local time in microseconds
  , _msgPpsTime_flags :: !Word8
    -- ^ Status flags
  } deriving ( Show, Read, Eq )

instance Binary MsgPpsTime where
  get = do
    _msgPpsTime_time <- getWord64le
    _msgPpsTime_flags <- getWord8
    pure MsgPpsTime {..}

  put MsgPpsTime {..} = do
    putWord64le _msgPpsTime_time
    putWord8 _msgPpsTime_flags

$(makeSBP 'msgPpsTime ''MsgPpsTime)
$(makeJSON "_msgPpsTime_" ''MsgPpsTime)
$(makeLenses ''MsgPpsTime)

msgSensorAidEvent :: Word16
msgSensorAidEvent = 0xFF09

-- | SBP class for message MSG_SENSOR_AID_EVENT (0xFF09).
--
-- This diagnostic message contains state and update status information for
-- all sensors that are being used by the fusion engine. This message will be
-- generated asynchronously to the solution messages and will be emitted
-- anytime a sensor update is being processed.
data MsgSensorAidEvent = MsgSensorAidEvent
  { _msgSensorAidEvent_time           :: !Word32
    -- ^ Update timestamp in milliseconds.
  , _msgSensorAidEvent_sensor_type    :: !Word8
    -- ^ Sensor type
  , _msgSensorAidEvent_sensor_id      :: !Word16
    -- ^ Sensor identifier
  , _msgSensorAidEvent_sensor_state   :: !Word8
    -- ^ Reserved for future use
  , _msgSensorAidEvent_n_available_meas :: !Word8
    -- ^ Number of available measurements in this epoch
  , _msgSensorAidEvent_n_attempted_meas :: !Word8
    -- ^ Number of attempted measurements in this epoch
  , _msgSensorAidEvent_n_accepted_meas :: !Word8
    -- ^ Number of accepted measurements in this epoch
  , _msgSensorAidEvent_flags          :: !Word32
    -- ^ Reserved for future use
  } deriving ( Show, Read, Eq )

instance Binary MsgSensorAidEvent where
  get = do
    _msgSensorAidEvent_time <- getWord32le
    _msgSensorAidEvent_sensor_type <- getWord8
    _msgSensorAidEvent_sensor_id <- getWord16le
    _msgSensorAidEvent_sensor_state <- getWord8
    _msgSensorAidEvent_n_available_meas <- getWord8
    _msgSensorAidEvent_n_attempted_meas <- getWord8
    _msgSensorAidEvent_n_accepted_meas <- getWord8
    _msgSensorAidEvent_flags <- getWord32le
    pure MsgSensorAidEvent {..}

  put MsgSensorAidEvent {..} = do
    putWord32le _msgSensorAidEvent_time
    putWord8 _msgSensorAidEvent_sensor_type
    putWord16le _msgSensorAidEvent_sensor_id
    putWord8 _msgSensorAidEvent_sensor_state
    putWord8 _msgSensorAidEvent_n_available_meas
    putWord8 _msgSensorAidEvent_n_attempted_meas
    putWord8 _msgSensorAidEvent_n_accepted_meas
    putWord32le _msgSensorAidEvent_flags

$(makeSBP 'msgSensorAidEvent ''MsgSensorAidEvent)
$(makeJSON "_msgSensorAidEvent_" ''MsgSensorAidEvent)
$(makeLenses ''MsgSensorAidEvent)

msgGroupMeta :: Word16
msgGroupMeta = 0xFF0A

-- | SBP class for message MSG_GROUP_META (0xFF0A).
--
-- This leading message lists the time metadata of the Solution Group. It also
-- lists the atomic contents (i.e. types of messages included) of the Solution
-- Group.
data MsgGroupMeta = MsgGroupMeta
  { _msgGroupMeta_group_id   :: !Word8
    -- ^ Id of the Msgs Group, 0 is Unknown, 1 is Bestpos, 2 is Gnss
  , _msgGroupMeta_flags      :: !Word8
    -- ^ Status flags (reserved)
  , _msgGroupMeta_n_group_msgs :: !Word8
    -- ^ Size of list group_msgs
  , _msgGroupMeta_group_msgs :: ![Word16]
    -- ^ An in-order list of message types included in the Solution Group,
    -- including GROUP_META itself
  } deriving ( Show, Read, Eq )

instance Binary MsgGroupMeta where
  get = do
    _msgGroupMeta_group_id <- getWord8
    _msgGroupMeta_flags <- getWord8
    _msgGroupMeta_n_group_msgs <- getWord8
    _msgGroupMeta_group_msgs <- whileM (not <$> isEmpty) getWord16le
    pure MsgGroupMeta {..}

  put MsgGroupMeta {..} = do
    putWord8 _msgGroupMeta_group_id
    putWord8 _msgGroupMeta_flags
    putWord8 _msgGroupMeta_n_group_msgs
    mapM_ putWord16le _msgGroupMeta_group_msgs

$(makeSBP 'msgGroupMeta ''MsgGroupMeta)
$(makeJSON "_msgGroupMeta_" ''MsgGroupMeta)
$(makeLenses ''MsgGroupMeta)