diff --git a/sbp.cabal b/sbp.cabal
--- a/sbp.cabal
+++ b/sbp.cabal
@@ -1,5 +1,5 @@
 name: sbp
-version: 2.2.8
+version: 2.2.9
 cabal-version: >=1.22
 build-type: Simple
 license: LGPL-3
@@ -25,9 +25,8 @@
 
 library
     exposed-modules:
-        SwiftNav.CRC16
+        SwiftNav.Internal
         SwiftNav.SBP
-        SwiftNav.SBP.Encoding
     build-depends:
         aeson >=0.11.3.0,
         array >=0.5.1.0,
@@ -45,6 +44,8 @@
     default-language: Haskell2010
     hs-source-dirs: src
     other-modules:
+        SwiftNav.CRC16
+        SwiftNav.Encoding
         SwiftNav.SBP.Msg
         SwiftNav.SBP.TH
         SwiftNav.SBP.Types
@@ -78,7 +79,7 @@
         conduit-combinators >=1.0.8.3,
         conduit-extra >=1.1.16,
         resourcet >=1.1.9,
-        sbp >=2.2.8
+        sbp
     default-language: Haskell2010
     hs-source-dirs: main
     ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
@@ -95,7 +96,7 @@
         conduit-combinators >=1.0.8.3,
         conduit-extra >=1.1.16,
         resourcet >=1.1.9,
-        sbp >=2.2.8
+        sbp
     default-language: Haskell2010
     hs-source-dirs: main
     ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
@@ -110,7 +111,7 @@
         conduit >=1.2.10,
         conduit-extra >=1.1.16,
         resourcet >=1.1.9,
-        sbp >=2.2.8,
+        sbp,
         yaml >=0.8.23
     default-language: Haskell2010
     hs-source-dirs: main
@@ -126,7 +127,7 @@
         basic-prelude >=0.5.2,
         bytestring >=0.10.6.0,
         QuickCheck >=2.8.2,
-        sbp >=2.2.8,
+        sbp,
         tasty >=0.11.2.1,
         tasty-hunit >=0.9.2,
         tasty-quickcheck >=0.8.4
@@ -134,5 +135,5 @@
     hs-source-dirs: test
     other-modules:
         Test.SwiftNav.CRC16
-        Test.SwiftNav.SBP.Encoding
+        Test.SwiftNav.Encoding
     ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
diff --git a/src/SwiftNav/Encoding.hs b/src/SwiftNav/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/SwiftNav/Encoding.hs
@@ -0,0 +1,31 @@
+{-# OPTIONS -fno-warn-orphans  #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module:      SwiftNav.Encoding
+-- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
+-- License:     LGPL-3
+-- Maintainer:  Mark Fine <dev@swiftnav.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Encoding utilities.
+
+module SwiftNav.Encoding where
+
+import BasicPrelude
+import Data.Aeson
+import Data.ByteString.Base64   as Base64
+import Data.Text.Encoding
+import Data.Text.Encoding.Error
+
+-- ByteString doesn't have Aeson instances defined for it since
+-- arbitrary ByteString's aren't really valid JSON. This defines
+-- orphaned instances for ByteStrings that are expected to be valid
+-- text.
+
+instance ToJSON ByteString where
+  toJSON = toJSON . decodeUtf8With ignore . Base64.encode
+
+instance FromJSON ByteString where
+  parseJSON = withText "ByteString" (pure . Base64.decodeLenient . encodeUtf8)
diff --git a/src/SwiftNav/Internal.hs b/src/SwiftNav/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/SwiftNav/Internal.hs
@@ -0,0 +1,8 @@
+-- | Internal Module
+--
+module SwiftNav.Internal
+  ( module Exports
+  ) where
+
+import SwiftNav.CRC16    as Exports
+import SwiftNav.Encoding as Exports ()
diff --git a/src/SwiftNav/SBP.hs b/src/SwiftNav/SBP.hs
--- a/src/SwiftNav/SBP.hs
+++ b/src/SwiftNav/SBP.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
 -- |
 -- Module:      SwiftNav.SBP
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -11,41 +9,24 @@
 -- SBP message containers.
 
 module SwiftNav.SBP
-  ( module SwiftNav.SBP.Msg
-  , module SwiftNav.SBP.Types
-  , module SwiftNav.SBP.Acquisition
-  , module SwiftNav.SBP.Bootload
-  , module SwiftNav.SBP.ExtEvents
-  , module SwiftNav.SBP.FileIo
-  , module SwiftNav.SBP.Flash
-  , module SwiftNav.SBP.Gnss
-  , module SwiftNav.SBP.Imu
-  , module SwiftNav.SBP.Logging
-  , module SwiftNav.SBP.Navigation
-  , module SwiftNav.SBP.Ndb
-  , module SwiftNav.SBP.Observation
-  , module SwiftNav.SBP.Piksi
-  , module SwiftNav.SBP.Settings
-  , module SwiftNav.SBP.System
-  , module SwiftNav.SBP.Tracking
-  , module SwiftNav.SBP.User
+  ( module Exports
   ) where
 
-import SwiftNav.SBP.Msg
-import SwiftNav.SBP.Types
-import SwiftNav.SBP.Acquisition
-import SwiftNav.SBP.Bootload
-import SwiftNav.SBP.ExtEvents
-import SwiftNav.SBP.FileIo
-import SwiftNav.SBP.Flash
-import SwiftNav.SBP.Gnss
-import SwiftNav.SBP.Imu
-import SwiftNav.SBP.Logging
-import SwiftNav.SBP.Navigation
-import SwiftNav.SBP.Ndb
-import SwiftNav.SBP.Observation
-import SwiftNav.SBP.Piksi
-import SwiftNav.SBP.Settings
-import SwiftNav.SBP.System
-import SwiftNav.SBP.Tracking
-import SwiftNav.SBP.User
+import SwiftNav.SBP.Msg as Exports
+import SwiftNav.SBP.Types as Exports
+import SwiftNav.SBP.Acquisition as Exports
+import SwiftNav.SBP.Bootload as Exports
+import SwiftNav.SBP.ExtEvents as Exports
+import SwiftNav.SBP.FileIo as Exports
+import SwiftNav.SBP.Flash as Exports
+import SwiftNav.SBP.Gnss as Exports
+import SwiftNav.SBP.Imu as Exports
+import SwiftNav.SBP.Logging as Exports
+import SwiftNav.SBP.Navigation as Exports
+import SwiftNav.SBP.Ndb as Exports
+import SwiftNav.SBP.Observation as Exports
+import SwiftNav.SBP.Piksi as Exports
+import SwiftNav.SBP.Settings as Exports
+import SwiftNav.SBP.System as Exports
+import SwiftNav.SBP.Tracking as Exports
+import SwiftNav.SBP.User as Exports
diff --git a/src/SwiftNav/SBP/Acquisition.hs b/src/SwiftNav/SBP/Acquisition.hs
--- a/src/SwiftNav/SBP/Acquisition.hs
+++ b/src/SwiftNav/SBP/Acquisition.hs
@@ -13,12 +13,13 @@
 --
 -- Satellite acquisition messages from the device.
 
-module SwiftNav.SBP.Acquisition where
+module SwiftNav.SBP.Acquisition
+  ( module SwiftNav.SBP.Acquisition
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 import SwiftNav.SBP.Gnss
@@ -66,10 +67,8 @@
     putFloat32le _msgAcqResult_cf
     put _msgAcqResult_sid
 
-$(deriveSBP 'msgAcqResult ''MsgAcqResult)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAcqResult_" . P.stripPrefix "_msgAcqResult_"}
-             ''MsgAcqResult)
+$(makeSBP 'msgAcqResult ''MsgAcqResult)
+$(makeJSON "_msgAcqResult_" ''MsgAcqResult)
 $(makeLenses ''MsgAcqResult)
 
 msgAcqResultDepB :: Word16
@@ -104,10 +103,8 @@
     putFloat32le _msgAcqResultDepB_cf
     put _msgAcqResultDepB_sid
 
-$(deriveSBP 'msgAcqResultDepB ''MsgAcqResultDepB)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAcqResultDepB_" . P.stripPrefix "_msgAcqResultDepB_"}
-             ''MsgAcqResultDepB)
+$(makeSBP 'msgAcqResultDepB ''MsgAcqResultDepB)
+$(makeJSON "_msgAcqResultDepB_" ''MsgAcqResultDepB)
 $(makeLenses ''MsgAcqResultDepB)
 
 msgAcqResultDepA :: Word16
@@ -143,10 +140,8 @@
     putFloat32le _msgAcqResultDepA_cf
     putWord8 _msgAcqResultDepA_prn
 
-$(deriveSBP 'msgAcqResultDepA ''MsgAcqResultDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAcqResultDepA_" . P.stripPrefix "_msgAcqResultDepA_"}
-             ''MsgAcqResultDepA)
+$(makeSBP 'msgAcqResultDepA ''MsgAcqResultDepA)
+$(makeJSON "_msgAcqResultDepA_" ''MsgAcqResultDepA)
 $(makeLenses ''MsgAcqResultDepA)
 
 -- | AcqSvProfile.
@@ -210,8 +205,8 @@
     putWord32le $ fromIntegral _acqSvProfile_cf_max
     putWord32le $ fromIntegral _acqSvProfile_cf
     putWord32le _acqSvProfile_cp
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_acqSvProfile_" . P.stripPrefix "_acqSvProfile_"}
-             ''AcqSvProfile)
+
+$(makeJSON "_acqSvProfile_" ''AcqSvProfile)
 $(makeLenses ''AcqSvProfile)
 
 msgAcqSvProfile :: Word16
@@ -234,8 +229,6 @@
   put MsgAcqSvProfile {..} = do
     mapM_ put _msgAcqSvProfile_acq_sv_profile
 
-$(deriveSBP 'msgAcqSvProfile ''MsgAcqSvProfile)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAcqSvProfile_" . P.stripPrefix "_msgAcqSvProfile_"}
-             ''MsgAcqSvProfile)
+$(makeSBP 'msgAcqSvProfile ''MsgAcqSvProfile)
+$(makeJSON "_msgAcqSvProfile_" ''MsgAcqSvProfile)
 $(makeLenses ''MsgAcqSvProfile)
diff --git a/src/SwiftNav/SBP/Bootload.hs b/src/SwiftNav/SBP/Bootload.hs
--- a/src/SwiftNav/SBP/Bootload.hs
+++ b/src/SwiftNav/SBP/Bootload.hs
@@ -15,12 +15,13 @@
 -- group does not apply to Piksi Multi.  Note that some of these messages share
 -- the same message type ID for both the host request and the device response.
 
-module SwiftNav.SBP.Bootload where
+module SwiftNav.SBP.Bootload
+  ( module SwiftNav.SBP.Bootload
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -29,7 +30,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -50,11 +51,8 @@
 
   put MsgBootloaderHandshakeReq =
     return ()
-
-$(deriveSBP 'msgBootloaderHandshakeReq ''MsgBootloaderHandshakeReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBootloaderHandshakeReq_" . P.stripPrefix "_msgBootloaderHandshakeReq_"}
-             ''MsgBootloaderHandshakeReq)
+$(makeSBP 'msgBootloaderHandshakeReq ''MsgBootloaderHandshakeReq)
+$(makeJSON "_msgBootloaderHandshakeReq_" ''MsgBootloaderHandshakeReq)
 $(makeLenses ''MsgBootloaderHandshakeReq)
 
 msgBootloaderHandshakeResp :: Word16
@@ -83,10 +81,8 @@
     putWord32le _msgBootloaderHandshakeResp_flags
     putByteString $ encodeUtf8 _msgBootloaderHandshakeResp_version
 
-$(deriveSBP 'msgBootloaderHandshakeResp ''MsgBootloaderHandshakeResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBootloaderHandshakeResp_" . P.stripPrefix "_msgBootloaderHandshakeResp_"}
-             ''MsgBootloaderHandshakeResp)
+$(makeSBP 'msgBootloaderHandshakeResp ''MsgBootloaderHandshakeResp)
+$(makeJSON "_msgBootloaderHandshakeResp_" ''MsgBootloaderHandshakeResp)
 $(makeLenses ''MsgBootloaderHandshakeResp)
 
 msgBootloaderJumpToApp :: Word16
@@ -108,10 +104,8 @@
   put MsgBootloaderJumpToApp {..} = do
     putWord8 _msgBootloaderJumpToApp_jump
 
-$(deriveSBP 'msgBootloaderJumpToApp ''MsgBootloaderJumpToApp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBootloaderJumpToApp_" . P.stripPrefix "_msgBootloaderJumpToApp_"}
-             ''MsgBootloaderJumpToApp)
+$(makeSBP 'msgBootloaderJumpToApp ''MsgBootloaderJumpToApp)
+$(makeJSON "_msgBootloaderJumpToApp_" ''MsgBootloaderJumpToApp)
 $(makeLenses ''MsgBootloaderJumpToApp)
 
 msgNapDeviceDnaReq :: Word16
@@ -133,11 +127,8 @@
 
   put MsgNapDeviceDnaReq =
     return ()
-
-$(deriveSBP 'msgNapDeviceDnaReq ''MsgNapDeviceDnaReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgNapDeviceDnaReq_" . P.stripPrefix "_msgNapDeviceDnaReq_"}
-             ''MsgNapDeviceDnaReq)
+$(makeSBP 'msgNapDeviceDnaReq ''MsgNapDeviceDnaReq)
+$(makeJSON "_msgNapDeviceDnaReq_" ''MsgNapDeviceDnaReq)
 $(makeLenses ''MsgNapDeviceDnaReq)
 
 msgNapDeviceDnaResp :: Word16
@@ -164,10 +155,8 @@
   put MsgNapDeviceDnaResp {..} = do
     mapM_ putWord8 _msgNapDeviceDnaResp_dna
 
-$(deriveSBP 'msgNapDeviceDnaResp ''MsgNapDeviceDnaResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgNapDeviceDnaResp_" . P.stripPrefix "_msgNapDeviceDnaResp_"}
-             ''MsgNapDeviceDnaResp)
+$(makeSBP 'msgNapDeviceDnaResp ''MsgNapDeviceDnaResp)
+$(makeJSON "_msgNapDeviceDnaResp_" ''MsgNapDeviceDnaResp)
 $(makeLenses ''MsgNapDeviceDnaResp)
 
 msgBootloaderHandshakeDepA :: Word16
@@ -189,8 +178,6 @@
   put MsgBootloaderHandshakeDepA {..} = do
     mapM_ putWord8 _msgBootloaderHandshakeDepA_handshake
 
-$(deriveSBP 'msgBootloaderHandshakeDepA ''MsgBootloaderHandshakeDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBootloaderHandshakeDepA_" . P.stripPrefix "_msgBootloaderHandshakeDepA_"}
-             ''MsgBootloaderHandshakeDepA)
+$(makeSBP 'msgBootloaderHandshakeDepA ''MsgBootloaderHandshakeDepA)
+$(makeJSON "_msgBootloaderHandshakeDepA_" ''MsgBootloaderHandshakeDepA)
 $(makeLenses ''MsgBootloaderHandshakeDepA)
diff --git a/src/SwiftNav/SBP/Encoding.hs b/src/SwiftNav/SBP/Encoding.hs
deleted file mode 100644
--- a/src/SwiftNav/SBP/Encoding.hs
+++ /dev/null
@@ -1,32 +0,0 @@
-{-# OPTIONS -fno-warn-orphans  #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-
--- |
--- Module:      SwiftNav.SBP.Encoding
--- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
--- License:     LGPL-3
--- Maintainer:  Mark Fine <dev@swiftnav.com>
--- Stability:   experimental
--- Portability: portable
---
--- Encoding utilities.
-
-module SwiftNav.SBP.Encoding where
-
-import           BasicPrelude
-import           Data.Aeson
-import qualified Data.ByteString          as B
-import           Data.ByteString.Base64   as Base64
-import           Data.Text.Encoding       (decodeUtf8With)
-import           Data.Text.Encoding.Error
-
--- ByteString doesn't have Aeson instances defined for it since
--- arbitrary ByteString's aren't really valid JSON. This defines
--- orphaned instances for ByteStrings that are expected to be valid
--- text.
-
-instance ToJSON B.ByteString where
-  toJSON = toJSON . decodeUtf8With ignore . Base64.encode
-
-instance FromJSON B.ByteString where
-  parseJSON = withText "ByteString" (pure . Base64.decodeLenient . encodeUtf8)
diff --git a/src/SwiftNav/SBP/ExtEvents.hs b/src/SwiftNav/SBP/ExtEvents.hs
--- a/src/SwiftNav/SBP/ExtEvents.hs
+++ b/src/SwiftNav/SBP/ExtEvents.hs
@@ -14,12 +14,13 @@
 -- Messages reporting accurately-timestamped external events, e.g. camera
 -- shutter time.
 
-module SwiftNav.SBP.ExtEvents where
+module SwiftNav.SBP.ExtEvents
+  ( module SwiftNav.SBP.ExtEvents
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -28,7 +29,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -69,8 +70,6 @@
     putWord8 _msgExtEvent_flags
     putWord8 _msgExtEvent_pin
 
-$(deriveSBP 'msgExtEvent ''MsgExtEvent)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgExtEvent_" . P.stripPrefix "_msgExtEvent_"}
-             ''MsgExtEvent)
+$(makeSBP 'msgExtEvent ''MsgExtEvent)
+$(makeJSON "_msgExtEvent_" ''MsgExtEvent)
 $(makeLenses ''MsgExtEvent)
diff --git a/src/SwiftNav/SBP/FileIo.hs b/src/SwiftNav/SBP/FileIo.hs
--- a/src/SwiftNav/SBP/FileIo.hs
+++ b/src/SwiftNav/SBP/FileIo.hs
@@ -18,12 +18,13 @@
 -- reading and writing files.  Note that some of these messages share the same
 -- message type ID for both the host request and the device response.
 
-module SwiftNav.SBP.FileIo where
+module SwiftNav.SBP.FileIo
+  ( module SwiftNav.SBP.FileIo
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -32,7 +33,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -73,10 +74,8 @@
     putWord8 _msgFileioReadReq_chunk_size
     putByteString $ encodeUtf8 _msgFileioReadReq_filename
 
-$(deriveSBP 'msgFileioReadReq ''MsgFileioReadReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioReadReq_" . P.stripPrefix "_msgFileioReadReq_"}
-             ''MsgFileioReadReq)
+$(makeSBP 'msgFileioReadReq ''MsgFileioReadReq)
+$(makeJSON "_msgFileioReadReq_" ''MsgFileioReadReq)
 $(makeLenses ''MsgFileioReadReq)
 
 msgFileioReadResp :: Word16
@@ -105,10 +104,8 @@
     putWord32le _msgFileioReadResp_sequence
     mapM_ putWord8 _msgFileioReadResp_contents
 
-$(deriveSBP 'msgFileioReadResp ''MsgFileioReadResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioReadResp_" . P.stripPrefix "_msgFileioReadResp_"}
-             ''MsgFileioReadResp)
+$(makeSBP 'msgFileioReadResp ''MsgFileioReadResp)
+$(makeJSON "_msgFileioReadResp_" ''MsgFileioReadResp)
 $(makeLenses ''MsgFileioReadResp)
 
 msgFileioReadDirReq :: Word16
@@ -145,10 +142,8 @@
     putWord32le _msgFileioReadDirReq_offset
     putByteString $ encodeUtf8 _msgFileioReadDirReq_dirname
 
-$(deriveSBP 'msgFileioReadDirReq ''MsgFileioReadDirReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioReadDirReq_" . P.stripPrefix "_msgFileioReadDirReq_"}
-             ''MsgFileioReadDirReq)
+$(makeSBP 'msgFileioReadDirReq ''MsgFileioReadDirReq)
+$(makeJSON "_msgFileioReadDirReq_" ''MsgFileioReadDirReq)
 $(makeLenses ''MsgFileioReadDirReq)
 
 msgFileioReadDirResp :: Word16
@@ -178,10 +173,8 @@
     putWord32le _msgFileioReadDirResp_sequence
     mapM_ putWord8 _msgFileioReadDirResp_contents
 
-$(deriveSBP 'msgFileioReadDirResp ''MsgFileioReadDirResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioReadDirResp_" . P.stripPrefix "_msgFileioReadDirResp_"}
-             ''MsgFileioReadDirResp)
+$(makeSBP 'msgFileioReadDirResp ''MsgFileioReadDirResp)
+$(makeJSON "_msgFileioReadDirResp_" ''MsgFileioReadDirResp)
 $(makeLenses ''MsgFileioReadDirResp)
 
 msgFileioRemove :: Word16
@@ -206,10 +199,8 @@
   put MsgFileioRemove {..} = do
     putByteString $ encodeUtf8 _msgFileioRemove_filename
 
-$(deriveSBP 'msgFileioRemove ''MsgFileioRemove)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioRemove_" . P.stripPrefix "_msgFileioRemove_"}
-             ''MsgFileioRemove)
+$(makeSBP 'msgFileioRemove ''MsgFileioRemove)
+$(makeJSON "_msgFileioRemove_" ''MsgFileioRemove)
 $(makeLenses ''MsgFileioRemove)
 
 msgFileioWriteReq :: Word16
@@ -249,10 +240,8 @@
     putByteString $ encodeUtf8 _msgFileioWriteReq_filename
     mapM_ putWord8 _msgFileioWriteReq_data
 
-$(deriveSBP 'msgFileioWriteReq ''MsgFileioWriteReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioWriteReq_" . P.stripPrefix "_msgFileioWriteReq_"}
-             ''MsgFileioWriteReq)
+$(makeSBP 'msgFileioWriteReq ''MsgFileioWriteReq)
+$(makeJSON "_msgFileioWriteReq_" ''MsgFileioWriteReq)
 $(makeLenses ''MsgFileioWriteReq)
 
 msgFileioWriteResp :: Word16
@@ -277,8 +266,6 @@
   put MsgFileioWriteResp {..} = do
     putWord32le _msgFileioWriteResp_sequence
 
-$(deriveSBP 'msgFileioWriteResp ''MsgFileioWriteResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFileioWriteResp_" . P.stripPrefix "_msgFileioWriteResp_"}
-             ''MsgFileioWriteResp)
+$(makeSBP 'msgFileioWriteResp ''MsgFileioWriteResp)
+$(makeJSON "_msgFileioWriteResp_" ''MsgFileioWriteResp)
 $(makeLenses ''MsgFileioWriteResp)
diff --git a/src/SwiftNav/SBP/Flash.hs b/src/SwiftNav/SBP/Flash.hs
--- a/src/SwiftNav/SBP/Flash.hs
+++ b/src/SwiftNav/SBP/Flash.hs
@@ -16,12 +16,13 @@
 -- Navigation devices: the STM32 flash and the M25Pxx FPGA configuration flash
 -- from Piksi 2.3.1.  This module does not apply  to Piksi Multi.
 
-module SwiftNav.SBP.Flash where
+module SwiftNav.SBP.Flash
+  ( module SwiftNav.SBP.Flash
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -30,7 +31,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -69,10 +70,8 @@
     putWord8 _msgFlashProgram_addr_len
     mapM_ putWord8 _msgFlashProgram_data
 
-$(deriveSBP 'msgFlashProgram ''MsgFlashProgram)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFlashProgram_" . P.stripPrefix "_msgFlashProgram_"}
-             ''MsgFlashProgram)
+$(makeSBP 'msgFlashProgram ''MsgFlashProgram)
+$(makeJSON "_msgFlashProgram_" ''MsgFlashProgram)
 $(makeLenses ''MsgFlashProgram)
 
 msgFlashDone :: Word16
@@ -97,10 +96,8 @@
   put MsgFlashDone {..} = do
     putWord8 _msgFlashDone_response
 
-$(deriveSBP 'msgFlashDone ''MsgFlashDone)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFlashDone_" . P.stripPrefix "_msgFlashDone_"}
-             ''MsgFlashDone)
+$(makeSBP 'msgFlashDone ''MsgFlashDone)
+$(makeJSON "_msgFlashDone_" ''MsgFlashDone)
 $(makeLenses ''MsgFlashDone)
 
 msgFlashReadReq :: Word16
@@ -135,10 +132,8 @@
     mapM_ putWord8 _msgFlashReadReq_addr_start
     putWord8 _msgFlashReadReq_addr_len
 
-$(deriveSBP 'msgFlashReadReq ''MsgFlashReadReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFlashReadReq_" . P.stripPrefix "_msgFlashReadReq_"}
-             ''MsgFlashReadReq)
+$(makeSBP 'msgFlashReadReq ''MsgFlashReadReq)
+$(makeJSON "_msgFlashReadReq_" ''MsgFlashReadReq)
 $(makeLenses ''MsgFlashReadReq)
 
 msgFlashReadResp :: Word16
@@ -173,10 +168,8 @@
     mapM_ putWord8 _msgFlashReadResp_addr_start
     putWord8 _msgFlashReadResp_addr_len
 
-$(deriveSBP 'msgFlashReadResp ''MsgFlashReadResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFlashReadResp_" . P.stripPrefix "_msgFlashReadResp_"}
-             ''MsgFlashReadResp)
+$(makeSBP 'msgFlashReadResp ''MsgFlashReadResp)
+$(makeJSON "_msgFlashReadResp_" ''MsgFlashReadResp)
 $(makeLenses ''MsgFlashReadResp)
 
 msgFlashErase :: Word16
@@ -205,10 +198,8 @@
     putWord8 _msgFlashErase_target
     putWord32le _msgFlashErase_sector_num
 
-$(deriveSBP 'msgFlashErase ''MsgFlashErase)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFlashErase_" . P.stripPrefix "_msgFlashErase_"}
-             ''MsgFlashErase)
+$(makeSBP 'msgFlashErase ''MsgFlashErase)
+$(makeJSON "_msgFlashErase_" ''MsgFlashErase)
 $(makeLenses ''MsgFlashErase)
 
 msgStmFlashLockSector :: Word16
@@ -231,10 +222,8 @@
   put MsgStmFlashLockSector {..} = do
     putWord32le _msgStmFlashLockSector_sector
 
-$(deriveSBP 'msgStmFlashLockSector ''MsgStmFlashLockSector)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgStmFlashLockSector_" . P.stripPrefix "_msgStmFlashLockSector_"}
-             ''MsgStmFlashLockSector)
+$(makeSBP 'msgStmFlashLockSector ''MsgStmFlashLockSector)
+$(makeJSON "_msgStmFlashLockSector_" ''MsgStmFlashLockSector)
 $(makeLenses ''MsgStmFlashLockSector)
 
 msgStmFlashUnlockSector :: Word16
@@ -257,10 +246,8 @@
   put MsgStmFlashUnlockSector {..} = do
     putWord32le _msgStmFlashUnlockSector_sector
 
-$(deriveSBP 'msgStmFlashUnlockSector ''MsgStmFlashUnlockSector)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgStmFlashUnlockSector_" . P.stripPrefix "_msgStmFlashUnlockSector_"}
-             ''MsgStmFlashUnlockSector)
+$(makeSBP 'msgStmFlashUnlockSector ''MsgStmFlashUnlockSector)
+$(makeJSON "_msgStmFlashUnlockSector_" ''MsgStmFlashUnlockSector)
 $(makeLenses ''MsgStmFlashUnlockSector)
 
 msgStmUniqueIdReq :: Word16
@@ -280,11 +267,8 @@
 
   put MsgStmUniqueIdReq =
     return ()
-
-$(deriveSBP 'msgStmUniqueIdReq ''MsgStmUniqueIdReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgStmUniqueIdReq_" . P.stripPrefix "_msgStmUniqueIdReq_"}
-             ''MsgStmUniqueIdReq)
+$(makeSBP 'msgStmUniqueIdReq ''MsgStmUniqueIdReq)
+$(makeJSON "_msgStmUniqueIdReq_" ''MsgStmUniqueIdReq)
 $(makeLenses ''MsgStmUniqueIdReq)
 
 msgStmUniqueIdResp :: Word16
@@ -308,10 +292,8 @@
   put MsgStmUniqueIdResp {..} = do
     mapM_ putWord8 _msgStmUniqueIdResp_stm_id
 
-$(deriveSBP 'msgStmUniqueIdResp ''MsgStmUniqueIdResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgStmUniqueIdResp_" . P.stripPrefix "_msgStmUniqueIdResp_"}
-             ''MsgStmUniqueIdResp)
+$(makeSBP 'msgStmUniqueIdResp ''MsgStmUniqueIdResp)
+$(makeJSON "_msgStmUniqueIdResp_" ''MsgStmUniqueIdResp)
 $(makeLenses ''MsgStmUniqueIdResp)
 
 msgM25FlashWriteStatus :: Word16
@@ -334,8 +316,6 @@
   put MsgM25FlashWriteStatus {..} = do
     mapM_ putWord8 _msgM25FlashWriteStatus_status
 
-$(deriveSBP 'msgM25FlashWriteStatus ''MsgM25FlashWriteStatus)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgM25FlashWriteStatus_" . P.stripPrefix "_msgM25FlashWriteStatus_"}
-             ''MsgM25FlashWriteStatus)
+$(makeSBP 'msgM25FlashWriteStatus ''MsgM25FlashWriteStatus)
+$(makeJSON "_msgM25FlashWriteStatus_" ''MsgM25FlashWriteStatus)
 $(makeLenses ''MsgM25FlashWriteStatus)
diff --git a/src/SwiftNav/SBP/Gnss.hs b/src/SwiftNav/SBP/Gnss.hs
--- a/src/SwiftNav/SBP/Gnss.hs
+++ b/src/SwiftNav/SBP/Gnss.hs
@@ -13,12 +13,13 @@
 --
 -- Various structs shared between modules
 
-module SwiftNav.SBP.Gnss where
+module SwiftNav.SBP.Gnss
+  ( module SwiftNav.SBP.Gnss
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -50,8 +51,8 @@
   put GnssSignal16 {..} = do
     putWord8 _gnssSignal16_sat
     putWord8 _gnssSignal16_code
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gnssSignal16_" . P.stripPrefix "_gnssSignal16_"}
-             ''GnssSignal16)
+
+$(makeJSON "_gnssSignal16_" ''GnssSignal16)
 $(makeLenses ''GnssSignal16)
 
 -- | GnssSignal.
@@ -79,8 +80,8 @@
     putWord16le _gnssSignal_sat
     putWord8 _gnssSignal_code
     putWord8 _gnssSignal_reserved
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gnssSignal_" . P.stripPrefix "_gnssSignal_"}
-             ''GnssSignal)
+
+$(makeJSON "_gnssSignal_" ''GnssSignal)
 $(makeLenses ''GnssSignal)
 
 -- | GPSTime.
@@ -103,8 +104,8 @@
   put GpsTime {..} = do
     putWord32le _gpsTime_tow
     putWord16le _gpsTime_wn
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gpsTime_" . P.stripPrefix "_gpsTime_"}
-             ''GpsTime)
+
+$(makeJSON "_gpsTime_" ''GpsTime)
 $(makeLenses ''GpsTime)
 
 -- | GPSTimeSec.
@@ -127,8 +128,8 @@
   put GpsTimeSec {..} = do
     putWord32le _gpsTimeSec_tow
     putWord16le _gpsTimeSec_wn
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gpsTimeSec_" . P.stripPrefix "_gpsTimeSec_"}
-             ''GpsTimeSec)
+
+$(makeJSON "_gpsTimeSec_" ''GpsTimeSec)
 $(makeLenses ''GpsTimeSec)
 
 -- | GPSTimeNano.
@@ -157,8 +158,8 @@
     putWord32le _gpsTimeNano_tow
     putWord32le $ fromIntegral _gpsTimeNano_ns_residual
     putWord16le _gpsTimeNano_wn
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gpsTimeNano_" . P.stripPrefix "_gpsTimeNano_"}
-             ''GpsTimeNano)
+
+$(makeJSON "_gpsTimeNano_" ''GpsTimeNano)
 $(makeLenses ''GpsTimeNano)
 
 -- | CarrierPhase.
@@ -182,6 +183,6 @@
   put CarrierPhase {..} = do
     putWord32le $ fromIntegral _carrierPhase_i
     putWord8 _carrierPhase_f
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_carrierPhase_" . P.stripPrefix "_carrierPhase_"}
-             ''CarrierPhase)
+
+$(makeJSON "_carrierPhase_" ''CarrierPhase)
 $(makeLenses ''CarrierPhase)
diff --git a/src/SwiftNav/SBP/Imu.hs b/src/SwiftNav/SBP/Imu.hs
--- a/src/SwiftNav/SBP/Imu.hs
+++ b/src/SwiftNav/SBP/Imu.hs
@@ -13,12 +13,13 @@
 --
 -- Inertial Measurement Unit (IMU) messages.
 
-module SwiftNav.SBP.Imu where
+module SwiftNav.SBP.Imu
+  ( module SwiftNav.SBP.Imu
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -80,10 +81,8 @@
     putWord16le $ fromIntegral _msgImuRaw_gyr_y
     putWord16le $ fromIntegral _msgImuRaw_gyr_z
 
-$(deriveSBP 'msgImuRaw ''MsgImuRaw)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgImuRaw_" . P.stripPrefix "_msgImuRaw_"}
-             ''MsgImuRaw)
+$(makeSBP 'msgImuRaw ''MsgImuRaw)
+$(makeJSON "_msgImuRaw_" ''MsgImuRaw)
 $(makeLenses ''MsgImuRaw)
 
 msgImuAux :: Word16
@@ -115,8 +114,6 @@
     putWord16le $ fromIntegral _msgImuAux_temp
     putWord8 _msgImuAux_imu_conf
 
-$(deriveSBP 'msgImuAux ''MsgImuAux)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgImuAux_" . P.stripPrefix "_msgImuAux_"}
-             ''MsgImuAux)
+$(makeSBP 'msgImuAux ''MsgImuAux)
+$(makeJSON "_msgImuAux_" ''MsgImuAux)
 $(makeLenses ''MsgImuAux)
diff --git a/src/SwiftNav/SBP/Logging.hs b/src/SwiftNav/SBP/Logging.hs
--- a/src/SwiftNav/SBP/Logging.hs
+++ b/src/SwiftNav/SBP/Logging.hs
@@ -13,12 +13,13 @@
 --
 -- Logging and debugging messages from the device.
 
-module SwiftNav.SBP.Logging where
+module SwiftNav.SBP.Logging
+  ( module SwiftNav.SBP.Logging
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -56,10 +57,8 @@
     putWord8 _msgLog_level
     putByteString $ encodeUtf8 _msgLog_text
 
-$(deriveSBP 'msgLog ''MsgLog)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgLog_" . P.stripPrefix "_msgLog_"}
-             ''MsgLog)
+$(makeSBP 'msgLog ''MsgLog)
+$(makeJSON "_msgLog_" ''MsgLog)
 $(makeLenses ''MsgLog)
 
 msgFwd :: Word16
@@ -95,10 +94,8 @@
     putWord8 _msgFwd_protocol
     putByteString $ encodeUtf8 _msgFwd_fwd_payload
 
-$(deriveSBP 'msgFwd ''MsgFwd)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFwd_" . P.stripPrefix "_msgFwd_"}
-             ''MsgFwd)
+$(makeSBP 'msgFwd ''MsgFwd)
+$(makeJSON "_msgFwd_" ''MsgFwd)
 $(makeLenses ''MsgFwd)
 
 msgTweet :: Word16
@@ -120,10 +117,8 @@
   put MsgTweet {..} = do
     putByteString $ encodeUtf8 _msgTweet_tweet
 
-$(deriveSBP 'msgTweet ''MsgTweet)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTweet_" . P.stripPrefix "_msgTweet_"}
-             ''MsgTweet)
+$(makeSBP 'msgTweet ''MsgTweet)
+$(makeJSON "_msgTweet_" ''MsgTweet)
 $(makeLenses ''MsgTweet)
 
 msgPrintDep :: Word16
@@ -145,8 +140,6 @@
   put MsgPrintDep {..} = do
     putByteString $ encodeUtf8 _msgPrintDep_text
 
-$(deriveSBP 'msgPrintDep ''MsgPrintDep)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgPrintDep_" . P.stripPrefix "_msgPrintDep_"}
-             ''MsgPrintDep)
+$(makeSBP 'msgPrintDep ''MsgPrintDep)
+$(makeJSON "_msgPrintDep_" ''MsgPrintDep)
 $(makeLenses ''MsgPrintDep)
diff --git a/src/SwiftNav/SBP/Msg.hs b/src/SwiftNav/SBP/Msg.hs
--- a/src/SwiftNav/SBP/Msg.hs
+++ b/src/SwiftNav/SBP/Msg.hs
@@ -14,11 +14,13 @@
 --
 -- SBP message containers.
 
-module SwiftNav.SBP.Msg where
+module SwiftNav.SBP.Msg
+  ( module SwiftNav.SBP.Msg
+  ) where
 
-import BasicPrelude             hiding (lookup)
-import Control.Lens             hiding ((.=))
-import Data.Aeson               hiding (decode, decode')
+import BasicPrelude
+import Control.Lens
+import Data.Aeson               hiding (decode)
 import Data.Binary
 import Data.ByteString.Lazy     hiding (ByteString)
 import SwiftNav.SBP.Acquisition
@@ -172,8 +174,8 @@
   get = do
     preamble <- getWord8
     if preamble /= msgSBPPreamble then get else do
-      decode' <$> get where
-        decode' m@Msg {..}
+      decoder <$> get where
+        decoder m@Msg {..}
           | checkCrc m /= _msgSBPCrc = SBPMsgBadCrc m
           | _msgSBPType == msgAcqResult = SBPMsgAcqResult (decode (fromStrict _msgSBPPayload)) m
           | _msgSBPType == msgAcqResultDepA = SBPMsgAcqResultDepA (decode (fromStrict _msgSBPPayload)) m
@@ -296,376 +298,377 @@
 
   put sm = do
     putWord8 msgSBPPreamble
-    encode' sm where
-      encode' (SBPMsgAcqResult _ m) = put m
-      encode' (SBPMsgAcqResultDepA _ m) = put m
-      encode' (SBPMsgAcqResultDepB _ m) = put m
-      encode' (SBPMsgAcqSvProfile _ m) = put m
-      encode' (SBPMsgAgeCorrections _ m) = put m
-      encode' (SBPMsgAlmanac _ m) = put m
-      encode' (SBPMsgAlmanacGlo _ m) = put m
-      encode' (SBPMsgAlmanacGps _ m) = put m
-      encode' (SBPMsgBasePosEcef _ m) = put m
-      encode' (SBPMsgBasePosLlh _ m) = put m
-      encode' (SBPMsgBaselineEcef _ m) = put m
-      encode' (SBPMsgBaselineEcefDepA _ m) = put m
-      encode' (SBPMsgBaselineHeading _ m) = put m
-      encode' (SBPMsgBaselineHeadingDepA _ m) = put m
-      encode' (SBPMsgBaselineNed _ m) = put m
-      encode' (SBPMsgBaselineNedDepA _ m) = put m
-      encode' (SBPMsgBootloaderHandshakeDepA _ m) = put m
-      encode' (SBPMsgBootloaderHandshakeReq _ m) = put m
-      encode' (SBPMsgBootloaderHandshakeResp _ m) = put m
-      encode' (SBPMsgBootloaderJumpToApp _ m) = put m
-      encode' (SBPMsgCommandOutput _ m) = put m
-      encode' (SBPMsgCommandReq _ m) = put m
-      encode' (SBPMsgCommandResp _ m) = put m
-      encode' (SBPMsgCwResults _ m) = put m
-      encode' (SBPMsgCwStart _ m) = put m
-      encode' (SBPMsgDeviceMonitor _ m) = put m
-      encode' (SBPMsgDgnssStatus _ m) = put m
-      encode' (SBPMsgDops _ m) = put m
-      encode' (SBPMsgDopsDepA _ m) = put m
-      encode' (SBPMsgEphemerisDepA _ m) = put m
-      encode' (SBPMsgEphemerisDepB _ m) = put m
-      encode' (SBPMsgEphemerisDepC _ m) = put m
-      encode' (SBPMsgEphemerisDepD _ m) = put m
-      encode' (SBPMsgEphemerisGlo _ m) = put m
-      encode' (SBPMsgEphemerisGloDepA _ m) = put m
-      encode' (SBPMsgEphemerisGloDepB _ m) = put m
-      encode' (SBPMsgEphemerisGloDepC _ m) = put m
-      encode' (SBPMsgEphemerisGps _ m) = put m
-      encode' (SBPMsgEphemerisGpsDepE _ m) = put m
-      encode' (SBPMsgEphemerisSbas _ m) = put m
-      encode' (SBPMsgEphemerisSbasDepA _ m) = put m
-      encode' (SBPMsgExtEvent _ m) = put m
-      encode' (SBPMsgFcnsGlo _ m) = put m
-      encode' (SBPMsgFileioReadDirReq _ m) = put m
-      encode' (SBPMsgFileioReadDirResp _ m) = put m
-      encode' (SBPMsgFileioReadReq _ m) = put m
-      encode' (SBPMsgFileioReadResp _ m) = put m
-      encode' (SBPMsgFileioRemove _ m) = put m
-      encode' (SBPMsgFileioWriteReq _ m) = put m
-      encode' (SBPMsgFileioWriteResp _ m) = put m
-      encode' (SBPMsgFlashDone _ m) = put m
-      encode' (SBPMsgFlashErase _ m) = put m
-      encode' (SBPMsgFlashProgram _ m) = put m
-      encode' (SBPMsgFlashReadReq _ m) = put m
-      encode' (SBPMsgFlashReadResp _ m) = put m
-      encode' (SBPMsgFwd _ m) = put m
-      encode' (SBPMsgGpsTime _ m) = put m
-      encode' (SBPMsgGpsTimeDepA _ m) = put m
-      encode' (SBPMsgGroupDelay _ m) = put m
-      encode' (SBPMsgGroupDelayDepA _ m) = put m
-      encode' (SBPMsgHeartbeat _ m) = put m
-      encode' (SBPMsgIarState _ m) = put m
-      encode' (SBPMsgImuAux _ m) = put m
-      encode' (SBPMsgImuRaw _ m) = put m
-      encode' (SBPMsgInitBase _ m) = put m
-      encode' (SBPMsgIono _ m) = put m
-      encode' (SBPMsgLog _ m) = put m
-      encode' (SBPMsgM25FlashWriteStatus _ m) = put m
-      encode' (SBPMsgMaskSatellite _ m) = put m
-      encode' (SBPMsgNapDeviceDnaReq _ m) = put m
-      encode' (SBPMsgNapDeviceDnaResp _ m) = put m
-      encode' (SBPMsgNdbEvent _ m) = put m
-      encode' (SBPMsgNetworkStateReq _ m) = put m
-      encode' (SBPMsgNetworkStateResp _ m) = put m
-      encode' (SBPMsgObs _ m) = put m
-      encode' (SBPMsgObsDepA _ m) = put m
-      encode' (SBPMsgObsDepB _ m) = put m
-      encode' (SBPMsgObsDepC _ m) = put m
-      encode' (SBPMsgPosEcef _ m) = put m
-      encode' (SBPMsgPosEcefDepA _ m) = put m
-      encode' (SBPMsgPosLlh _ m) = put m
-      encode' (SBPMsgPosLlhDepA _ m) = put m
-      encode' (SBPMsgPrintDep _ m) = put m
-      encode' (SBPMsgReset _ m) = put m
-      encode' (SBPMsgResetDep _ m) = put m
-      encode' (SBPMsgResetFilters _ m) = put m
-      encode' (SBPMsgSetTime _ m) = put m
-      encode' (SBPMsgSettingsReadByIndexDone _ m) = put m
-      encode' (SBPMsgSettingsReadByIndexReq _ m) = put m
-      encode' (SBPMsgSettingsReadByIndexResp _ m) = put m
-      encode' (SBPMsgSettingsReadReq _ m) = put m
-      encode' (SBPMsgSettingsReadResp _ m) = put m
-      encode' (SBPMsgSettingsRegister _ m) = put m
-      encode' (SBPMsgSettingsSave _ m) = put m
-      encode' (SBPMsgSettingsWrite _ m) = put m
-      encode' (SBPMsgSpecan _ m) = put m
-      encode' (SBPMsgStartup _ m) = put m
-      encode' (SBPMsgStmFlashLockSector _ m) = put m
-      encode' (SBPMsgStmFlashUnlockSector _ m) = put m
-      encode' (SBPMsgStmUniqueIdReq _ m) = put m
-      encode' (SBPMsgStmUniqueIdResp _ m) = put m
-      encode' (SBPMsgSvConfigurationGps _ m) = put m
-      encode' (SBPMsgThreadState _ m) = put m
-      encode' (SBPMsgTrackingIq _ m) = put m
-      encode' (SBPMsgTrackingState _ m) = put m
-      encode' (SBPMsgTrackingStateDepA _ m) = put m
-      encode' (SBPMsgTrackingStateDepB _ m) = put m
-      encode' (SBPMsgTrackingStateDetailed _ m) = put m
-      encode' (SBPMsgTweet _ m) = put m
-      encode' (SBPMsgUartState _ m) = put m
-      encode' (SBPMsgUartStateDepa _ m) = put m
-      encode' (SBPMsgUserData _ m) = put m
-      encode' (SBPMsgUtcTime _ m) = put m
-      encode' (SBPMsgVelEcef _ m) = put m
-      encode' (SBPMsgVelEcefDepA _ m) = put m
-      encode' (SBPMsgVelNed _ m) = put m
-      encode' (SBPMsgVelNedDepA _ m) = put m
-      encode' (SBPMsgUnknown m) = put m
-      encode' (SBPMsgBadCrc m) = put m
+    encoder sm where
+      encoder (SBPMsgAcqResult _ m) = put m
+      encoder (SBPMsgAcqResultDepA _ m) = put m
+      encoder (SBPMsgAcqResultDepB _ m) = put m
+      encoder (SBPMsgAcqSvProfile _ m) = put m
+      encoder (SBPMsgAgeCorrections _ m) = put m
+      encoder (SBPMsgAlmanac _ m) = put m
+      encoder (SBPMsgAlmanacGlo _ m) = put m
+      encoder (SBPMsgAlmanacGps _ m) = put m
+      encoder (SBPMsgBasePosEcef _ m) = put m
+      encoder (SBPMsgBasePosLlh _ m) = put m
+      encoder (SBPMsgBaselineEcef _ m) = put m
+      encoder (SBPMsgBaselineEcefDepA _ m) = put m
+      encoder (SBPMsgBaselineHeading _ m) = put m
+      encoder (SBPMsgBaselineHeadingDepA _ m) = put m
+      encoder (SBPMsgBaselineNed _ m) = put m
+      encoder (SBPMsgBaselineNedDepA _ m) = put m
+      encoder (SBPMsgBootloaderHandshakeDepA _ m) = put m
+      encoder (SBPMsgBootloaderHandshakeReq _ m) = put m
+      encoder (SBPMsgBootloaderHandshakeResp _ m) = put m
+      encoder (SBPMsgBootloaderJumpToApp _ m) = put m
+      encoder (SBPMsgCommandOutput _ m) = put m
+      encoder (SBPMsgCommandReq _ m) = put m
+      encoder (SBPMsgCommandResp _ m) = put m
+      encoder (SBPMsgCwResults _ m) = put m
+      encoder (SBPMsgCwStart _ m) = put m
+      encoder (SBPMsgDeviceMonitor _ m) = put m
+      encoder (SBPMsgDgnssStatus _ m) = put m
+      encoder (SBPMsgDops _ m) = put m
+      encoder (SBPMsgDopsDepA _ m) = put m
+      encoder (SBPMsgEphemerisDepA _ m) = put m
+      encoder (SBPMsgEphemerisDepB _ m) = put m
+      encoder (SBPMsgEphemerisDepC _ m) = put m
+      encoder (SBPMsgEphemerisDepD _ m) = put m
+      encoder (SBPMsgEphemerisGlo _ m) = put m
+      encoder (SBPMsgEphemerisGloDepA _ m) = put m
+      encoder (SBPMsgEphemerisGloDepB _ m) = put m
+      encoder (SBPMsgEphemerisGloDepC _ m) = put m
+      encoder (SBPMsgEphemerisGps _ m) = put m
+      encoder (SBPMsgEphemerisGpsDepE _ m) = put m
+      encoder (SBPMsgEphemerisSbas _ m) = put m
+      encoder (SBPMsgEphemerisSbasDepA _ m) = put m
+      encoder (SBPMsgExtEvent _ m) = put m
+      encoder (SBPMsgFcnsGlo _ m) = put m
+      encoder (SBPMsgFileioReadDirReq _ m) = put m
+      encoder (SBPMsgFileioReadDirResp _ m) = put m
+      encoder (SBPMsgFileioReadReq _ m) = put m
+      encoder (SBPMsgFileioReadResp _ m) = put m
+      encoder (SBPMsgFileioRemove _ m) = put m
+      encoder (SBPMsgFileioWriteReq _ m) = put m
+      encoder (SBPMsgFileioWriteResp _ m) = put m
+      encoder (SBPMsgFlashDone _ m) = put m
+      encoder (SBPMsgFlashErase _ m) = put m
+      encoder (SBPMsgFlashProgram _ m) = put m
+      encoder (SBPMsgFlashReadReq _ m) = put m
+      encoder (SBPMsgFlashReadResp _ m) = put m
+      encoder (SBPMsgFwd _ m) = put m
+      encoder (SBPMsgGpsTime _ m) = put m
+      encoder (SBPMsgGpsTimeDepA _ m) = put m
+      encoder (SBPMsgGroupDelay _ m) = put m
+      encoder (SBPMsgGroupDelayDepA _ m) = put m
+      encoder (SBPMsgHeartbeat _ m) = put m
+      encoder (SBPMsgIarState _ m) = put m
+      encoder (SBPMsgImuAux _ m) = put m
+      encoder (SBPMsgImuRaw _ m) = put m
+      encoder (SBPMsgInitBase _ m) = put m
+      encoder (SBPMsgIono _ m) = put m
+      encoder (SBPMsgLog _ m) = put m
+      encoder (SBPMsgM25FlashWriteStatus _ m) = put m
+      encoder (SBPMsgMaskSatellite _ m) = put m
+      encoder (SBPMsgNapDeviceDnaReq _ m) = put m
+      encoder (SBPMsgNapDeviceDnaResp _ m) = put m
+      encoder (SBPMsgNdbEvent _ m) = put m
+      encoder (SBPMsgNetworkStateReq _ m) = put m
+      encoder (SBPMsgNetworkStateResp _ m) = put m
+      encoder (SBPMsgObs _ m) = put m
+      encoder (SBPMsgObsDepA _ m) = put m
+      encoder (SBPMsgObsDepB _ m) = put m
+      encoder (SBPMsgObsDepC _ m) = put m
+      encoder (SBPMsgPosEcef _ m) = put m
+      encoder (SBPMsgPosEcefDepA _ m) = put m
+      encoder (SBPMsgPosLlh _ m) = put m
+      encoder (SBPMsgPosLlhDepA _ m) = put m
+      encoder (SBPMsgPrintDep _ m) = put m
+      encoder (SBPMsgReset _ m) = put m
+      encoder (SBPMsgResetDep _ m) = put m
+      encoder (SBPMsgResetFilters _ m) = put m
+      encoder (SBPMsgSetTime _ m) = put m
+      encoder (SBPMsgSettingsReadByIndexDone _ m) = put m
+      encoder (SBPMsgSettingsReadByIndexReq _ m) = put m
+      encoder (SBPMsgSettingsReadByIndexResp _ m) = put m
+      encoder (SBPMsgSettingsReadReq _ m) = put m
+      encoder (SBPMsgSettingsReadResp _ m) = put m
+      encoder (SBPMsgSettingsRegister _ m) = put m
+      encoder (SBPMsgSettingsSave _ m) = put m
+      encoder (SBPMsgSettingsWrite _ m) = put m
+      encoder (SBPMsgSpecan _ m) = put m
+      encoder (SBPMsgStartup _ m) = put m
+      encoder (SBPMsgStmFlashLockSector _ m) = put m
+      encoder (SBPMsgStmFlashUnlockSector _ m) = put m
+      encoder (SBPMsgStmUniqueIdReq _ m) = put m
+      encoder (SBPMsgStmUniqueIdResp _ m) = put m
+      encoder (SBPMsgSvConfigurationGps _ m) = put m
+      encoder (SBPMsgThreadState _ m) = put m
+      encoder (SBPMsgTrackingIq _ m) = put m
+      encoder (SBPMsgTrackingState _ m) = put m
+      encoder (SBPMsgTrackingStateDepA _ m) = put m
+      encoder (SBPMsgTrackingStateDepB _ m) = put m
+      encoder (SBPMsgTrackingStateDetailed _ m) = put m
+      encoder (SBPMsgTweet _ m) = put m
+      encoder (SBPMsgUartState _ m) = put m
+      encoder (SBPMsgUartStateDepa _ m) = put m
+      encoder (SBPMsgUserData _ m) = put m
+      encoder (SBPMsgUtcTime _ m) = put m
+      encoder (SBPMsgVelEcef _ m) = put m
+      encoder (SBPMsgVelEcefDepA _ m) = put m
+      encoder (SBPMsgVelNed _ m) = put m
+      encoder (SBPMsgVelNedDepA _ m) = put m
+      encoder (SBPMsgUnknown m) = put m
+      encoder (SBPMsgBadCrc m) = put m
 
 instance FromJSON SBPMsg where
   parseJSON obj@(Object o) = do
     msgType <- o .: "msg_type"
-    decode' msgType where
-      decode' msgType
-        | msgType == msgAcqResult = SBPMsgAcqResult <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAcqResultDepA = SBPMsgAcqResultDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAcqResultDepB = SBPMsgAcqResultDepB <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAcqSvProfile = SBPMsgAcqSvProfile <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAgeCorrections = SBPMsgAgeCorrections <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAlmanac = SBPMsgAlmanac <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAlmanacGlo = SBPMsgAlmanacGlo <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgAlmanacGps = SBPMsgAlmanacGps <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBasePosEcef = SBPMsgBasePosEcef <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBasePosLlh = SBPMsgBasePosLlh <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineEcef = SBPMsgBaselineEcef <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineEcefDepA = SBPMsgBaselineEcefDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineHeading = SBPMsgBaselineHeading <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineHeadingDepA = SBPMsgBaselineHeadingDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineNed = SBPMsgBaselineNed <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBaselineNedDepA = SBPMsgBaselineNedDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBootloaderHandshakeDepA = SBPMsgBootloaderHandshakeDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBootloaderHandshakeReq = SBPMsgBootloaderHandshakeReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBootloaderHandshakeResp = SBPMsgBootloaderHandshakeResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgBootloaderJumpToApp = SBPMsgBootloaderJumpToApp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgCommandOutput = SBPMsgCommandOutput <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgCommandReq = SBPMsgCommandReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgCommandResp = SBPMsgCommandResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgCwResults = SBPMsgCwResults <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgCwStart = SBPMsgCwStart <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgDeviceMonitor = SBPMsgDeviceMonitor <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgDgnssStatus = SBPMsgDgnssStatus <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgDops = SBPMsgDops <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgDopsDepA = SBPMsgDopsDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisDepA = SBPMsgEphemerisDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisDepB = SBPMsgEphemerisDepB <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisDepC = SBPMsgEphemerisDepC <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisDepD = SBPMsgEphemerisDepD <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGlo = SBPMsgEphemerisGlo <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGloDepA = SBPMsgEphemerisGloDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGloDepB = SBPMsgEphemerisGloDepB <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGloDepC = SBPMsgEphemerisGloDepC <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGps = SBPMsgEphemerisGps <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisGpsDepE = SBPMsgEphemerisGpsDepE <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisSbas = SBPMsgEphemerisSbas <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgEphemerisSbasDepA = SBPMsgEphemerisSbasDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgExtEvent = SBPMsgExtEvent <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFcnsGlo = SBPMsgFcnsGlo <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioReadDirReq = SBPMsgFileioReadDirReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioReadDirResp = SBPMsgFileioReadDirResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioReadReq = SBPMsgFileioReadReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioReadResp = SBPMsgFileioReadResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioRemove = SBPMsgFileioRemove <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioWriteReq = SBPMsgFileioWriteReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFileioWriteResp = SBPMsgFileioWriteResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFlashDone = SBPMsgFlashDone <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFlashErase = SBPMsgFlashErase <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFlashProgram = SBPMsgFlashProgram <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFlashReadReq = SBPMsgFlashReadReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFlashReadResp = SBPMsgFlashReadResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgFwd = SBPMsgFwd <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgGpsTime = SBPMsgGpsTime <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgGpsTimeDepA = SBPMsgGpsTimeDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgGroupDelay = SBPMsgGroupDelay <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgGroupDelayDepA = SBPMsgGroupDelayDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgHeartbeat = SBPMsgHeartbeat <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgIarState = SBPMsgIarState <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgImuAux = SBPMsgImuAux <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgImuRaw = SBPMsgImuRaw <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgInitBase = SBPMsgInitBase <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgIono = SBPMsgIono <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgLog = SBPMsgLog <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgM25FlashWriteStatus = SBPMsgM25FlashWriteStatus <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgMaskSatellite = SBPMsgMaskSatellite <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgNapDeviceDnaReq = SBPMsgNapDeviceDnaReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgNapDeviceDnaResp = SBPMsgNapDeviceDnaResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgNdbEvent = SBPMsgNdbEvent <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgNetworkStateReq = SBPMsgNetworkStateReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgNetworkStateResp = SBPMsgNetworkStateResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgObs = SBPMsgObs <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgObsDepA = SBPMsgObsDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgObsDepB = SBPMsgObsDepB <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgObsDepC = SBPMsgObsDepC <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgPosEcef = SBPMsgPosEcef <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgPosEcefDepA = SBPMsgPosEcefDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgPosLlh = SBPMsgPosLlh <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgPosLlhDepA = SBPMsgPosLlhDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgPrintDep = SBPMsgPrintDep <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgReset = SBPMsgReset <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgResetDep = SBPMsgResetDep <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgResetFilters = SBPMsgResetFilters <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSetTime = SBPMsgSetTime <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsReadByIndexDone = SBPMsgSettingsReadByIndexDone <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsReadByIndexReq = SBPMsgSettingsReadByIndexReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsReadByIndexResp = SBPMsgSettingsReadByIndexResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsReadReq = SBPMsgSettingsReadReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsReadResp = SBPMsgSettingsReadResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsRegister = SBPMsgSettingsRegister <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsSave = SBPMsgSettingsSave <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSettingsWrite = SBPMsgSettingsWrite <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSpecan = SBPMsgSpecan <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgStartup = SBPMsgStartup <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgStmFlashLockSector = SBPMsgStmFlashLockSector <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgStmFlashUnlockSector = SBPMsgStmFlashUnlockSector <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgStmUniqueIdReq = SBPMsgStmUniqueIdReq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgStmUniqueIdResp = SBPMsgStmUniqueIdResp <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgSvConfigurationGps = SBPMsgSvConfigurationGps <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgThreadState = SBPMsgThreadState <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTrackingIq = SBPMsgTrackingIq <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTrackingState = SBPMsgTrackingState <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTrackingStateDepA = SBPMsgTrackingStateDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTrackingStateDepB = SBPMsgTrackingStateDepB <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTrackingStateDetailed = SBPMsgTrackingStateDetailed <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgTweet = SBPMsgTweet <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgUartState = SBPMsgUartState <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgUartStateDepa = SBPMsgUartStateDepa <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgUserData = SBPMsgUserData <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgUtcTime = SBPMsgUtcTime <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgVelEcef = SBPMsgVelEcef <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgVelEcefDepA = SBPMsgVelEcefDepA <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgVelNed = SBPMsgVelNed <$> parseJSON obj <*> parseJSON obj
-        | msgType == msgVelNedDepA = SBPMsgVelNedDepA <$> parseJSON obj <*> parseJSON obj
+    payload <- o .: "payload"
+    decoder msgType payload where
+      decoder msgType payload
+        | msgType == msgAcqResult = SBPMsgAcqResult <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAcqResultDepA = SBPMsgAcqResultDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAcqResultDepB = SBPMsgAcqResultDepB <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAcqSvProfile = SBPMsgAcqSvProfile <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAgeCorrections = SBPMsgAgeCorrections <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAlmanac = SBPMsgAlmanac <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAlmanacGlo = SBPMsgAlmanacGlo <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgAlmanacGps = SBPMsgAlmanacGps <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBasePosEcef = SBPMsgBasePosEcef <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBasePosLlh = SBPMsgBasePosLlh <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineEcef = SBPMsgBaselineEcef <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineEcefDepA = SBPMsgBaselineEcefDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineHeading = SBPMsgBaselineHeading <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineHeadingDepA = SBPMsgBaselineHeadingDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineNed = SBPMsgBaselineNed <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBaselineNedDepA = SBPMsgBaselineNedDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBootloaderHandshakeDepA = SBPMsgBootloaderHandshakeDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBootloaderHandshakeReq = SBPMsgBootloaderHandshakeReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBootloaderHandshakeResp = SBPMsgBootloaderHandshakeResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgBootloaderJumpToApp = SBPMsgBootloaderJumpToApp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgCommandOutput = SBPMsgCommandOutput <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgCommandReq = SBPMsgCommandReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgCommandResp = SBPMsgCommandResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgCwResults = SBPMsgCwResults <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgCwStart = SBPMsgCwStart <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgDeviceMonitor = SBPMsgDeviceMonitor <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgDgnssStatus = SBPMsgDgnssStatus <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgDops = SBPMsgDops <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgDopsDepA = SBPMsgDopsDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisDepA = SBPMsgEphemerisDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisDepB = SBPMsgEphemerisDepB <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisDepC = SBPMsgEphemerisDepC <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisDepD = SBPMsgEphemerisDepD <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGlo = SBPMsgEphemerisGlo <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGloDepA = SBPMsgEphemerisGloDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGloDepB = SBPMsgEphemerisGloDepB <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGloDepC = SBPMsgEphemerisGloDepC <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGps = SBPMsgEphemerisGps <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisGpsDepE = SBPMsgEphemerisGpsDepE <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisSbas = SBPMsgEphemerisSbas <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgEphemerisSbasDepA = SBPMsgEphemerisSbasDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgExtEvent = SBPMsgExtEvent <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFcnsGlo = SBPMsgFcnsGlo <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioReadDirReq = SBPMsgFileioReadDirReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioReadDirResp = SBPMsgFileioReadDirResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioReadReq = SBPMsgFileioReadReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioReadResp = SBPMsgFileioReadResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioRemove = SBPMsgFileioRemove <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioWriteReq = SBPMsgFileioWriteReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFileioWriteResp = SBPMsgFileioWriteResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFlashDone = SBPMsgFlashDone <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFlashErase = SBPMsgFlashErase <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFlashProgram = SBPMsgFlashProgram <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFlashReadReq = SBPMsgFlashReadReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFlashReadResp = SBPMsgFlashReadResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgFwd = SBPMsgFwd <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgGpsTime = SBPMsgGpsTime <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgGpsTimeDepA = SBPMsgGpsTimeDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgGroupDelay = SBPMsgGroupDelay <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgGroupDelayDepA = SBPMsgGroupDelayDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgHeartbeat = SBPMsgHeartbeat <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgIarState = SBPMsgIarState <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgImuAux = SBPMsgImuAux <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgImuRaw = SBPMsgImuRaw <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgInitBase = SBPMsgInitBase <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgIono = SBPMsgIono <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgLog = SBPMsgLog <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgM25FlashWriteStatus = SBPMsgM25FlashWriteStatus <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgMaskSatellite = SBPMsgMaskSatellite <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgNapDeviceDnaReq = SBPMsgNapDeviceDnaReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgNapDeviceDnaResp = SBPMsgNapDeviceDnaResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgNdbEvent = SBPMsgNdbEvent <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgNetworkStateReq = SBPMsgNetworkStateReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgNetworkStateResp = SBPMsgNetworkStateResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgObs = SBPMsgObs <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgObsDepA = SBPMsgObsDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgObsDepB = SBPMsgObsDepB <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgObsDepC = SBPMsgObsDepC <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgPosEcef = SBPMsgPosEcef <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgPosEcefDepA = SBPMsgPosEcefDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgPosLlh = SBPMsgPosLlh <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgPosLlhDepA = SBPMsgPosLlhDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgPrintDep = SBPMsgPrintDep <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgReset = SBPMsgReset <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgResetDep = SBPMsgResetDep <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgResetFilters = SBPMsgResetFilters <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSetTime = SBPMsgSetTime <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsReadByIndexDone = SBPMsgSettingsReadByIndexDone <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsReadByIndexReq = SBPMsgSettingsReadByIndexReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsReadByIndexResp = SBPMsgSettingsReadByIndexResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsReadReq = SBPMsgSettingsReadReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsReadResp = SBPMsgSettingsReadResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsRegister = SBPMsgSettingsRegister <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsSave = SBPMsgSettingsSave <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSettingsWrite = SBPMsgSettingsWrite <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSpecan = SBPMsgSpecan <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgStartup = SBPMsgStartup <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgStmFlashLockSector = SBPMsgStmFlashLockSector <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgStmFlashUnlockSector = SBPMsgStmFlashUnlockSector <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgStmUniqueIdReq = SBPMsgStmUniqueIdReq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgStmUniqueIdResp = SBPMsgStmUniqueIdResp <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgSvConfigurationGps = SBPMsgSvConfigurationGps <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgThreadState = SBPMsgThreadState <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTrackingIq = SBPMsgTrackingIq <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTrackingState = SBPMsgTrackingState <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTrackingStateDepA = SBPMsgTrackingStateDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTrackingStateDepB = SBPMsgTrackingStateDepB <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTrackingStateDetailed = SBPMsgTrackingStateDetailed <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgTweet = SBPMsgTweet <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgUartState = SBPMsgUartState <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgUartStateDepa = SBPMsgUartStateDepa <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgUserData = SBPMsgUserData <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgUtcTime = SBPMsgUtcTime <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgVelEcef = SBPMsgVelEcef <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgVelEcefDepA = SBPMsgVelEcefDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgVelNed = SBPMsgVelNed <$> pure (decode (fromStrict payload)) <*> parseJSON obj
+        | msgType == msgVelNedDepA = SBPMsgVelNedDepA <$> pure (decode (fromStrict payload)) <*> parseJSON obj
         | otherwise = SBPMsgUnknown <$> parseJSON obj
   parseJSON _ = mzero
 
-mergeValues :: Value -> Value -> Value
-mergeValues (Object a) (Object b) = Object (a <> b)
-mergeValues (Object a) _          = Object a
-mergeValues _          (Object b) = Object b
-mergeValues _          v          = v
+(<<>>) :: Value -> Value -> Value
+(Object a) <<>> (Object b) = Object (a <> b)
+(Object a) <<>> _          = Object a
+_          <<>> (Object b) = Object b
+_          <<>> v          = v
 
 instance ToJSON SBPMsg where
-  toJSON (SBPMsgAcqResult n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAcqResultDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAcqResultDepB n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAcqSvProfile n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAgeCorrections n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAlmanac n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAlmanacGlo n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgAlmanacGps n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBasePosEcef n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBasePosLlh n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineEcef n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineEcefDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineHeading n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineHeadingDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineNed n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBaselineNedDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBootloaderHandshakeDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBootloaderHandshakeReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBootloaderHandshakeResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgBootloaderJumpToApp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgCommandOutput n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgCommandReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgCommandResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgCwResults n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgCwStart n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgDeviceMonitor n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgDgnssStatus n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgDops n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgDopsDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisDepB n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisDepC n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisDepD n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGlo n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGloDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGloDepB n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGloDepC n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGps n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisGpsDepE n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisSbas n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgEphemerisSbasDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgExtEvent n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFcnsGlo n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioReadDirReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioReadDirResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioReadReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioReadResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioRemove n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioWriteReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFileioWriteResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFlashDone n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFlashErase n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFlashProgram n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFlashReadReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFlashReadResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgFwd n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgGpsTime n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgGpsTimeDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgGroupDelay n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgGroupDelayDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgHeartbeat n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgIarState n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgImuAux n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgImuRaw n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgInitBase n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgIono n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgLog n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgM25FlashWriteStatus n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgMaskSatellite n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgNapDeviceDnaReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgNapDeviceDnaResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgNdbEvent n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgNetworkStateReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgNetworkStateResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgObs n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgObsDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgObsDepB n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgObsDepC n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgPosEcef n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgPosEcefDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgPosLlh n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgPosLlhDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgPrintDep n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgReset n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgResetDep n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgResetFilters n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSetTime n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsReadByIndexDone n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsReadByIndexReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsReadByIndexResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsReadReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsReadResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsRegister n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsSave n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSettingsWrite n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSpecan n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgStartup n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgStmFlashLockSector n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgStmFlashUnlockSector n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgStmUniqueIdReq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgStmUniqueIdResp n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgSvConfigurationGps n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgThreadState n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTrackingIq n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTrackingState n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTrackingStateDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTrackingStateDepB n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTrackingStateDetailed n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgTweet n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgUartState n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgUartStateDepa n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgUserData n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgUtcTime n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgVelEcef n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgVelEcefDepA n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgVelNed n m) = toJSON n `mergeValues` toJSON m
-  toJSON (SBPMsgVelNedDepA n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgAcqResult n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAcqResultDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAcqResultDepB n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAcqSvProfile n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAgeCorrections n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAlmanac n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAlmanacGlo n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgAlmanacGps n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBasePosEcef n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBasePosLlh n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineEcef n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineEcefDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineHeading n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineHeadingDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineNed n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBaselineNedDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBootloaderHandshakeDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBootloaderHandshakeReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBootloaderHandshakeResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgBootloaderJumpToApp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgCommandOutput n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgCommandReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgCommandResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgCwResults n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgCwStart n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgDeviceMonitor n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgDgnssStatus n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgDops n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgDopsDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisDepB n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisDepC n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisDepD n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGlo n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGloDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGloDepB n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGloDepC n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGps n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisGpsDepE n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisSbas n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgEphemerisSbasDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgExtEvent n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFcnsGlo n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioReadDirReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioReadDirResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioReadReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioReadResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioRemove n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioWriteReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFileioWriteResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFlashDone n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFlashErase n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFlashProgram n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFlashReadReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFlashReadResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgFwd n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgGpsTime n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgGpsTimeDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgGroupDelay n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgGroupDelayDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgHeartbeat n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgIarState n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgImuAux n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgImuRaw n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgInitBase n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgIono n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgLog n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgM25FlashWriteStatus n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgMaskSatellite n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgNapDeviceDnaReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgNapDeviceDnaResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgNdbEvent n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgNetworkStateReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgNetworkStateResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgObs n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgObsDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgObsDepB n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgObsDepC n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgPosEcef n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgPosEcefDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgPosLlh n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgPosLlhDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgPrintDep n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgReset n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgResetDep n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgResetFilters n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSetTime n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsReadByIndexDone n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsReadByIndexReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsReadByIndexResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsReadReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsReadResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsRegister n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsSave n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSettingsWrite n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSpecan n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgStartup n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgStmFlashLockSector n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgStmFlashUnlockSector n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgStmUniqueIdReq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgStmUniqueIdResp n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgSvConfigurationGps n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgThreadState n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTrackingIq n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTrackingState n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTrackingStateDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTrackingStateDepB n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTrackingStateDetailed n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgTweet n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgUartState n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgUartStateDepa n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgUserData n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgUtcTime n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgVelEcef n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgVelEcefDepA n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgVelNed n m) = toJSON n <<>> toJSON m
+  toJSON (SBPMsgVelNedDepA n m) = toJSON n <<>> toJSON m
   toJSON (SBPMsgBadCrc m) = toJSON m
   toJSON (SBPMsgUnknown m) = toJSON m
 
diff --git a/src/SwiftNav/SBP/Navigation.hs b/src/SwiftNav/SBP/Navigation.hs
--- a/src/SwiftNav/SBP/Navigation.hs
+++ b/src/SwiftNav/SBP/Navigation.hs
@@ -21,12 +21,13 @@
 -- provided, well-surveyed base station position (if available) and the RTK
 -- solution in tandem.
 
-module SwiftNav.SBP.Navigation where
+module SwiftNav.SBP.Navigation
+  ( module SwiftNav.SBP.Navigation
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -35,7 +36,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -79,10 +80,8 @@
     putWord32le $ fromIntegral _msgGpsTime_ns_residual
     putWord8 _msgGpsTime_flags
 
-$(deriveSBP 'msgGpsTime ''MsgGpsTime)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgGpsTime_" . P.stripPrefix "_msgGpsTime_"}
-             ''MsgGpsTime)
+$(makeSBP 'msgGpsTime ''MsgGpsTime)
+$(makeJSON "_msgGpsTime_" ''MsgGpsTime)
 $(makeLenses ''MsgGpsTime)
 
 msgUtcTime :: Word16
@@ -138,10 +137,8 @@
     putWord8 _msgUtcTime_seconds
     putWord32le _msgUtcTime_ns
 
-$(deriveSBP 'msgUtcTime ''MsgUtcTime)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgUtcTime_" . P.stripPrefix "_msgUtcTime_"}
-             ''MsgUtcTime)
+$(makeSBP 'msgUtcTime ''MsgUtcTime)
+$(makeJSON "_msgUtcTime_" ''MsgUtcTime)
 $(makeLenses ''MsgUtcTime)
 
 msgDops :: Word16
@@ -190,10 +187,8 @@
     putWord16le _msgDops_vdop
     putWord8 _msgDops_flags
 
-$(deriveSBP 'msgDops ''MsgDops)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgDops_" . P.stripPrefix "_msgDops_"}
-             ''MsgDops)
+$(makeSBP 'msgDops ''MsgDops)
+$(makeJSON "_msgDops_" ''MsgDops)
 $(makeLenses ''MsgDops)
 
 msgPosEcef :: Word16
@@ -245,10 +240,8 @@
     putWord8 _msgPosEcef_n_sats
     putWord8 _msgPosEcef_flags
 
-$(deriveSBP 'msgPosEcef ''MsgPosEcef)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgPosEcef_" . P.stripPrefix "_msgPosEcef_"}
-             ''MsgPosEcef)
+$(makeSBP 'msgPosEcef ''MsgPosEcef)
+$(makeJSON "_msgPosEcef_" ''MsgPosEcef)
 $(makeLenses ''MsgPosEcef)
 
 msgPosLlh :: Word16
@@ -304,10 +297,8 @@
     putWord8 _msgPosLlh_n_sats
     putWord8 _msgPosLlh_flags
 
-$(deriveSBP 'msgPosLlh ''MsgPosLlh)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgPosLlh_" . P.stripPrefix "_msgPosLlh_"}
-             ''MsgPosLlh)
+$(makeSBP 'msgPosLlh ''MsgPosLlh)
+$(makeJSON "_msgPosLlh_" ''MsgPosLlh)
 $(makeLenses ''MsgPosLlh)
 
 msgBaselineEcef :: Word16
@@ -356,10 +347,8 @@
     putWord8 _msgBaselineEcef_n_sats
     putWord8 _msgBaselineEcef_flags
 
-$(deriveSBP 'msgBaselineEcef ''MsgBaselineEcef)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineEcef_" . P.stripPrefix "_msgBaselineEcef_"}
-             ''MsgBaselineEcef)
+$(makeSBP 'msgBaselineEcef ''MsgBaselineEcef)
+$(makeJSON "_msgBaselineEcef_" ''MsgBaselineEcef)
 $(makeLenses ''MsgBaselineEcef)
 
 msgBaselineNed :: Word16
@@ -414,10 +403,8 @@
     putWord8 _msgBaselineNed_n_sats
     putWord8 _msgBaselineNed_flags
 
-$(deriveSBP 'msgBaselineNed ''MsgBaselineNed)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineNed_" . P.stripPrefix "_msgBaselineNed_"}
-             ''MsgBaselineNed)
+$(makeSBP 'msgBaselineNed ''MsgBaselineNed)
+$(makeJSON "_msgBaselineNed_" ''MsgBaselineNed)
 $(makeLenses ''MsgBaselineNed)
 
 msgVelEcef :: Word16
@@ -465,10 +452,8 @@
     putWord8 _msgVelEcef_n_sats
     putWord8 _msgVelEcef_flags
 
-$(deriveSBP 'msgVelEcef ''MsgVelEcef)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgVelEcef_" . P.stripPrefix "_msgVelEcef_"}
-             ''MsgVelEcef)
+$(makeSBP 'msgVelEcef ''MsgVelEcef)
+$(makeJSON "_msgVelEcef_" ''MsgVelEcef)
 $(makeLenses ''MsgVelEcef)
 
 msgVelNed :: Word16
@@ -521,10 +506,8 @@
     putWord8 _msgVelNed_n_sats
     putWord8 _msgVelNed_flags
 
-$(deriveSBP 'msgVelNed ''MsgVelNed)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgVelNed_" . P.stripPrefix "_msgVelNed_"}
-             ''MsgVelNed)
+$(makeSBP 'msgVelNed ''MsgVelNed)
+$(makeJSON "_msgVelNed_" ''MsgVelNed)
 $(makeLenses ''MsgVelNed)
 
 msgBaselineHeading :: Word16
@@ -561,10 +544,8 @@
     putWord8 _msgBaselineHeading_n_sats
     putWord8 _msgBaselineHeading_flags
 
-$(deriveSBP 'msgBaselineHeading ''MsgBaselineHeading)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineHeading_" . P.stripPrefix "_msgBaselineHeading_"}
-             ''MsgBaselineHeading)
+$(makeSBP 'msgBaselineHeading ''MsgBaselineHeading)
+$(makeJSON "_msgBaselineHeading_" ''MsgBaselineHeading)
 $(makeLenses ''MsgBaselineHeading)
 
 msgAgeCorrections :: Word16
@@ -591,10 +572,8 @@
     putWord32le _msgAgeCorrections_tow
     putWord16le _msgAgeCorrections_age
 
-$(deriveSBP 'msgAgeCorrections ''MsgAgeCorrections)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAgeCorrections_" . P.stripPrefix "_msgAgeCorrections_"}
-             ''MsgAgeCorrections)
+$(makeSBP 'msgAgeCorrections ''MsgAgeCorrections)
+$(makeJSON "_msgAgeCorrections_" ''MsgAgeCorrections)
 $(makeLenses ''MsgAgeCorrections)
 
 msgGpsTimeDepA :: Word16
@@ -637,10 +616,8 @@
     putWord32le $ fromIntegral _msgGpsTimeDepA_ns_residual
     putWord8 _msgGpsTimeDepA_flags
 
-$(deriveSBP 'msgGpsTimeDepA ''MsgGpsTimeDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgGpsTimeDepA_" . P.stripPrefix "_msgGpsTimeDepA_"}
-             ''MsgGpsTimeDepA)
+$(makeSBP 'msgGpsTimeDepA ''MsgGpsTimeDepA)
+$(makeJSON "_msgGpsTimeDepA_" ''MsgGpsTimeDepA)
 $(makeLenses ''MsgGpsTimeDepA)
 
 msgDopsDepA :: Word16
@@ -683,10 +660,8 @@
     putWord16le _msgDopsDepA_hdop
     putWord16le _msgDopsDepA_vdop
 
-$(deriveSBP 'msgDopsDepA ''MsgDopsDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgDopsDepA_" . P.stripPrefix "_msgDopsDepA_"}
-             ''MsgDopsDepA)
+$(makeSBP 'msgDopsDepA ''MsgDopsDepA)
+$(makeJSON "_msgDopsDepA_" ''MsgDopsDepA)
 $(makeLenses ''MsgDopsDepA)
 
 msgPosEcefDepA :: Word16
@@ -738,10 +713,8 @@
     putWord8 _msgPosEcefDepA_n_sats
     putWord8 _msgPosEcefDepA_flags
 
-$(deriveSBP 'msgPosEcefDepA ''MsgPosEcefDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgPosEcefDepA_" . P.stripPrefix "_msgPosEcefDepA_"}
-             ''MsgPosEcefDepA)
+$(makeSBP 'msgPosEcefDepA ''MsgPosEcefDepA)
+$(makeJSON "_msgPosEcefDepA_" ''MsgPosEcefDepA)
 $(makeLenses ''MsgPosEcefDepA)
 
 msgPosLlhDepA :: Word16
@@ -797,10 +770,8 @@
     putWord8 _msgPosLlhDepA_n_sats
     putWord8 _msgPosLlhDepA_flags
 
-$(deriveSBP 'msgPosLlhDepA ''MsgPosLlhDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgPosLlhDepA_" . P.stripPrefix "_msgPosLlhDepA_"}
-             ''MsgPosLlhDepA)
+$(makeSBP 'msgPosLlhDepA ''MsgPosLlhDepA)
+$(makeJSON "_msgPosLlhDepA_" ''MsgPosLlhDepA)
 $(makeLenses ''MsgPosLlhDepA)
 
 msgBaselineEcefDepA :: Word16
@@ -849,10 +820,8 @@
     putWord8 _msgBaselineEcefDepA_n_sats
     putWord8 _msgBaselineEcefDepA_flags
 
-$(deriveSBP 'msgBaselineEcefDepA ''MsgBaselineEcefDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineEcefDepA_" . P.stripPrefix "_msgBaselineEcefDepA_"}
-             ''MsgBaselineEcefDepA)
+$(makeSBP 'msgBaselineEcefDepA ''MsgBaselineEcefDepA)
+$(makeJSON "_msgBaselineEcefDepA_" ''MsgBaselineEcefDepA)
 $(makeLenses ''MsgBaselineEcefDepA)
 
 msgBaselineNedDepA :: Word16
@@ -907,10 +876,8 @@
     putWord8 _msgBaselineNedDepA_n_sats
     putWord8 _msgBaselineNedDepA_flags
 
-$(deriveSBP 'msgBaselineNedDepA ''MsgBaselineNedDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineNedDepA_" . P.stripPrefix "_msgBaselineNedDepA_"}
-             ''MsgBaselineNedDepA)
+$(makeSBP 'msgBaselineNedDepA ''MsgBaselineNedDepA)
+$(makeJSON "_msgBaselineNedDepA_" ''MsgBaselineNedDepA)
 $(makeLenses ''MsgBaselineNedDepA)
 
 msgVelEcefDepA :: Word16
@@ -958,10 +925,8 @@
     putWord8 _msgVelEcefDepA_n_sats
     putWord8 _msgVelEcefDepA_flags
 
-$(deriveSBP 'msgVelEcefDepA ''MsgVelEcefDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgVelEcefDepA_" . P.stripPrefix "_msgVelEcefDepA_"}
-             ''MsgVelEcefDepA)
+$(makeSBP 'msgVelEcefDepA ''MsgVelEcefDepA)
+$(makeJSON "_msgVelEcefDepA_" ''MsgVelEcefDepA)
 $(makeLenses ''MsgVelEcefDepA)
 
 msgVelNedDepA :: Word16
@@ -1014,10 +979,8 @@
     putWord8 _msgVelNedDepA_n_sats
     putWord8 _msgVelNedDepA_flags
 
-$(deriveSBP 'msgVelNedDepA ''MsgVelNedDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgVelNedDepA_" . P.stripPrefix "_msgVelNedDepA_"}
-             ''MsgVelNedDepA)
+$(makeSBP 'msgVelNedDepA ''MsgVelNedDepA)
+$(makeJSON "_msgVelNedDepA_" ''MsgVelNedDepA)
 $(makeLenses ''MsgVelNedDepA)
 
 msgBaselineHeadingDepA :: Word16
@@ -1053,8 +1016,6 @@
     putWord8 _msgBaselineHeadingDepA_n_sats
     putWord8 _msgBaselineHeadingDepA_flags
 
-$(deriveSBP 'msgBaselineHeadingDepA ''MsgBaselineHeadingDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBaselineHeadingDepA_" . P.stripPrefix "_msgBaselineHeadingDepA_"}
-             ''MsgBaselineHeadingDepA)
+$(makeSBP 'msgBaselineHeadingDepA ''MsgBaselineHeadingDepA)
+$(makeJSON "_msgBaselineHeadingDepA_" ''MsgBaselineHeadingDepA)
 $(makeLenses ''MsgBaselineHeadingDepA)
diff --git a/src/SwiftNav/SBP/Ndb.hs b/src/SwiftNav/SBP/Ndb.hs
--- a/src/SwiftNav/SBP/Ndb.hs
+++ b/src/SwiftNav/SBP/Ndb.hs
@@ -13,12 +13,13 @@
 --
 -- Messages for logging NDB events.
 
-module SwiftNav.SBP.Ndb where
+module SwiftNav.SBP.Ndb
+  ( module SwiftNav.SBP.Ndb
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 import SwiftNav.SBP.Gnss
@@ -86,8 +87,6 @@
     put _msgNdbEvent_src_sid
     putWord16le _msgNdbEvent_original_sender
 
-$(deriveSBP 'msgNdbEvent ''MsgNdbEvent)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgNdbEvent_" . P.stripPrefix "_msgNdbEvent_"}
-             ''MsgNdbEvent)
+$(makeSBP 'msgNdbEvent ''MsgNdbEvent)
+$(makeJSON "_msgNdbEvent_" ''MsgNdbEvent)
 $(makeLenses ''MsgNdbEvent)
diff --git a/src/SwiftNav/SBP/Observation.hs b/src/SwiftNav/SBP/Observation.hs
--- a/src/SwiftNav/SBP/Observation.hs
+++ b/src/SwiftNav/SBP/Observation.hs
@@ -13,12 +13,13 @@
 --
 -- Satellite observation messages from the device.
 
-module SwiftNav.SBP.Observation where
+module SwiftNav.SBP.Observation
+  ( module SwiftNav.SBP.Observation
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 import SwiftNav.SBP.Gnss
@@ -52,8 +53,8 @@
   put ObservationHeader {..} = do
     put _observationHeader_t
     putWord8 _observationHeader_n_obs
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_observationHeader_" . P.stripPrefix "_observationHeader_"}
-             ''ObservationHeader)
+
+$(makeJSON "_observationHeader_" ''ObservationHeader)
 $(makeLenses ''ObservationHeader)
 
 -- | Doppler.
@@ -77,8 +78,8 @@
   put Doppler {..} = do
     putWord16le $ fromIntegral _doppler_i
     putWord8 _doppler_f
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_doppler_" . P.stripPrefix "_doppler_"}
-             ''Doppler)
+
+$(makeJSON "_doppler_" ''Doppler)
 $(makeLenses ''Doppler)
 
 -- | PackedObsContent.
@@ -129,8 +130,8 @@
     putWord8 _packedObsContent_lock
     putWord8 _packedObsContent_flags
     put _packedObsContent_sid
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_packedObsContent_" . P.stripPrefix "_packedObsContent_"}
-             ''PackedObsContent)
+
+$(makeJSON "_packedObsContent_" ''PackedObsContent)
 $(makeLenses ''PackedObsContent)
 
 msgObs :: Word16
@@ -161,10 +162,8 @@
     put _msgObs_header
     mapM_ put _msgObs_obs
 
-$(deriveSBP 'msgObs ''MsgObs)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgObs_" . P.stripPrefix "_msgObs_"}
-             ''MsgObs)
+$(makeSBP 'msgObs ''MsgObs)
+$(makeJSON "_msgObs_" ''MsgObs)
 $(makeLenses ''MsgObs)
 
 msgBasePosLlh :: Word16
@@ -197,10 +196,8 @@
     putFloat64le _msgBasePosLlh_lon
     putFloat64le _msgBasePosLlh_height
 
-$(deriveSBP 'msgBasePosLlh ''MsgBasePosLlh)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBasePosLlh_" . P.stripPrefix "_msgBasePosLlh_"}
-             ''MsgBasePosLlh)
+$(makeSBP 'msgBasePosLlh ''MsgBasePosLlh)
+$(makeJSON "_msgBasePosLlh_" ''MsgBasePosLlh)
 $(makeLenses ''MsgBasePosLlh)
 
 msgBasePosEcef :: Word16
@@ -234,10 +231,8 @@
     putFloat64le _msgBasePosEcef_y
     putFloat64le _msgBasePosEcef_z
 
-$(deriveSBP 'msgBasePosEcef ''MsgBasePosEcef)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgBasePosEcef_" . P.stripPrefix "_msgBasePosEcef_"}
-             ''MsgBasePosEcef)
+$(makeSBP 'msgBasePosEcef ''MsgBasePosEcef)
+$(makeJSON "_msgBasePosEcef_" ''MsgBasePosEcef)
 $(makeLenses ''MsgBasePosEcef)
 
 data EphemerisCommonContent = EphemerisCommonContent
@@ -273,8 +268,8 @@
     putWord32le _ephemerisCommonContent_fit_interval
     putWord8 _ephemerisCommonContent_valid
     putWord8 _ephemerisCommonContent_health_bits
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_ephemerisCommonContent_" . P.stripPrefix "_ephemerisCommonContent_"}
-             ''EphemerisCommonContent)
+
+$(makeJSON "_ephemerisCommonContent_" ''EphemerisCommonContent)
 $(makeLenses ''EphemerisCommonContent)
 
 data EphemerisCommonContentDepA = EphemerisCommonContentDepA
@@ -310,8 +305,8 @@
     putWord32le _ephemerisCommonContentDepA_fit_interval
     putWord8 _ephemerisCommonContentDepA_valid
     putWord8 _ephemerisCommonContentDepA_health_bits
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_ephemerisCommonContentDepA_" . P.stripPrefix "_ephemerisCommonContentDepA_"}
-             ''EphemerisCommonContentDepA)
+
+$(makeJSON "_ephemerisCommonContentDepA_" ''EphemerisCommonContentDepA)
 $(makeLenses ''EphemerisCommonContentDepA)
 
 msgEphemerisGpsDepE :: Word16
@@ -428,10 +423,8 @@
     putWord8 _msgEphemerisGpsDepE_iode
     putWord16le _msgEphemerisGpsDepE_iodc
 
-$(deriveSBP 'msgEphemerisGpsDepE ''MsgEphemerisGpsDepE)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGpsDepE_" . P.stripPrefix "_msgEphemerisGpsDepE_"}
-             ''MsgEphemerisGpsDepE)
+$(makeSBP 'msgEphemerisGpsDepE ''MsgEphemerisGpsDepE)
+$(makeJSON "_msgEphemerisGpsDepE_" ''MsgEphemerisGpsDepE)
 $(makeLenses ''MsgEphemerisGpsDepE)
 
 msgEphemerisGps :: Word16
@@ -548,10 +541,8 @@
     putWord8 _msgEphemerisGps_iode
     putWord16le _msgEphemerisGps_iodc
 
-$(deriveSBP 'msgEphemerisGps ''MsgEphemerisGps)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGps_" . P.stripPrefix "_msgEphemerisGps_"}
-             ''MsgEphemerisGps)
+$(makeSBP 'msgEphemerisGps ''MsgEphemerisGps)
+$(makeJSON "_msgEphemerisGps_" ''MsgEphemerisGps)
 $(makeLenses ''MsgEphemerisGps)
 
 msgEphemerisSbasDepA :: Word16
@@ -590,10 +581,8 @@
     putFloat64le _msgEphemerisSbasDepA_a_gf0
     putFloat64le _msgEphemerisSbasDepA_a_gf1
 
-$(deriveSBP 'msgEphemerisSbasDepA ''MsgEphemerisSbasDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisSbasDepA_" . P.stripPrefix "_msgEphemerisSbasDepA_"}
-             ''MsgEphemerisSbasDepA)
+$(makeSBP 'msgEphemerisSbasDepA ''MsgEphemerisSbasDepA)
+$(makeJSON "_msgEphemerisSbasDepA_" ''MsgEphemerisSbasDepA)
 $(makeLenses ''MsgEphemerisSbasDepA)
 
 msgEphemerisGloDepA :: Word16
@@ -638,10 +627,8 @@
     mapM_ putFloat64le _msgEphemerisGloDepA_vel
     mapM_ putFloat64le _msgEphemerisGloDepA_acc
 
-$(deriveSBP 'msgEphemerisGloDepA ''MsgEphemerisGloDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGloDepA_" . P.stripPrefix "_msgEphemerisGloDepA_"}
-             ''MsgEphemerisGloDepA)
+$(makeSBP 'msgEphemerisGloDepA ''MsgEphemerisGloDepA)
+$(makeJSON "_msgEphemerisGloDepA_" ''MsgEphemerisGloDepA)
 $(makeLenses ''MsgEphemerisGloDepA)
 
 msgEphemerisSbas :: Word16
@@ -680,10 +667,8 @@
     putFloat64le _msgEphemerisSbas_a_gf0
     putFloat64le _msgEphemerisSbas_a_gf1
 
-$(deriveSBP 'msgEphemerisSbas ''MsgEphemerisSbas)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisSbas_" . P.stripPrefix "_msgEphemerisSbas_"}
-             ''MsgEphemerisSbas)
+$(makeSBP 'msgEphemerisSbas ''MsgEphemerisSbas)
+$(makeJSON "_msgEphemerisSbas_" ''MsgEphemerisSbas)
 $(makeLenses ''MsgEphemerisSbas)
 
 msgEphemerisGloDepB :: Word16
@@ -728,10 +713,8 @@
     mapM_ putFloat64le _msgEphemerisGloDepB_vel
     mapM_ putFloat64le _msgEphemerisGloDepB_acc
 
-$(deriveSBP 'msgEphemerisGloDepB ''MsgEphemerisGloDepB)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGloDepB_" . P.stripPrefix "_msgEphemerisGloDepB_"}
-             ''MsgEphemerisGloDepB)
+$(makeSBP 'msgEphemerisGloDepB ''MsgEphemerisGloDepB)
+$(makeJSON "_msgEphemerisGloDepB_" ''MsgEphemerisGloDepB)
 $(makeLenses ''MsgEphemerisGloDepB)
 
 msgEphemerisGloDepC :: Word16
@@ -784,10 +767,8 @@
     mapM_ putFloat64le _msgEphemerisGloDepC_acc
     putWord8 _msgEphemerisGloDepC_fcn
 
-$(deriveSBP 'msgEphemerisGloDepC ''MsgEphemerisGloDepC)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGloDepC_" . P.stripPrefix "_msgEphemerisGloDepC_"}
-             ''MsgEphemerisGloDepC)
+$(makeSBP 'msgEphemerisGloDepC ''MsgEphemerisGloDepC)
+$(makeJSON "_msgEphemerisGloDepC_" ''MsgEphemerisGloDepC)
 $(makeLenses ''MsgEphemerisGloDepC)
 
 msgEphemerisGlo :: Word16
@@ -844,10 +825,8 @@
     putWord8 _msgEphemerisGlo_fcn
     putWord8 _msgEphemerisGlo_iod
 
-$(deriveSBP 'msgEphemerisGlo ''MsgEphemerisGlo)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisGlo_" . P.stripPrefix "_msgEphemerisGlo_"}
-             ''MsgEphemerisGlo)
+$(makeSBP 'msgEphemerisGlo ''MsgEphemerisGlo)
+$(makeJSON "_msgEphemerisGlo_" ''MsgEphemerisGlo)
 $(makeLenses ''MsgEphemerisGlo)
 
 msgEphemerisDepD :: Word16
@@ -988,10 +967,8 @@
     putWord16le _msgEphemerisDepD_iodc
     putWord32le _msgEphemerisDepD_reserved
 
-$(deriveSBP 'msgEphemerisDepD ''MsgEphemerisDepD)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisDepD_" . P.stripPrefix "_msgEphemerisDepD_"}
-             ''MsgEphemerisDepD)
+$(makeSBP 'msgEphemerisDepD ''MsgEphemerisDepD)
+$(makeJSON "_msgEphemerisDepD_" ''MsgEphemerisDepD)
 $(makeLenses ''MsgEphemerisDepD)
 
 msgEphemerisDepA :: Word16
@@ -1117,10 +1094,8 @@
     putWord8 _msgEphemerisDepA_healthy
     putWord8 _msgEphemerisDepA_prn
 
-$(deriveSBP 'msgEphemerisDepA ''MsgEphemerisDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisDepA_" . P.stripPrefix "_msgEphemerisDepA_"}
-             ''MsgEphemerisDepA)
+$(makeSBP 'msgEphemerisDepA ''MsgEphemerisDepA)
+$(makeJSON "_msgEphemerisDepA_" ''MsgEphemerisDepA)
 $(makeLenses ''MsgEphemerisDepA)
 
 msgEphemerisDepB :: Word16
@@ -1250,10 +1225,8 @@
     putWord8 _msgEphemerisDepB_prn
     putWord8 _msgEphemerisDepB_iode
 
-$(deriveSBP 'msgEphemerisDepB ''MsgEphemerisDepB)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisDepB_" . P.stripPrefix "_msgEphemerisDepB_"}
-             ''MsgEphemerisDepB)
+$(makeSBP 'msgEphemerisDepB ''MsgEphemerisDepB)
+$(makeJSON "_msgEphemerisDepB_" ''MsgEphemerisDepB)
 $(makeLenses ''MsgEphemerisDepB)
 
 msgEphemerisDepC :: Word16
@@ -1394,10 +1367,8 @@
     putWord16le _msgEphemerisDepC_iodc
     putWord32le _msgEphemerisDepC_reserved
 
-$(deriveSBP 'msgEphemerisDepC ''MsgEphemerisDepC)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgEphemerisDepC_" . P.stripPrefix "_msgEphemerisDepC_"}
-             ''MsgEphemerisDepC)
+$(makeSBP 'msgEphemerisDepC ''MsgEphemerisDepC)
+$(makeJSON "_msgEphemerisDepC_" ''MsgEphemerisDepC)
 $(makeLenses ''MsgEphemerisDepC)
 
 -- | ObservationHeaderDep.
@@ -1420,8 +1391,8 @@
   put ObservationHeaderDep {..} = do
     put _observationHeaderDep_t
     putWord8 _observationHeaderDep_n_obs
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_observationHeaderDep_" . P.stripPrefix "_observationHeaderDep_"}
-             ''ObservationHeaderDep)
+
+$(makeJSON "_observationHeaderDep_" ''ObservationHeaderDep)
 $(makeLenses ''ObservationHeaderDep)
 
 -- | CarrierPhaseDepA.
@@ -1446,8 +1417,8 @@
   put CarrierPhaseDepA {..} = do
     putWord32le $ fromIntegral _carrierPhaseDepA_i
     putWord8 _carrierPhaseDepA_f
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_carrierPhaseDepA_" . P.stripPrefix "_carrierPhaseDepA_"}
-             ''CarrierPhaseDepA)
+
+$(makeJSON "_carrierPhaseDepA_" ''CarrierPhaseDepA)
 $(makeLenses ''CarrierPhaseDepA)
 
 -- | PackedObsContentDepA.
@@ -1483,8 +1454,8 @@
     putWord8 _packedObsContentDepA_cn0
     putWord16le _packedObsContentDepA_lock
     putWord8 _packedObsContentDepA_prn
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_packedObsContentDepA_" . P.stripPrefix "_packedObsContentDepA_"}
-             ''PackedObsContentDepA)
+
+$(makeJSON "_packedObsContentDepA_" ''PackedObsContentDepA)
 $(makeLenses ''PackedObsContentDepA)
 
 -- | PackedObsContentDepB.
@@ -1521,8 +1492,8 @@
     putWord8 _packedObsContentDepB_cn0
     putWord16le _packedObsContentDepB_lock
     put _packedObsContentDepB_sid
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_packedObsContentDepB_" . P.stripPrefix "_packedObsContentDepB_"}
-             ''PackedObsContentDepB)
+
+$(makeJSON "_packedObsContentDepB_" ''PackedObsContentDepB)
 $(makeLenses ''PackedObsContentDepB)
 
 -- | PackedObsContentDepC.
@@ -1560,8 +1531,8 @@
     putWord8 _packedObsContentDepC_cn0
     putWord16le _packedObsContentDepC_lock
     put _packedObsContentDepC_sid
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_packedObsContentDepC_" . P.stripPrefix "_packedObsContentDepC_"}
-             ''PackedObsContentDepC)
+
+$(makeJSON "_packedObsContentDepC_" ''PackedObsContentDepC)
 $(makeLenses ''PackedObsContentDepC)
 
 msgObsDepA :: Word16
@@ -1587,10 +1558,8 @@
     put _msgObsDepA_header
     mapM_ put _msgObsDepA_obs
 
-$(deriveSBP 'msgObsDepA ''MsgObsDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgObsDepA_" . P.stripPrefix "_msgObsDepA_"}
-             ''MsgObsDepA)
+$(makeSBP 'msgObsDepA ''MsgObsDepA)
+$(makeJSON "_msgObsDepA_" ''MsgObsDepA)
 $(makeLenses ''MsgObsDepA)
 
 msgObsDepB :: Word16
@@ -1619,10 +1588,8 @@
     put _msgObsDepB_header
     mapM_ put _msgObsDepB_obs
 
-$(deriveSBP 'msgObsDepB ''MsgObsDepB)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgObsDepB_" . P.stripPrefix "_msgObsDepB_"}
-             ''MsgObsDepB)
+$(makeSBP 'msgObsDepB ''MsgObsDepB)
+$(makeJSON "_msgObsDepB_" ''MsgObsDepB)
 $(makeLenses ''MsgObsDepB)
 
 msgObsDepC :: Word16
@@ -1653,10 +1620,8 @@
     put _msgObsDepC_header
     mapM_ put _msgObsDepC_obs
 
-$(deriveSBP 'msgObsDepC ''MsgObsDepC)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgObsDepC_" . P.stripPrefix "_msgObsDepC_"}
-             ''MsgObsDepC)
+$(makeSBP 'msgObsDepC ''MsgObsDepC)
+$(makeJSON "_msgObsDepC_" ''MsgObsDepC)
 $(makeLenses ''MsgObsDepC)
 
 msgIono :: Word16
@@ -1704,10 +1669,8 @@
     putFloat64le _msgIono_b2
     putFloat64le _msgIono_b3
 
-$(deriveSBP 'msgIono ''MsgIono)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgIono_" . P.stripPrefix "_msgIono_"}
-             ''MsgIono)
+$(makeSBP 'msgIono ''MsgIono)
+$(makeJSON "_msgIono_" ''MsgIono)
 $(makeLenses ''MsgIono)
 
 msgSvConfigurationGps :: Word16
@@ -1733,10 +1696,8 @@
     put _msgSvConfigurationGps_t_nmct
     putWord32le _msgSvConfigurationGps_l2c_mask
 
-$(deriveSBP 'msgSvConfigurationGps ''MsgSvConfigurationGps)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSvConfigurationGps_" . P.stripPrefix "_msgSvConfigurationGps_"}
-             ''MsgSvConfigurationGps)
+$(makeSBP 'msgSvConfigurationGps ''MsgSvConfigurationGps)
+$(makeJSON "_msgSvConfigurationGps_" ''MsgSvConfigurationGps)
 $(makeLenses ''MsgSvConfigurationGps)
 
 msgGroupDelayDepA :: Word16
@@ -1776,10 +1737,8 @@
     putWord16le $ fromIntegral _msgGroupDelayDepA_isc_l1ca
     putWord16le $ fromIntegral _msgGroupDelayDepA_isc_l2c
 
-$(deriveSBP 'msgGroupDelayDepA ''MsgGroupDelayDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgGroupDelayDepA_" . P.stripPrefix "_msgGroupDelayDepA_"}
-             ''MsgGroupDelayDepA)
+$(makeSBP 'msgGroupDelayDepA ''MsgGroupDelayDepA)
+$(makeJSON "_msgGroupDelayDepA_" ''MsgGroupDelayDepA)
 $(makeLenses ''MsgGroupDelayDepA)
 
 msgGroupDelay :: Word16
@@ -1819,10 +1778,8 @@
     putWord16le $ fromIntegral _msgGroupDelay_isc_l1ca
     putWord16le $ fromIntegral _msgGroupDelay_isc_l2c
 
-$(deriveSBP 'msgGroupDelay ''MsgGroupDelay)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgGroupDelay_" . P.stripPrefix "_msgGroupDelay_"}
-             ''MsgGroupDelay)
+$(makeSBP 'msgGroupDelay ''MsgGroupDelay)
+$(makeJSON "_msgGroupDelay_" ''MsgGroupDelay)
 $(makeLenses ''MsgGroupDelay)
 
 data AlmanacCommonContent = AlmanacCommonContent
@@ -1866,8 +1823,8 @@
     putWord32le _almanacCommonContent_fit_interval
     putWord8 _almanacCommonContent_valid
     putWord8 _almanacCommonContent_health_bits
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_almanacCommonContent_" . P.stripPrefix "_almanacCommonContent_"}
-             ''AlmanacCommonContent)
+
+$(makeJSON "_almanacCommonContent_" ''AlmanacCommonContent)
 $(makeLenses ''AlmanacCommonContent)
 
 msgAlmanacGps :: Word16
@@ -1928,10 +1885,8 @@
     putFloat64le _msgAlmanacGps_af0
     putFloat64le _msgAlmanacGps_af1
 
-$(deriveSBP 'msgAlmanacGps ''MsgAlmanacGps)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAlmanacGps_" . P.stripPrefix "_msgAlmanacGps_"}
-             ''MsgAlmanacGps)
+$(makeSBP 'msgAlmanacGps ''MsgAlmanacGps)
+$(makeJSON "_msgAlmanacGps_" ''MsgAlmanacGps)
 $(makeLenses ''MsgAlmanacGps)
 
 msgAlmanacGlo :: Word16
@@ -1985,10 +1940,8 @@
     putFloat64le _msgAlmanacGlo_epsilon
     putFloat64le _msgAlmanacGlo_omega
 
-$(deriveSBP 'msgAlmanacGlo ''MsgAlmanacGlo)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAlmanacGlo_" . P.stripPrefix "_msgAlmanacGlo_"}
-             ''MsgAlmanacGlo)
+$(makeSBP 'msgAlmanacGlo ''MsgAlmanacGlo)
+$(makeJSON "_msgAlmanacGlo_" ''MsgAlmanacGlo)
 $(makeLenses ''MsgAlmanacGlo)
 
 msgFcnsGlo :: Word16
@@ -2022,8 +1975,6 @@
     putWord32le _msgFcnsGlo_tow_ms
     mapM_ putWord8 _msgFcnsGlo_fcns
 
-$(deriveSBP 'msgFcnsGlo ''MsgFcnsGlo)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgFcnsGlo_" . P.stripPrefix "_msgFcnsGlo_"}
-             ''MsgFcnsGlo)
+$(makeSBP 'msgFcnsGlo ''MsgFcnsGlo)
+$(makeJSON "_msgFcnsGlo_" ''MsgFcnsGlo)
 $(makeLenses ''MsgFcnsGlo)
diff --git a/src/SwiftNav/SBP/Piksi.hs b/src/SwiftNav/SBP/Piksi.hs
--- a/src/SwiftNav/SBP/Piksi.hs
+++ b/src/SwiftNav/SBP/Piksi.hs
@@ -15,12 +15,13 @@
 -- L1 receiver, including a variety of legacy messages that may no longer be
 -- used.
 
-module SwiftNav.SBP.Piksi where
+module SwiftNav.SBP.Piksi
+  ( module SwiftNav.SBP.Piksi
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -29,7 +30,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 import SwiftNav.SBP.Gnss
@@ -50,11 +51,8 @@
 
   put MsgAlmanac =
     return ()
-
-$(deriveSBP 'msgAlmanac ''MsgAlmanac)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgAlmanac_" . P.stripPrefix "_msgAlmanac_"}
-             ''MsgAlmanac)
+$(makeSBP 'msgAlmanac ''MsgAlmanac)
+$(makeJSON "_msgAlmanac_" ''MsgAlmanac)
 $(makeLenses ''MsgAlmanac)
 
 msgSetTime :: Word16
@@ -73,11 +71,8 @@
 
   put MsgSetTime =
     return ()
-
-$(deriveSBP 'msgSetTime ''MsgSetTime)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSetTime_" . P.stripPrefix "_msgSetTime_"}
-             ''MsgSetTime)
+$(makeSBP 'msgSetTime ''MsgSetTime)
+$(makeJSON "_msgSetTime_" ''MsgSetTime)
 $(makeLenses ''MsgSetTime)
 
 msgReset :: Word16
@@ -99,10 +94,8 @@
   put MsgReset {..} = do
     putWord32le _msgReset_flags
 
-$(deriveSBP 'msgReset ''MsgReset)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgReset_" . P.stripPrefix "_msgReset_"}
-             ''MsgReset)
+$(makeSBP 'msgReset ''MsgReset)
+$(makeJSON "_msgReset_" ''MsgReset)
 $(makeLenses ''MsgReset)
 
 msgResetDep :: Word16
@@ -120,11 +113,8 @@
 
   put MsgResetDep =
     return ()
-
-$(deriveSBP 'msgResetDep ''MsgResetDep)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgResetDep_" . P.stripPrefix "_msgResetDep_"}
-             ''MsgResetDep)
+$(makeSBP 'msgResetDep ''MsgResetDep)
+$(makeJSON "_msgResetDep_" ''MsgResetDep)
 $(makeLenses ''MsgResetDep)
 
 msgCwResults :: Word16
@@ -144,11 +134,8 @@
 
   put MsgCwResults =
     return ()
-
-$(deriveSBP 'msgCwResults ''MsgCwResults)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgCwResults_" . P.stripPrefix "_msgCwResults_"}
-             ''MsgCwResults)
+$(makeSBP 'msgCwResults ''MsgCwResults)
+$(makeJSON "_msgCwResults_" ''MsgCwResults)
 $(makeLenses ''MsgCwResults)
 
 msgCwStart :: Word16
@@ -168,11 +155,8 @@
 
   put MsgCwStart =
     return ()
-
-$(deriveSBP 'msgCwStart ''MsgCwStart)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgCwStart_" . P.stripPrefix "_msgCwStart_"}
-             ''MsgCwStart)
+$(makeSBP 'msgCwStart ''MsgCwStart)
+$(makeJSON "_msgCwStart_" ''MsgCwStart)
 $(makeLenses ''MsgCwStart)
 
 msgResetFilters :: Word16
@@ -195,10 +179,8 @@
   put MsgResetFilters {..} = do
     putWord8 _msgResetFilters_filter
 
-$(deriveSBP 'msgResetFilters ''MsgResetFilters)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgResetFilters_" . P.stripPrefix "_msgResetFilters_"}
-             ''MsgResetFilters)
+$(makeSBP 'msgResetFilters ''MsgResetFilters)
+$(makeJSON "_msgResetFilters_" ''MsgResetFilters)
 $(makeLenses ''MsgResetFilters)
 
 msgInitBase :: Word16
@@ -219,11 +201,8 @@
 
   put MsgInitBase =
     return ()
-
-$(deriveSBP 'msgInitBase ''MsgInitBase)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgInitBase_" . P.stripPrefix "_msgInitBase_"}
-             ''MsgInitBase)
+$(makeSBP 'msgInitBase ''MsgInitBase)
+$(makeJSON "_msgInitBase_" ''MsgInitBase)
 $(makeLenses ''MsgInitBase)
 
 msgThreadState :: Word16
@@ -256,10 +235,8 @@
     putWord16le _msgThreadState_cpu
     putWord32le _msgThreadState_stack_free
 
-$(deriveSBP 'msgThreadState ''MsgThreadState)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgThreadState_" . P.stripPrefix "_msgThreadState_"}
-             ''MsgThreadState)
+$(makeSBP 'msgThreadState ''MsgThreadState)
+$(makeJSON "_msgThreadState_" ''MsgThreadState)
 $(makeLenses ''MsgThreadState)
 
 -- | UARTChannel.
@@ -298,8 +275,8 @@
     putWord16le _uARTChannel_io_error_count
     putWord8 _uARTChannel_tx_buffer_level
     putWord8 _uARTChannel_rx_buffer_level
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_uARTChannel_" . P.stripPrefix "_uARTChannel_"}
-             ''UARTChannel)
+
+$(makeJSON "_uARTChannel_" ''UARTChannel)
 $(makeLenses ''UARTChannel)
 
 -- | Period.
@@ -333,8 +310,8 @@
     putWord32le $ fromIntegral _period_pmin
     putWord32le $ fromIntegral _period_pmax
     putWord32le $ fromIntegral _period_current
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_period_" . P.stripPrefix "_period_"}
-             ''Period)
+
+$(makeJSON "_period_" ''Period)
 $(makeLenses ''Period)
 
 -- | Latency.
@@ -367,8 +344,8 @@
     putWord32le $ fromIntegral _latency_lmin
     putWord32le $ fromIntegral _latency_lmax
     putWord32le $ fromIntegral _latency_current
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_latency_" . P.stripPrefix "_latency_"}
-             ''Latency)
+
+$(makeJSON "_latency_" ''Latency)
 $(makeLenses ''Latency)
 
 msgUartState :: Word16
@@ -413,10 +390,8 @@
     put _msgUartState_latency
     put _msgUartState_obs_period
 
-$(deriveSBP 'msgUartState ''MsgUartState)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgUartState_" . P.stripPrefix "_msgUartState_"}
-             ''MsgUartState)
+$(makeSBP 'msgUartState ''MsgUartState)
+$(makeJSON "_msgUartState_" ''MsgUartState)
 $(makeLenses ''MsgUartState)
 
 msgUartStateDepa :: Word16
@@ -450,10 +425,8 @@
     put _msgUartStateDepa_uart_ftdi
     put _msgUartStateDepa_latency
 
-$(deriveSBP 'msgUartStateDepa ''MsgUartStateDepa)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgUartStateDepa_" . P.stripPrefix "_msgUartStateDepa_"}
-             ''MsgUartStateDepa)
+$(makeSBP 'msgUartStateDepa ''MsgUartStateDepa)
+$(makeJSON "_msgUartStateDepa_" ''MsgUartStateDepa)
 $(makeLenses ''MsgUartStateDepa)
 
 msgIarState :: Word16
@@ -477,10 +450,8 @@
   put MsgIarState {..} = do
     putWord32le _msgIarState_num_hyps
 
-$(deriveSBP 'msgIarState ''MsgIarState)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgIarState_" . P.stripPrefix "_msgIarState_"}
-             ''MsgIarState)
+$(makeSBP 'msgIarState ''MsgIarState)
+$(makeJSON "_msgIarState_" ''MsgIarState)
 $(makeLenses ''MsgIarState)
 
 msgMaskSatellite :: Word16
@@ -507,10 +478,8 @@
     putWord8 _msgMaskSatellite_mask
     put _msgMaskSatellite_sid
 
-$(deriveSBP 'msgMaskSatellite ''MsgMaskSatellite)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgMaskSatellite_" . P.stripPrefix "_msgMaskSatellite_"}
-             ''MsgMaskSatellite)
+$(makeSBP 'msgMaskSatellite ''MsgMaskSatellite)
+$(makeJSON "_msgMaskSatellite_" ''MsgMaskSatellite)
 $(makeLenses ''MsgMaskSatellite)
 
 msgDeviceMonitor :: Word16
@@ -550,10 +519,8 @@
     putWord16le $ fromIntegral _msgDeviceMonitor_cpu_temperature
     putWord16le $ fromIntegral _msgDeviceMonitor_fe_temperature
 
-$(deriveSBP 'msgDeviceMonitor ''MsgDeviceMonitor)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgDeviceMonitor_" . P.stripPrefix "_msgDeviceMonitor_"}
-             ''MsgDeviceMonitor)
+$(makeSBP 'msgDeviceMonitor ''MsgDeviceMonitor)
+$(makeJSON "_msgDeviceMonitor_" ''MsgDeviceMonitor)
 $(makeLenses ''MsgDeviceMonitor)
 
 msgCommandReq :: Word16
@@ -580,10 +547,8 @@
     putWord32le _msgCommandReq_sequence
     putByteString $ encodeUtf8 _msgCommandReq_command
 
-$(deriveSBP 'msgCommandReq ''MsgCommandReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgCommandReq_" . P.stripPrefix "_msgCommandReq_"}
-             ''MsgCommandReq)
+$(makeSBP 'msgCommandReq ''MsgCommandReq)
+$(makeJSON "_msgCommandReq_" ''MsgCommandReq)
 $(makeLenses ''MsgCommandReq)
 
 msgCommandResp :: Word16
@@ -610,10 +575,8 @@
     putWord32le _msgCommandResp_sequence
     putWord32le $ fromIntegral _msgCommandResp_code
 
-$(deriveSBP 'msgCommandResp ''MsgCommandResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgCommandResp_" . P.stripPrefix "_msgCommandResp_"}
-             ''MsgCommandResp)
+$(makeSBP 'msgCommandResp ''MsgCommandResp)
+$(makeJSON "_msgCommandResp_" ''MsgCommandResp)
 $(makeLenses ''MsgCommandResp)
 
 msgCommandOutput :: Word16
@@ -641,10 +604,8 @@
     putWord32le _msgCommandOutput_sequence
     putByteString $ encodeUtf8 _msgCommandOutput_line
 
-$(deriveSBP 'msgCommandOutput ''MsgCommandOutput)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgCommandOutput_" . P.stripPrefix "_msgCommandOutput_"}
-             ''MsgCommandOutput)
+$(makeSBP 'msgCommandOutput ''MsgCommandOutput)
+$(makeJSON "_msgCommandOutput_" ''MsgCommandOutput)
 $(makeLenses ''MsgCommandOutput)
 
 msgNetworkStateReq :: Word16
@@ -663,11 +624,8 @@
 
   put MsgNetworkStateReq =
     return ()
-
-$(deriveSBP 'msgNetworkStateReq ''MsgNetworkStateReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgNetworkStateReq_" . P.stripPrefix "_msgNetworkStateReq_"}
-             ''MsgNetworkStateReq)
+$(makeSBP 'msgNetworkStateReq ''MsgNetworkStateReq)
+$(makeJSON "_msgNetworkStateReq_" ''MsgNetworkStateReq)
 $(makeLenses ''MsgNetworkStateReq)
 
 msgNetworkStateResp :: Word16
@@ -718,10 +676,8 @@
     putByteString $ encodeUtf8 _msgNetworkStateResp_interface_name
     putWord32le _msgNetworkStateResp_flags
 
-$(deriveSBP 'msgNetworkStateResp ''MsgNetworkStateResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgNetworkStateResp_" . P.stripPrefix "_msgNetworkStateResp_"}
-             ''MsgNetworkStateResp)
+$(makeSBP 'msgNetworkStateResp ''MsgNetworkStateResp)
+$(makeJSON "_msgNetworkStateResp_" ''MsgNetworkStateResp)
 $(makeLenses ''MsgNetworkStateResp)
 
 msgSpecan :: Word16
@@ -767,8 +723,6 @@
     putFloat32le _msgSpecan_amplitude_unit
     mapM_ putWord8 _msgSpecan_amplitude_value
 
-$(deriveSBP 'msgSpecan ''MsgSpecan)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSpecan_" . P.stripPrefix "_msgSpecan_"}
-             ''MsgSpecan)
+$(makeSBP 'msgSpecan ''MsgSpecan)
+$(makeJSON "_msgSpecan_" ''MsgSpecan)
 $(makeLenses ''MsgSpecan)
diff --git a/src/SwiftNav/SBP/Settings.hs b/src/SwiftNav/SBP/Settings.hs
--- a/src/SwiftNav/SBP/Settings.hs
+++ b/src/SwiftNav/SBP/Settings.hs
@@ -17,12 +17,13 @@
 -- descriptions of settings configurations and examples:  https://github.com
 -- /swift-nav/piksi\_firmware/blob/master/docs/settings.pdf
 
-module SwiftNav.SBP.Settings where
+module SwiftNav.SBP.Settings
+  ( module SwiftNav.SBP.Settings
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -31,7 +32,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -51,11 +52,8 @@
 
   put MsgSettingsSave =
     return ()
-
-$(deriveSBP 'msgSettingsSave ''MsgSettingsSave)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsSave_" . P.stripPrefix "_msgSettingsSave_"}
-             ''MsgSettingsSave)
+$(makeSBP 'msgSettingsSave ''MsgSettingsSave)
+$(makeJSON "_msgSettingsSave_" ''MsgSettingsSave)
 $(makeLenses ''MsgSettingsSave)
 
 msgSettingsWrite :: Word16
@@ -79,10 +77,8 @@
   put MsgSettingsWrite {..} = do
     putByteString $ encodeUtf8 _msgSettingsWrite_setting
 
-$(deriveSBP 'msgSettingsWrite ''MsgSettingsWrite)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsWrite_" . P.stripPrefix "_msgSettingsWrite_"}
-             ''MsgSettingsWrite)
+$(makeSBP 'msgSettingsWrite ''MsgSettingsWrite)
+$(makeJSON "_msgSettingsWrite_" ''MsgSettingsWrite)
 $(makeLenses ''MsgSettingsWrite)
 
 msgSettingsReadReq :: Word16
@@ -106,10 +102,8 @@
   put MsgSettingsReadReq {..} = do
     putByteString $ encodeUtf8 _msgSettingsReadReq_setting
 
-$(deriveSBP 'msgSettingsReadReq ''MsgSettingsReadReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsReadReq_" . P.stripPrefix "_msgSettingsReadReq_"}
-             ''MsgSettingsReadReq)
+$(makeSBP 'msgSettingsReadReq ''MsgSettingsReadReq)
+$(makeJSON "_msgSettingsReadReq_" ''MsgSettingsReadReq)
 $(makeLenses ''MsgSettingsReadReq)
 
 msgSettingsReadResp :: Word16
@@ -132,10 +126,8 @@
   put MsgSettingsReadResp {..} = do
     putByteString $ encodeUtf8 _msgSettingsReadResp_setting
 
-$(deriveSBP 'msgSettingsReadResp ''MsgSettingsReadResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsReadResp_" . P.stripPrefix "_msgSettingsReadResp_"}
-             ''MsgSettingsReadResp)
+$(makeSBP 'msgSettingsReadResp ''MsgSettingsReadResp)
+$(makeJSON "_msgSettingsReadResp_" ''MsgSettingsReadResp)
 $(makeLenses ''MsgSettingsReadResp)
 
 msgSettingsReadByIndexReq :: Word16
@@ -161,10 +153,8 @@
   put MsgSettingsReadByIndexReq {..} = do
     putWord16le _msgSettingsReadByIndexReq_index
 
-$(deriveSBP 'msgSettingsReadByIndexReq ''MsgSettingsReadByIndexReq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsReadByIndexReq_" . P.stripPrefix "_msgSettingsReadByIndexReq_"}
-             ''MsgSettingsReadByIndexReq)
+$(makeSBP 'msgSettingsReadByIndexReq ''MsgSettingsReadByIndexReq)
+$(makeJSON "_msgSettingsReadByIndexReq_" ''MsgSettingsReadByIndexReq)
 $(makeLenses ''MsgSettingsReadByIndexReq)
 
 msgSettingsReadByIndexResp :: Word16
@@ -194,10 +184,8 @@
     putWord16le _msgSettingsReadByIndexResp_index
     putByteString $ encodeUtf8 _msgSettingsReadByIndexResp_setting
 
-$(deriveSBP 'msgSettingsReadByIndexResp ''MsgSettingsReadByIndexResp)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsReadByIndexResp_" . P.stripPrefix "_msgSettingsReadByIndexResp_"}
-             ''MsgSettingsReadByIndexResp)
+$(makeSBP 'msgSettingsReadByIndexResp ''MsgSettingsReadByIndexResp)
+$(makeJSON "_msgSettingsReadByIndexResp_" ''MsgSettingsReadByIndexResp)
 $(makeLenses ''MsgSettingsReadByIndexResp)
 
 msgSettingsReadByIndexDone :: Word16
@@ -215,11 +203,8 @@
 
   put MsgSettingsReadByIndexDone =
     return ()
-
-$(deriveSBP 'msgSettingsReadByIndexDone ''MsgSettingsReadByIndexDone)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsReadByIndexDone_" . P.stripPrefix "_msgSettingsReadByIndexDone_"}
-             ''MsgSettingsReadByIndexDone)
+$(makeSBP 'msgSettingsReadByIndexDone ''MsgSettingsReadByIndexDone)
+$(makeJSON "_msgSettingsReadByIndexDone_" ''MsgSettingsReadByIndexDone)
 $(makeLenses ''MsgSettingsReadByIndexDone)
 
 msgSettingsRegister :: Word16
@@ -244,8 +229,6 @@
   put MsgSettingsRegister {..} = do
     putByteString $ encodeUtf8 _msgSettingsRegister_setting
 
-$(deriveSBP 'msgSettingsRegister ''MsgSettingsRegister)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgSettingsRegister_" . P.stripPrefix "_msgSettingsRegister_"}
-             ''MsgSettingsRegister)
+$(makeSBP 'msgSettingsRegister ''MsgSettingsRegister)
+$(makeJSON "_msgSettingsRegister_" ''MsgSettingsRegister)
 $(makeLenses ''MsgSettingsRegister)
diff --git a/src/SwiftNav/SBP/System.hs b/src/SwiftNav/SBP/System.hs
--- a/src/SwiftNav/SBP/System.hs
+++ b/src/SwiftNav/SBP/System.hs
@@ -13,12 +13,13 @@
 --
 -- Standardized system messages from Swift Navigation devices.
 
-module SwiftNav.SBP.System where
+module SwiftNav.SBP.System
+  ( module SwiftNav.SBP.System
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -60,10 +61,8 @@
     putWord8 _msgStartup_startup_type
     putWord16le _msgStartup_reserved
 
-$(deriveSBP 'msgStartup ''MsgStartup)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgStartup_" . P.stripPrefix "_msgStartup_"}
-             ''MsgStartup)
+$(makeSBP 'msgStartup ''MsgStartup)
+$(makeJSON "_msgStartup_" ''MsgStartup)
 $(makeLenses ''MsgStartup)
 
 msgDgnssStatus :: Word16
@@ -99,10 +98,8 @@
     putWord8 _msgDgnssStatus_num_signals
     putByteString $ encodeUtf8 _msgDgnssStatus_source
 
-$(deriveSBP 'msgDgnssStatus ''MsgDgnssStatus)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgDgnssStatus_" . P.stripPrefix "_msgDgnssStatus_"}
-             ''MsgDgnssStatus)
+$(makeSBP 'msgDgnssStatus ''MsgDgnssStatus)
+$(makeJSON "_msgDgnssStatus_" ''MsgDgnssStatus)
 $(makeLenses ''MsgDgnssStatus)
 
 msgHeartbeat :: Word16
@@ -130,8 +127,6 @@
   put MsgHeartbeat {..} = do
     putWord32le _msgHeartbeat_flags
 
-$(deriveSBP 'msgHeartbeat ''MsgHeartbeat)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgHeartbeat_" . P.stripPrefix "_msgHeartbeat_"}
-             ''MsgHeartbeat)
+$(makeSBP 'msgHeartbeat ''MsgHeartbeat)
+$(makeJSON "_msgHeartbeat_" ''MsgHeartbeat)
 $(makeLenses ''MsgHeartbeat)
diff --git a/src/SwiftNav/SBP/TH.hs b/src/SwiftNav/SBP/TH.hs
--- a/src/SwiftNav/SBP/TH.hs
+++ b/src/SwiftNav/SBP/TH.hs
@@ -1,6 +1,5 @@
-{-# OPTIONS_GHC -fno-warn-unused-imports #-}
-{-# LANGUAGE NoImplicitPrelude           #-}
-{-# LANGUAGE TemplateHaskell             #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TemplateHaskell   #-}
 
 -- |
 -- Module:      SwiftNav.SBP.TH
@@ -10,28 +9,36 @@
 -- Stability:   experimental
 -- Portability: portable
 --
--- Templated generation of SBP interfaces.
+-- Templated generation of SBP and JSON interfaces.
 
-module SwiftNav.SBP.TH where
+module SwiftNav.SBP.TH
+  ( makeSBP
+  , makeJSON
+  ) where
 
-import BasicPrelude
+import BasicPrelude         hiding (length)
 import Control.Lens
+import Data.Aeson.TH
 import Data.Binary
 import Data.ByteString
-import Data.ByteString.Lazy hiding (ByteString)
+import Data.ByteString.Lazy hiding (length)
 import Language.Haskell.TH
 import SwiftNav.SBP.Types
-import Control.Exception.Base (assert)
 
 -- | Derive ToSBP typeclass, given an SBP message type name and the
 -- name of the implemented type.
-deriveSBP :: Name -> Name -> Q [Dec]
-deriveSBP msgType name =
+makeSBP :: Name -> Name -> Q [Dec]
+makeSBP msgType name =
   [d|instance ToSBP $(conT name) where
        toSBP m senderID = encoded & msgSBPCrc .~ checkCrc encoded
          where
            payload = toStrict $ encode m
-           len' = Data.ByteString.length payload
-           len = assert (len' < 256) $ fromIntegral len'
+           len     = fromIntegral $ length payload
            encoded = Msg $(varE msgType) senderID len payload 0
     |]
+
+-- | Derive JSON stripping out prefixes of the implemented type.
+makeJSON :: String -> Name -> Q [Dec]
+makeJSON prefix = deriveJSON defaultOptions
+  { fieldLabelModifier = fromMaybe prefix . stripPrefix prefix
+  }
diff --git a/src/SwiftNav/SBP/Tracking.hs b/src/SwiftNav/SBP/Tracking.hs
--- a/src/SwiftNav/SBP/Tracking.hs
+++ b/src/SwiftNav/SBP/Tracking.hs
@@ -13,12 +13,13 @@
 --
 -- Satellite code and carrier-phase tracking messages from the device.
 
-module SwiftNav.SBP.Tracking where
+module SwiftNav.SBP.Tracking
+  ( module SwiftNav.SBP.Tracking
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 import SwiftNav.SBP.Gnss
@@ -138,10 +139,8 @@
     putWord8 _msgTrackingStateDetailed_pset_flags
     putWord8 _msgTrackingStateDetailed_misc_flags
 
-$(deriveSBP 'msgTrackingStateDetailed ''MsgTrackingStateDetailed)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTrackingStateDetailed_" . P.stripPrefix "_msgTrackingStateDetailed_"}
-             ''MsgTrackingStateDetailed)
+$(makeSBP 'msgTrackingStateDetailed ''MsgTrackingStateDetailed)
+$(makeJSON "_msgTrackingStateDetailed_" ''MsgTrackingStateDetailed)
 $(makeLenses ''MsgTrackingStateDetailed)
 
 -- | TrackingChannelState.
@@ -168,8 +167,8 @@
     put _trackingChannelState_sid
     putWord8 _trackingChannelState_fcn
     putWord8 _trackingChannelState_cn0
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_trackingChannelState_" . P.stripPrefix "_trackingChannelState_"}
-             ''TrackingChannelState)
+
+$(makeJSON "_trackingChannelState_" ''TrackingChannelState)
 $(makeLenses ''TrackingChannelState)
 
 msgTrackingState :: Word16
@@ -193,10 +192,8 @@
   put MsgTrackingState {..} = do
     mapM_ put _msgTrackingState_states
 
-$(deriveSBP 'msgTrackingState ''MsgTrackingState)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTrackingState_" . P.stripPrefix "_msgTrackingState_"}
-             ''MsgTrackingState)
+$(makeSBP 'msgTrackingState ''MsgTrackingState)
+$(makeJSON "_msgTrackingState_" ''MsgTrackingState)
 $(makeLenses ''MsgTrackingState)
 
 -- | TrackingChannelCorrelation.
@@ -218,8 +215,8 @@
   put TrackingChannelCorrelation {..} = do
     putWord32le $ fromIntegral _trackingChannelCorrelation_I
     putWord32le $ fromIntegral _trackingChannelCorrelation_Q
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_trackingChannelCorrelation_" . P.stripPrefix "_trackingChannelCorrelation_"}
-             ''TrackingChannelCorrelation)
+
+$(makeJSON "_trackingChannelCorrelation_" ''TrackingChannelCorrelation)
 $(makeLenses ''TrackingChannelCorrelation)
 
 msgTrackingIq :: Word16
@@ -250,10 +247,8 @@
     put _msgTrackingIq_sid
     mapM_ put _msgTrackingIq_corrs
 
-$(deriveSBP 'msgTrackingIq ''MsgTrackingIq)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTrackingIq_" . P.stripPrefix "_msgTrackingIq_"}
-             ''MsgTrackingIq)
+$(makeSBP 'msgTrackingIq ''MsgTrackingIq)
+$(makeJSON "_msgTrackingIq_" ''MsgTrackingIq)
 $(makeLenses ''MsgTrackingIq)
 
 -- | TrackingChannelStateDepA.
@@ -279,8 +274,8 @@
     putWord8 _trackingChannelStateDepA_state
     putWord8 _trackingChannelStateDepA_prn
     putFloat32le _trackingChannelStateDepA_cn0
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_trackingChannelStateDepA_" . P.stripPrefix "_trackingChannelStateDepA_"}
-             ''TrackingChannelStateDepA)
+
+$(makeJSON "_trackingChannelStateDepA_" ''TrackingChannelStateDepA)
 $(makeLenses ''TrackingChannelStateDepA)
 
 msgTrackingStateDepA :: Word16
@@ -302,10 +297,8 @@
   put MsgTrackingStateDepA {..} = do
     mapM_ put _msgTrackingStateDepA_states
 
-$(deriveSBP 'msgTrackingStateDepA ''MsgTrackingStateDepA)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTrackingStateDepA_" . P.stripPrefix "_msgTrackingStateDepA_"}
-             ''MsgTrackingStateDepA)
+$(makeSBP 'msgTrackingStateDepA ''MsgTrackingStateDepA)
+$(makeJSON "_msgTrackingStateDepA_" ''MsgTrackingStateDepA)
 $(makeLenses ''MsgTrackingStateDepA)
 
 -- | TrackingChannelStateDepB.
@@ -331,8 +324,8 @@
     putWord8 _trackingChannelStateDepB_state
     put _trackingChannelStateDepB_sid
     putFloat32le _trackingChannelStateDepB_cn0
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_trackingChannelStateDepB_" . P.stripPrefix "_trackingChannelStateDepB_"}
-             ''TrackingChannelStateDepB)
+
+$(makeJSON "_trackingChannelStateDepB_" ''TrackingChannelStateDepB)
 $(makeLenses ''TrackingChannelStateDepB)
 
 msgTrackingStateDepB :: Word16
@@ -354,8 +347,6 @@
   put MsgTrackingStateDepB {..} = do
     mapM_ put _msgTrackingStateDepB_states
 
-$(deriveSBP 'msgTrackingStateDepB ''MsgTrackingStateDepB)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgTrackingStateDepB_" . P.stripPrefix "_msgTrackingStateDepB_"}
-             ''MsgTrackingStateDepB)
+$(makeSBP 'msgTrackingStateDepB ''MsgTrackingStateDepB)
+$(makeJSON "_msgTrackingStateDepB_" ''MsgTrackingStateDepB)
 $(makeLenses ''MsgTrackingStateDepB)
diff --git a/src/SwiftNav/SBP/Types.hs b/src/SwiftNav/SBP/Types.hs
--- a/src/SwiftNav/SBP/Types.hs
+++ b/src/SwiftNav/SBP/Types.hs
@@ -13,8 +13,11 @@
 --
 -- Common SBP type requirements, containers, and serialization
 -- utilities.
+--
 
-module SwiftNav.SBP.Types where
+module SwiftNav.SBP.Types
+  ( module SwiftNav.SBP.Types
+  ) where
 
 import BasicPrelude            hiding (lookup)
 import Control.Lens            hiding ((.=))
@@ -24,14 +27,16 @@
 import Data.Binary.Put
 import Data.ByteString.Builder
 import SwiftNav.CRC16
-import SwiftNav.SBP.Encoding   ()
+import SwiftNav.Encoding       ()
 
 -- | Denotes the start of frame transmission. For v1.0, always 0x55.
+--
 msgSBPPreamble :: Word8
 msgSBPPreamble = 0x55
 
 -- | Default sender ID. Intended for messages sent from the host to
 -- the device.
+--
 defaultSender :: Word16
 defaultSender = 0x42
 
@@ -43,6 +48,7 @@
 -- to transmit solutions, observations, status and debugging
 -- messages, as well as receive messages from the host operating
 -- system.
+--
 data Msg = Msg
   { _msgSBPType    :: !Word16
     -- ^ Uniquely identifies the type of the payload contents
@@ -66,19 +72,19 @@
 
 instance Binary Msg where
   get = do
-    _msgSBPType <- getWord16le
-    _msgSBPSender <- getWord16le
-    _msgSBPLen <- getWord8
+    _msgSBPType    <- getWord16le
+    _msgSBPSender  <- getWord16le
+    _msgSBPLen     <- getWord8
     _msgSBPPayload <- getByteString $ fromIntegral _msgSBPLen
-    _msgSBPCrc <- getWord16le
+    _msgSBPCrc     <- getWord16le
     return Msg {..}
 
   put Msg {..} = do
-    putWord16le _msgSBPType
-    putWord16le _msgSBPSender
-    putWord8 _msgSBPLen
+    putWord16le   _msgSBPType
+    putWord16le   _msgSBPSender
+    putWord8      _msgSBPLen
     putByteString _msgSBPPayload
-    putWord16le _msgSBPCrc
+    putWord16le   _msgSBPCrc
 
 checkCrc :: Msg -> Word16
 checkCrc Msg {..} =
@@ -101,14 +107,15 @@
   toJSON Msg {..} = object
     [ "preamble" .= msgSBPPreamble
     , "msg_type" .= _msgSBPType
-    , "sender" .= _msgSBPSender
-    , "length" .= _msgSBPLen
-    , "payload" .= _msgSBPPayload
-    , "crc" .= _msgSBPCrc
+    , "sender"   .= _msgSBPSender
+    , "length"   .= _msgSBPLen
+    , "payload"  .= _msgSBPPayload
+    , "crc"      .= _msgSBPCrc
     ]
 
 -- | Class of generic representation of specialized SBP messages into
 -- SBP message frames.
+--
 class Binary a => ToSBP a where
     -- | Convert an SBP message record that is serializable and a two-byte
     -- senderID to a binary into an SBP message frame.
diff --git a/src/SwiftNav/SBP/User.hs b/src/SwiftNav/SBP/User.hs
--- a/src/SwiftNav/SBP/User.hs
+++ b/src/SwiftNav/SBP/User.hs
@@ -13,12 +13,13 @@
 --
 -- Messages reserved for use by the user.
 
-module SwiftNav.SBP.User where
+module SwiftNav.SBP.User
+  ( module SwiftNav.SBP.User
+  ) where
 
-import BasicPrelude as P
+import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
@@ -27,7 +28,7 @@
 import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
-import SwiftNav.SBP.Encoding
+import SwiftNav.Encoding       ()
 import SwiftNav.SBP.TH
 import SwiftNav.SBP.Types
 
@@ -51,8 +52,6 @@
   put MsgUserData {..} = do
     mapM_ putWord8 _msgUserData_contents
 
-$(deriveSBP 'msgUserData ''MsgUserData)
-
-$(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_msgUserData_" . P.stripPrefix "_msgUserData_"}
-             ''MsgUserData)
+$(makeSBP 'msgUserData ''MsgUserData)
+$(makeJSON "_msgUserData_" ''MsgUserData)
 $(makeLenses ''MsgUserData)
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -1,6 +1,8 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
 import           BasicPrelude
-import qualified Test.SwiftNav.CRC16        as CRC16
-import qualified Test.SwiftNav.SBP.Encoding as Encoding
+import qualified Test.SwiftNav.CRC16    as CRC16
+import qualified Test.SwiftNav.Encoding as Encoding
 import           Test.Tasty
 
 tests :: TestTree
diff --git a/test/Test/SwiftNav/CRC16.hs b/test/Test/SwiftNav/CRC16.hs
--- a/test/Test/SwiftNav/CRC16.hs
+++ b/test/Test/SwiftNav/CRC16.hs
@@ -6,7 +6,7 @@
   ) where
 
 import BasicPrelude
-import SwiftNav.CRC16
+import SwiftNav.Internal
 import Test.Tasty
 import Test.Tasty.HUnit
 
diff --git a/test/Test/SwiftNav/Encoding.hs b/test/Test/SwiftNav/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/SwiftNav/Encoding.hs
@@ -0,0 +1,40 @@
+{-# OPTIONS -fno-warn-orphans  #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.SwiftNav.Encoding
+  ( tests
+  ) where
+
+import           BasicPrelude
+import qualified Data.Aeson            as A
+import           Data.ByteString       as BS
+import           SwiftNav.Internal     ()
+import           Test.QuickCheck
+import           Test.Tasty
+import           Test.Tasty.HUnit
+import           Test.Tasty.QuickCheck as QC
+
+instance Arbitrary BS.ByteString where
+    arbitrary = BS.pack <$> arbitrary
+    shrink xs = BS.pack <$> shrink (BS.unpack xs)
+
+instance CoArbitrary BS.ByteString where
+    coarbitrary = coarbitrary . BS.unpack
+
+testParse :: TestTree
+testParse =
+  testGroup "Empty Test"
+    [ testCase "Empty data" $ do
+        (A.decode . A.encode $ ("dddd" :: BS.ByteString)) @?= Just ("dddd" :: BS.ByteString)
+    ]
+
+testRoundtrip :: TestTree
+testRoundtrip = QC.testProperty "Aeson" prop
+  where prop ws = (A.decode . A.encode $ (ws :: BS.ByteString)) === Just (ws :: BS.ByteString)
+
+tests :: TestTree
+tests = testGroup "Roundtrip JSON serialization"
+        [ testRoundtrip
+        , testParse
+        ]
diff --git a/test/Test/SwiftNav/SBP/Encoding.hs b/test/Test/SwiftNav/SBP/Encoding.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Encoding.hs
+++ /dev/null
@@ -1,40 +0,0 @@
-{-# OPTIONS -fno-warn-orphans  #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.SwiftNav.SBP.Encoding
-  ( tests
-  ) where
-
-import           BasicPrelude
-import qualified Data.Aeson            as A
-import           Data.ByteString       as BS
-import           SwiftNav.SBP.Encoding ()
-import           Test.QuickCheck
-import           Test.Tasty
-import           Test.Tasty.HUnit
-import           Test.Tasty.QuickCheck as QC
-
-instance Arbitrary BS.ByteString where
-    arbitrary = BS.pack <$> arbitrary
-    shrink xs = BS.pack <$> shrink (BS.unpack xs)
-
-instance CoArbitrary BS.ByteString where
-    coarbitrary = coarbitrary . BS.unpack
-
-testParse :: TestTree
-testParse =
-  testGroup "Empty Test"
-    [ testCase "Empty data" $ do
-        (A.decode . A.encode $ ("dddd" :: BS.ByteString)) @?= Just ("dddd" :: BS.ByteString)
-    ]
-
-testRoundtrip :: TestTree
-testRoundtrip = QC.testProperty "Aeson" prop
-  where prop ws = (A.decode . A.encode $ (ws :: BS.ByteString)) === Just (ws :: BS.ByteString)
-
-tests :: TestTree
-tests = testGroup "Roundtrip JSON serialization"
-        [ testRoundtrip
-        , testParse
-        ]
