content: {-# 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)
  
  