diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,6 +2,14 @@
 
 Haskell client for Swift Binary Protocol (SBP).
 
+## Requirements
+
+`haskell-stack`: [Instructions here](https://github.com/commercialhaskell/stack/blob/master/doc/install_and_upgrade.md).
+
+## Install from Hackage
+
+Available on [Hackage as `sbp`](http://hackage.haskell.org/package/sbp).
+
 ## Setup
 
 To build:
diff --git a/main/JSON2SBP.hs b/main/JSON2SBP.hs
--- a/main/JSON2SBP.hs
+++ b/main/JSON2SBP.hs
@@ -9,14 +9,13 @@
 -- JSON to SBP tool - reads SBP JSON from stdin and sends SBP JSON to
 -- stdout.
 
-import           BasicPrelude
+import           BasicPrelude hiding (lines)
 import           Control.Monad.Trans.Resource
 import           Data.Aeson
 import           Data.Conduit
 import           Data.Conduit.Binary
 import qualified Data.Conduit.List as CL
 import           Data.Conduit.Serialization.Binary
-import qualified Data.Conduit.Text as CT
 import           SwiftNav.SBP
 import           System.IO
 
@@ -33,8 +32,10 @@
 decodeSBPMsg v = decodeStrict v <|> sbpMsgData <$> decodeStrict v
 
 main :: IO ()
-main = runResourceT $
-  sourceHandle stdin =$=
-  CT.decode CT.utf8 =$= CT.lines =$= CL.mapMaybe (decodeSBPMsg . encodeUtf8) =$=
-  conduitEncode $$
-  sinkHandle stdout
+main =
+  runResourceT $
+    sourceHandle stdin       =$=
+    lines                    =$=
+    CL.mapMaybe decodeSBPMsg =$=
+    conduitEncode            $$
+    sinkHandle stdout
diff --git a/main/SBP2JSON.hs b/main/SBP2JSON.hs
--- a/main/SBP2JSON.hs
+++ b/main/SBP2JSON.hs
@@ -24,12 +24,12 @@
 
 -- | Encode a SBPMsg to a line of JSON.
 encodeLine :: SBPMsg -> ByteString
-encodeLine v = BL.toStrict $ toLazyByteString $
-  encodeToByteStringBuilder (toJSON v) <> "\n"
+encodeLine v = BL.toStrict $ toLazyByteString $ encodeToBuilder (toJSON v) <> "\n"
 
 main :: IO ()
-main = runResourceT $
-  sourceHandle stdin =$=
-  conduitDecode =$=
-  CL.map encodeLine $$
-  sinkHandle stdout
+main =
+  runResourceT $
+    sourceHandle stdin  =$=
+      conduitDecode     =$=
+      CL.map encodeLine $$
+      sinkHandle stdout
diff --git a/main/SBP2YAML.hs b/main/SBP2YAML.hs
--- a/main/SBP2YAML.hs
+++ b/main/SBP2YAML.hs
@@ -20,8 +20,9 @@
 import           System.IO
 
 main :: IO ()
-main = runResourceT $
-  sourceHandle stdin =$=
-  conduitDecode =$=
-  CL.map (encode :: SBPMsg -> ByteString) $$
-  sinkHandle stdout
+main =
+  runResourceT $
+    sourceHandle stdin                      =$=
+    conduitDecode                           =$=
+    CL.map (encode :: SBPMsg -> ByteString) $$
+    sinkHandle stdout
diff --git a/sbp.cabal b/sbp.cabal
--- a/sbp.cabal
+++ b/sbp.cabal
@@ -1,5 +1,5 @@
 name:                  sbp
-version:               0.52.1
+version:               0.52.2
 synopsis:              SwiftNav's SBP Library
 homepage:              https://github.com/swift-nav/libsbp
 license:               LGPL-3
@@ -137,18 +137,7 @@
   hs-source-dirs:      test
   main-is:             Test.hs
   other-modules:       Test.SwiftNav.CRC16
-                     , Test.SwiftNav.SBP.Acquisition
-                     , Test.SwiftNav.SBP.Bootload
                      , Test.SwiftNav.SBP.Encoding
-                     , Test.SwiftNav.SBP.ExtEvents
-                     , Test.SwiftNav.SBP.Logging
-                     , Test.SwiftNav.SBP.Navigation
-                     , Test.SwiftNav.SBP.Observation
-                     , Test.SwiftNav.SBP.Piksi
-                     , Test.SwiftNav.SBP.System
-                     , Test.SwiftNav.SBP.Table
-                     , Test.SwiftNav.SBP.Tracking
-                     , Test.SwiftNav.SBP.Utils
   build-depends:       aeson
                      , base
                      , base64-bytestring
@@ -159,7 +148,6 @@
                      , tasty
                      , tasty-hunit
                      , tasty-quickcheck
-                     , yaml-light
   ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall
   default-language:    Haskell2010
   default-extensions:  NoImplicitPrelude
diff --git a/src/SwiftNav/CRC16.hs b/src/SwiftNav/CRC16.hs
--- a/src/SwiftNav/CRC16.hs
+++ b/src/SwiftNav/CRC16.hs
@@ -12,7 +12,7 @@
   ( crc16
   ) where
 
-import BasicPrelude hiding ( ByteString, foldl' )
+import BasicPrelude         hiding (ByteString, foldl')
 import Data.Array
 import Data.Bits
 import Data.ByteString.Lazy
diff --git a/src/SwiftNav/SBP.hs b/src/SwiftNav/SBP.hs
--- a/src/SwiftNav/SBP.hs
+++ b/src/SwiftNav/SBP.hs
@@ -27,16 +27,11 @@
   , module SwiftNav.SBP.User
   ) where
 
-import BasicPrelude hiding (lookup)
-import Control.Lens hiding ((.=))
-import Data.Aeson hiding (decode, decode')
+import BasicPrelude             hiding (lookup)
+import Control.Lens             hiding ((.=))
+import Data.Aeson               hiding (decode, decode')
 import Data.Binary
-import Data.Binary.Get
-import Data.Binary.Put
-import Data.ByteString.Lazy hiding (ByteString)
-import Data.ByteString.Builder
-import Data.HashMap.Strict
-import SwiftNav.CRC16
+import Data.ByteString.Lazy     hiding (ByteString)
 import SwiftNav.SBP.Acquisition
 import SwiftNav.SBP.Bootload
 import SwiftNav.SBP.ExtEvents
@@ -132,160 +127,160 @@
    | SBPMsgUnknown Msg
   deriving ( Show, Read, Eq )
 
+$(makePrisms ''SBPMsg)
+
 instance Binary SBPMsg where
   get = do
     preamble <- getWord8
     if preamble /= msgSBPPreamble then get else do
-      sbp <- get
-      return $ decode' sbp where
-        decode' sbp@Msg {..}
-          | checkCrc sbp /= _msgSBPCrc = SBPMsgBadCrc sbp
-          | _msgSBPType == msgAcqResult = SBPMsgAcqResult (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgAcqResultDepA = SBPMsgAcqResultDepA (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgAlmanac = SBPMsgAlmanac (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBasePosEcef = SBPMsgBasePosEcef (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBasePosLlh = SBPMsgBasePosLlh (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBaselineEcef = SBPMsgBaselineEcef (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBaselineHeading = SBPMsgBaselineHeading (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBaselineNed = SBPMsgBaselineNed (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBootloaderHandshakeDepA = SBPMsgBootloaderHandshakeDepA (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBootloaderHandshakeReq = SBPMsgBootloaderHandshakeReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBootloaderHandshakeResp = SBPMsgBootloaderHandshakeResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgBootloaderJumpToApp = SBPMsgBootloaderJumpToApp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgCwResults = SBPMsgCwResults (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgCwStart = SBPMsgCwStart (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgDops = SBPMsgDops (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgEphemeris = SBPMsgEphemeris (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgEphemerisDepA = SBPMsgEphemerisDepA (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgEphemerisDepB = SBPMsgEphemerisDepB (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgExtEvent = SBPMsgExtEvent (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioReadDirReq = SBPMsgFileioReadDirReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioReadDirResp = SBPMsgFileioReadDirResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioReadReq = SBPMsgFileioReadReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioReadResp = SBPMsgFileioReadResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioRemove = SBPMsgFileioRemove (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioWriteReq = SBPMsgFileioWriteReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFileioWriteResp = SBPMsgFileioWriteResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFlashDone = SBPMsgFlashDone (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFlashErase = SBPMsgFlashErase (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFlashProgram = SBPMsgFlashProgram (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFlashReadReq = SBPMsgFlashReadReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgFlashReadResp = SBPMsgFlashReadResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgGpsTime = SBPMsgGpsTime (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgHeartbeat = SBPMsgHeartbeat (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgIarState = SBPMsgIarState (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgInitBase = SBPMsgInitBase (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgLog = SBPMsgLog (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgM25FlashWriteStatus = SBPMsgM25FlashWriteStatus (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgMaskSatellite = SBPMsgMaskSatellite (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgNapDeviceDnaReq = SBPMsgNapDeviceDnaReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgNapDeviceDnaResp = SBPMsgNapDeviceDnaResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgObs = SBPMsgObs (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgObsDepA = SBPMsgObsDepA (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgPosEcef = SBPMsgPosEcef (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgPosLlh = SBPMsgPosLlh (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgPrintDep = SBPMsgPrintDep (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgReset = SBPMsgReset (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgResetFilters = SBPMsgResetFilters (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSetTime = SBPMsgSetTime (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsReadByIndexDone = SBPMsgSettingsReadByIndexDone (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsReadByIndexReq = SBPMsgSettingsReadByIndexReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsReadByIndexResp = SBPMsgSettingsReadByIndexResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsReadReq = SBPMsgSettingsReadReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsReadResp = SBPMsgSettingsReadResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsSave = SBPMsgSettingsSave (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgSettingsWrite = SBPMsgSettingsWrite (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgStartup = SBPMsgStartup (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgStmFlashLockSector = SBPMsgStmFlashLockSector (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgStmFlashUnlockSector = SBPMsgStmFlashUnlockSector (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgStmUniqueIdReq = SBPMsgStmUniqueIdReq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgStmUniqueIdResp = SBPMsgStmUniqueIdResp (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgThreadState = SBPMsgThreadState (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgTrackingIq = SBPMsgTrackingIq (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgTrackingState = SBPMsgTrackingState (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgTrackingStateDepA = SBPMsgTrackingStateDepA (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgTweet = SBPMsgTweet (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgUartState = SBPMsgUartState (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgUserData = SBPMsgUserData (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgVelEcef = SBPMsgVelEcef (decode (fromStrict _msgSBPPayload)) sbp
-          | _msgSBPType == msgVelNed = SBPMsgVelNed (decode (fromStrict _msgSBPPayload)) sbp
-          | otherwise = SBPMsgUnknown sbp
+      decode' <$> get where
+        decode' m@Msg {..}
+          | checkCrc m /= _msgSBPCrc = SBPMsgBadCrc m
+          | _msgSBPType == msgAcqResult = SBPMsgAcqResult (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgAcqResultDepA = SBPMsgAcqResultDepA (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgAlmanac = SBPMsgAlmanac (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBasePosEcef = SBPMsgBasePosEcef (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBasePosLlh = SBPMsgBasePosLlh (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBaselineEcef = SBPMsgBaselineEcef (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBaselineHeading = SBPMsgBaselineHeading (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBaselineNed = SBPMsgBaselineNed (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBootloaderHandshakeDepA = SBPMsgBootloaderHandshakeDepA (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBootloaderHandshakeReq = SBPMsgBootloaderHandshakeReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBootloaderHandshakeResp = SBPMsgBootloaderHandshakeResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgBootloaderJumpToApp = SBPMsgBootloaderJumpToApp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgCwResults = SBPMsgCwResults (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgCwStart = SBPMsgCwStart (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgDops = SBPMsgDops (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgEphemeris = SBPMsgEphemeris (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgEphemerisDepA = SBPMsgEphemerisDepA (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgEphemerisDepB = SBPMsgEphemerisDepB (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgExtEvent = SBPMsgExtEvent (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioReadDirReq = SBPMsgFileioReadDirReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioReadDirResp = SBPMsgFileioReadDirResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioReadReq = SBPMsgFileioReadReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioReadResp = SBPMsgFileioReadResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioRemove = SBPMsgFileioRemove (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioWriteReq = SBPMsgFileioWriteReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFileioWriteResp = SBPMsgFileioWriteResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFlashDone = SBPMsgFlashDone (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFlashErase = SBPMsgFlashErase (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFlashProgram = SBPMsgFlashProgram (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFlashReadReq = SBPMsgFlashReadReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgFlashReadResp = SBPMsgFlashReadResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgGpsTime = SBPMsgGpsTime (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgHeartbeat = SBPMsgHeartbeat (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgIarState = SBPMsgIarState (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgInitBase = SBPMsgInitBase (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgLog = SBPMsgLog (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgM25FlashWriteStatus = SBPMsgM25FlashWriteStatus (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgMaskSatellite = SBPMsgMaskSatellite (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgNapDeviceDnaReq = SBPMsgNapDeviceDnaReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgNapDeviceDnaResp = SBPMsgNapDeviceDnaResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgObs = SBPMsgObs (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgObsDepA = SBPMsgObsDepA (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgPosEcef = SBPMsgPosEcef (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgPosLlh = SBPMsgPosLlh (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgPrintDep = SBPMsgPrintDep (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgReset = SBPMsgReset (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgResetFilters = SBPMsgResetFilters (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSetTime = SBPMsgSetTime (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsReadByIndexDone = SBPMsgSettingsReadByIndexDone (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsReadByIndexReq = SBPMsgSettingsReadByIndexReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsReadByIndexResp = SBPMsgSettingsReadByIndexResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsReadReq = SBPMsgSettingsReadReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsReadResp = SBPMsgSettingsReadResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsSave = SBPMsgSettingsSave (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgSettingsWrite = SBPMsgSettingsWrite (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgStartup = SBPMsgStartup (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgStmFlashLockSector = SBPMsgStmFlashLockSector (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgStmFlashUnlockSector = SBPMsgStmFlashUnlockSector (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgStmUniqueIdReq = SBPMsgStmUniqueIdReq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgStmUniqueIdResp = SBPMsgStmUniqueIdResp (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgThreadState = SBPMsgThreadState (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgTrackingIq = SBPMsgTrackingIq (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgTrackingState = SBPMsgTrackingState (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgTrackingStateDepA = SBPMsgTrackingStateDepA (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgTweet = SBPMsgTweet (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgUartState = SBPMsgUartState (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgUserData = SBPMsgUserData (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgVelEcef = SBPMsgVelEcef (decode (fromStrict _msgSBPPayload)) m
+          | _msgSBPType == msgVelNed = SBPMsgVelNed (decode (fromStrict _msgSBPPayload)) m
+          | otherwise = SBPMsgUnknown m
 
-  put msg = do
+  put sm = do
     putWord8 msgSBPPreamble
-    put $ encode' msg
-    where
-      encode' (SBPMsgAcqResult _ sbp) = sbp
-      encode' (SBPMsgAcqResultDepA _ sbp) = sbp
-      encode' (SBPMsgAlmanac _ sbp) = sbp
-      encode' (SBPMsgBasePosEcef _ sbp) = sbp
-      encode' (SBPMsgBasePosLlh _ sbp) = sbp
-      encode' (SBPMsgBaselineEcef _ sbp) = sbp
-      encode' (SBPMsgBaselineHeading _ sbp) = sbp
-      encode' (SBPMsgBaselineNed _ sbp) = sbp
-      encode' (SBPMsgBootloaderHandshakeDepA _ sbp) = sbp
-      encode' (SBPMsgBootloaderHandshakeReq _ sbp) = sbp
-      encode' (SBPMsgBootloaderHandshakeResp _ sbp) = sbp
-      encode' (SBPMsgBootloaderJumpToApp _ sbp) = sbp
-      encode' (SBPMsgCwResults _ sbp) = sbp
-      encode' (SBPMsgCwStart _ sbp) = sbp
-      encode' (SBPMsgDops _ sbp) = sbp
-      encode' (SBPMsgEphemeris _ sbp) = sbp
-      encode' (SBPMsgEphemerisDepA _ sbp) = sbp
-      encode' (SBPMsgEphemerisDepB _ sbp) = sbp
-      encode' (SBPMsgExtEvent _ sbp) = sbp
-      encode' (SBPMsgFileioReadDirReq _ sbp) = sbp
-      encode' (SBPMsgFileioReadDirResp _ sbp) = sbp
-      encode' (SBPMsgFileioReadReq _ sbp) = sbp
-      encode' (SBPMsgFileioReadResp _ sbp) = sbp
-      encode' (SBPMsgFileioRemove _ sbp) = sbp
-      encode' (SBPMsgFileioWriteReq _ sbp) = sbp
-      encode' (SBPMsgFileioWriteResp _ sbp) = sbp
-      encode' (SBPMsgFlashDone _ sbp) = sbp
-      encode' (SBPMsgFlashErase _ sbp) = sbp
-      encode' (SBPMsgFlashProgram _ sbp) = sbp
-      encode' (SBPMsgFlashReadReq _ sbp) = sbp
-      encode' (SBPMsgFlashReadResp _ sbp) = sbp
-      encode' (SBPMsgGpsTime _ sbp) = sbp
-      encode' (SBPMsgHeartbeat _ sbp) = sbp
-      encode' (SBPMsgIarState _ sbp) = sbp
-      encode' (SBPMsgInitBase _ sbp) = sbp
-      encode' (SBPMsgLog _ sbp) = sbp
-      encode' (SBPMsgM25FlashWriteStatus _ sbp) = sbp
-      encode' (SBPMsgMaskSatellite _ sbp) = sbp
-      encode' (SBPMsgNapDeviceDnaReq _ sbp) = sbp
-      encode' (SBPMsgNapDeviceDnaResp _ sbp) = sbp
-      encode' (SBPMsgObs _ sbp) = sbp
-      encode' (SBPMsgObsDepA _ sbp) = sbp
-      encode' (SBPMsgPosEcef _ sbp) = sbp
-      encode' (SBPMsgPosLlh _ sbp) = sbp
-      encode' (SBPMsgPrintDep _ sbp) = sbp
-      encode' (SBPMsgReset _ sbp) = sbp
-      encode' (SBPMsgResetFilters _ sbp) = sbp
-      encode' (SBPMsgSetTime _ sbp) = sbp
-      encode' (SBPMsgSettingsReadByIndexDone _ sbp) = sbp
-      encode' (SBPMsgSettingsReadByIndexReq _ sbp) = sbp
-      encode' (SBPMsgSettingsReadByIndexResp _ sbp) = sbp
-      encode' (SBPMsgSettingsReadReq _ sbp) = sbp
-      encode' (SBPMsgSettingsReadResp _ sbp) = sbp
-      encode' (SBPMsgSettingsSave _ sbp) = sbp
-      encode' (SBPMsgSettingsWrite _ sbp) = sbp
-      encode' (SBPMsgStartup _ sbp) = sbp
-      encode' (SBPMsgStmFlashLockSector _ sbp) = sbp
-      encode' (SBPMsgStmFlashUnlockSector _ sbp) = sbp
-      encode' (SBPMsgStmUniqueIdReq _ sbp) = sbp
-      encode' (SBPMsgStmUniqueIdResp _ sbp) = sbp
-      encode' (SBPMsgThreadState _ sbp) = sbp
-      encode' (SBPMsgTrackingIq _ sbp) = sbp
-      encode' (SBPMsgTrackingState _ sbp) = sbp
-      encode' (SBPMsgTrackingStateDepA _ sbp) = sbp
-      encode' (SBPMsgTweet _ sbp) = sbp
-      encode' (SBPMsgUartState _ sbp) = sbp
-      encode' (SBPMsgUserData _ sbp) = sbp
-      encode' (SBPMsgVelEcef _ sbp) = sbp
-      encode' (SBPMsgVelNed _ sbp) = sbp
-      encode' (SBPMsgUnknown sbp) = sbp
-      encode' (SBPMsgBadCrc sbp) = sbp
+    encode' sm where
+      encode' (SBPMsgAcqResult _ m) = put m
+      encode' (SBPMsgAcqResultDepA _ m) = put m
+      encode' (SBPMsgAlmanac _ m) = put m
+      encode' (SBPMsgBasePosEcef _ m) = put m
+      encode' (SBPMsgBasePosLlh _ m) = put m
+      encode' (SBPMsgBaselineEcef _ m) = put m
+      encode' (SBPMsgBaselineHeading _ m) = put m
+      encode' (SBPMsgBaselineNed _ m) = put m
+      encode' (SBPMsgBootloaderHandshakeDepA _ m) = put m
+      encode' (SBPMsgBootloaderHandshakeReq _ m) = put m
+      encode' (SBPMsgBootloaderHandshakeResp _ m) = put m
+      encode' (SBPMsgBootloaderJumpToApp _ m) = put m
+      encode' (SBPMsgCwResults _ m) = put m
+      encode' (SBPMsgCwStart _ m) = put m
+      encode' (SBPMsgDops _ m) = put m
+      encode' (SBPMsgEphemeris _ m) = put m
+      encode' (SBPMsgEphemerisDepA _ m) = put m
+      encode' (SBPMsgEphemerisDepB _ m) = put m
+      encode' (SBPMsgExtEvent _ 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' (SBPMsgGpsTime _ m) = put m
+      encode' (SBPMsgHeartbeat _ m) = put m
+      encode' (SBPMsgIarState _ m) = put m
+      encode' (SBPMsgInitBase _ 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' (SBPMsgObs _ m) = put m
+      encode' (SBPMsgObsDepA _ m) = put m
+      encode' (SBPMsgPosEcef _ m) = put m
+      encode' (SBPMsgPosLlh _ m) = put m
+      encode' (SBPMsgPrintDep _ m) = put m
+      encode' (SBPMsgReset _ 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' (SBPMsgSettingsSave _ m) = put m
+      encode' (SBPMsgSettingsWrite _ 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' (SBPMsgThreadState _ m) = put m
+      encode' (SBPMsgTrackingIq _ m) = put m
+      encode' (SBPMsgTrackingState _ m) = put m
+      encode' (SBPMsgTrackingStateDepA _ m) = put m
+      encode' (SBPMsgTweet _ m) = put m
+      encode' (SBPMsgUartState _ m) = put m
+      encode' (SBPMsgUserData _ m) = put m
+      encode' (SBPMsgVelEcef _ m) = put m
+      encode' (SBPMsgVelNed _ m) = put m
+      encode' (SBPMsgUnknown m) = put m
+      encode' (SBPMsgBadCrc m) = put m
 
 instance FromJSON SBPMsg where
   parseJSON obj@(Object o) = do
@@ -364,81 +359,154 @@
         | otherwise = SBPMsgUnknown <$> parseJSON obj
   parseJSON _ = mzero
 
-merge :: Value -> Value -> Value
-merge (Object one) (Object two) = Object (one <> two)
-merge _ (Object two) = Object two
-merge (Object one) _ = Object one
-merge _ v = v
+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
 
 instance ToJSON SBPMsg where
-   toJSON (SBPMsgAcqResult msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgAcqResultDepA msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgAlmanac msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBasePosEcef msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBasePosLlh msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBaselineEcef msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBaselineHeading msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBaselineNed msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBootloaderHandshakeDepA msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBootloaderHandshakeReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBootloaderHandshakeResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBootloaderJumpToApp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgCwResults msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgCwStart msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgDops msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgEphemeris msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgEphemerisDepA msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgEphemerisDepB msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgExtEvent msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioReadDirReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioReadDirResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioReadReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioReadResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioRemove msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioWriteReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFileioWriteResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFlashDone msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFlashErase msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFlashProgram msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFlashReadReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgFlashReadResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgGpsTime msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgHeartbeat msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgIarState msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgInitBase msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgLog msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgM25FlashWriteStatus msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgMaskSatellite msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgNapDeviceDnaReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgNapDeviceDnaResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgObs msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgObsDepA msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgPosEcef msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgPosLlh msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgPrintDep msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgReset msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgResetFilters msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSetTime msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsReadByIndexDone msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsReadByIndexReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsReadByIndexResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsReadReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsReadResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsSave msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgSettingsWrite msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgStartup msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgStmFlashLockSector msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgStmFlashUnlockSector msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgStmUniqueIdReq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgStmUniqueIdResp msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgThreadState msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgTrackingIq msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgTrackingState msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgTrackingStateDepA msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgTweet msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgUartState msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgUserData msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgVelEcef msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgVelNed msg sbp) = toJSON msg `merge` toJSON sbp
-   toJSON (SBPMsgBadCrc sbp) = toJSON sbp
-   toJSON (SBPMsgUnknown sbp) = toJSON sbp
+  toJSON (SBPMsgAcqResult n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgAcqResultDepA n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgAlmanac 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 (SBPMsgBaselineHeading n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgBaselineNed 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 (SBPMsgCwResults n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgCwStart n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgDops n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgEphemeris 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 (SBPMsgExtEvent 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 (SBPMsgGpsTime 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 (SBPMsgInitBase 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 (SBPMsgObs n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgObsDepA n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgPosEcef n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgPosLlh 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 (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 (SBPMsgSettingsSave n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgSettingsWrite 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 (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 (SBPMsgTweet n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgUartState n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgUserData n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgVelEcef n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgVelNed n m) = toJSON n `mergeValues` toJSON m
+  toJSON (SBPMsgBadCrc m) = toJSON m
+  toJSON (SBPMsgUnknown m) = toJSON m
+
+instance HasMsg SBPMsg where
+  msg f (SBPMsgAcqResult n m) = SBPMsgAcqResult n <$> f m
+  msg f (SBPMsgAcqResultDepA n m) = SBPMsgAcqResultDepA n <$> f m
+  msg f (SBPMsgAlmanac n m) = SBPMsgAlmanac n <$> f m
+  msg f (SBPMsgBasePosEcef n m) = SBPMsgBasePosEcef n <$> f m
+  msg f (SBPMsgBasePosLlh n m) = SBPMsgBasePosLlh n <$> f m
+  msg f (SBPMsgBaselineEcef n m) = SBPMsgBaselineEcef n <$> f m
+  msg f (SBPMsgBaselineHeading n m) = SBPMsgBaselineHeading n <$> f m
+  msg f (SBPMsgBaselineNed n m) = SBPMsgBaselineNed n <$> f m
+  msg f (SBPMsgBootloaderHandshakeDepA n m) = SBPMsgBootloaderHandshakeDepA n <$> f m
+  msg f (SBPMsgBootloaderHandshakeReq n m) = SBPMsgBootloaderHandshakeReq n <$> f m
+  msg f (SBPMsgBootloaderHandshakeResp n m) = SBPMsgBootloaderHandshakeResp n <$> f m
+  msg f (SBPMsgBootloaderJumpToApp n m) = SBPMsgBootloaderJumpToApp n <$> f m
+  msg f (SBPMsgCwResults n m) = SBPMsgCwResults n <$> f m
+  msg f (SBPMsgCwStart n m) = SBPMsgCwStart n <$> f m
+  msg f (SBPMsgDops n m) = SBPMsgDops n <$> f m
+  msg f (SBPMsgEphemeris n m) = SBPMsgEphemeris n <$> f m
+  msg f (SBPMsgEphemerisDepA n m) = SBPMsgEphemerisDepA n <$> f m
+  msg f (SBPMsgEphemerisDepB n m) = SBPMsgEphemerisDepB n <$> f m
+  msg f (SBPMsgExtEvent n m) = SBPMsgExtEvent n <$> f m
+  msg f (SBPMsgFileioReadDirReq n m) = SBPMsgFileioReadDirReq n <$> f m
+  msg f (SBPMsgFileioReadDirResp n m) = SBPMsgFileioReadDirResp n <$> f m
+  msg f (SBPMsgFileioReadReq n m) = SBPMsgFileioReadReq n <$> f m
+  msg f (SBPMsgFileioReadResp n m) = SBPMsgFileioReadResp n <$> f m
+  msg f (SBPMsgFileioRemove n m) = SBPMsgFileioRemove n <$> f m
+  msg f (SBPMsgFileioWriteReq n m) = SBPMsgFileioWriteReq n <$> f m
+  msg f (SBPMsgFileioWriteResp n m) = SBPMsgFileioWriteResp n <$> f m
+  msg f (SBPMsgFlashDone n m) = SBPMsgFlashDone n <$> f m
+  msg f (SBPMsgFlashErase n m) = SBPMsgFlashErase n <$> f m
+  msg f (SBPMsgFlashProgram n m) = SBPMsgFlashProgram n <$> f m
+  msg f (SBPMsgFlashReadReq n m) = SBPMsgFlashReadReq n <$> f m
+  msg f (SBPMsgFlashReadResp n m) = SBPMsgFlashReadResp n <$> f m
+  msg f (SBPMsgGpsTime n m) = SBPMsgGpsTime n <$> f m
+  msg f (SBPMsgHeartbeat n m) = SBPMsgHeartbeat n <$> f m
+  msg f (SBPMsgIarState n m) = SBPMsgIarState n <$> f m
+  msg f (SBPMsgInitBase n m) = SBPMsgInitBase n <$> f m
+  msg f (SBPMsgLog n m) = SBPMsgLog n <$> f m
+  msg f (SBPMsgM25FlashWriteStatus n m) = SBPMsgM25FlashWriteStatus n <$> f m
+  msg f (SBPMsgMaskSatellite n m) = SBPMsgMaskSatellite n <$> f m
+  msg f (SBPMsgNapDeviceDnaReq n m) = SBPMsgNapDeviceDnaReq n <$> f m
+  msg f (SBPMsgNapDeviceDnaResp n m) = SBPMsgNapDeviceDnaResp n <$> f m
+  msg f (SBPMsgObs n m) = SBPMsgObs n <$> f m
+  msg f (SBPMsgObsDepA n m) = SBPMsgObsDepA n <$> f m
+  msg f (SBPMsgPosEcef n m) = SBPMsgPosEcef n <$> f m
+  msg f (SBPMsgPosLlh n m) = SBPMsgPosLlh n <$> f m
+  msg f (SBPMsgPrintDep n m) = SBPMsgPrintDep n <$> f m
+  msg f (SBPMsgReset n m) = SBPMsgReset n <$> f m
+  msg f (SBPMsgResetFilters n m) = SBPMsgResetFilters n <$> f m
+  msg f (SBPMsgSetTime n m) = SBPMsgSetTime n <$> f m
+  msg f (SBPMsgSettingsReadByIndexDone n m) = SBPMsgSettingsReadByIndexDone n <$> f m
+  msg f (SBPMsgSettingsReadByIndexReq n m) = SBPMsgSettingsReadByIndexReq n <$> f m
+  msg f (SBPMsgSettingsReadByIndexResp n m) = SBPMsgSettingsReadByIndexResp n <$> f m
+  msg f (SBPMsgSettingsReadReq n m) = SBPMsgSettingsReadReq n <$> f m
+  msg f (SBPMsgSettingsReadResp n m) = SBPMsgSettingsReadResp n <$> f m
+  msg f (SBPMsgSettingsSave n m) = SBPMsgSettingsSave n <$> f m
+  msg f (SBPMsgSettingsWrite n m) = SBPMsgSettingsWrite n <$> f m
+  msg f (SBPMsgStartup n m) = SBPMsgStartup n <$> f m
+  msg f (SBPMsgStmFlashLockSector n m) = SBPMsgStmFlashLockSector n <$> f m
+  msg f (SBPMsgStmFlashUnlockSector n m) = SBPMsgStmFlashUnlockSector n <$> f m
+  msg f (SBPMsgStmUniqueIdReq n m) = SBPMsgStmUniqueIdReq n <$> f m
+  msg f (SBPMsgStmUniqueIdResp n m) = SBPMsgStmUniqueIdResp n <$> f m
+  msg f (SBPMsgThreadState n m) = SBPMsgThreadState n <$> f m
+  msg f (SBPMsgTrackingIq n m) = SBPMsgTrackingIq n <$> f m
+  msg f (SBPMsgTrackingState n m) = SBPMsgTrackingState n <$> f m
+  msg f (SBPMsgTrackingStateDepA n m) = SBPMsgTrackingStateDepA n <$> f m
+  msg f (SBPMsgTweet n m) = SBPMsgTweet n <$> f m
+  msg f (SBPMsgUartState n m) = SBPMsgUartState n <$> f m
+  msg f (SBPMsgUserData n m) = SBPMsgUserData n <$> f m
+  msg f (SBPMsgVelEcef n m) = SBPMsgVelEcef n <$> f m
+  msg f (SBPMsgVelNed n m) = SBPMsgVelNed n <$> f m
+  msg f (SBPMsgUnknown m) = SBPMsgUnknown <$> f m
+  msg f (SBPMsgBadCrc m) = SBPMsgBadCrc <$> f m
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Acquisition
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Bootload
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -15,13 +16,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
diff --git a/src/SwiftNav/SBP/Encoding.hs b/src/SwiftNav/SBP/Encoding.hs
--- a/src/SwiftNav/SBP/Encoding.hs
+++ b/src/SwiftNav/SBP/Encoding.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS -fno-warn-orphans #-}
 -- |
 -- Module:      SwiftNav.SBP.Encoding
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -10,12 +11,12 @@
 
 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
+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
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.ExtEvents
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -14,13 +15,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.FileIo
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -18,13 +19,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Flash
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -15,13 +16,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
diff --git a/src/SwiftNav/SBP/GnssSignal.hs b/src/SwiftNav/SBP/GnssSignal.hs
--- a/src/SwiftNav/SBP/GnssSignal.hs
+++ b/src/SwiftNav/SBP/GnssSignal.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.GnssSignal
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
@@ -30,25 +31,25 @@
 --
 -- Signal identifier containing constellation, band, and satellite identifier
 data GnssSignal = GnssSignal
-  { _gnssSignal_sat         :: Word16
+  { _gnssSignal_sat    :: Word16
     -- ^ Constellation-specific satellite identifier
-  , _gnssSignal_band        :: Word8
-    -- ^ Signal band
-  , _gnssSignal_constellation :: Word8
-    -- ^ Constellation to which the satellite belongs
+  , _gnssSignal_code   :: Word8
+    -- ^ Signal constellation, band and code
+  , _gnssSignal_reserved :: Word8
+    -- ^ Reserved
   } deriving ( Show, Read, Eq )
 
 instance Binary GnssSignal where
   get = do
     _gnssSignal_sat <- getWord16le
-    _gnssSignal_band <- getWord8
-    _gnssSignal_constellation <- getWord8
+    _gnssSignal_code <- getWord8
+    _gnssSignal_reserved <- getWord8
     return GnssSignal {..}
 
   put GnssSignal {..} = do
     putWord16le _gnssSignal_sat
-    putWord8 _gnssSignal_band
-    putWord8 _gnssSignal_constellation
+    putWord8 _gnssSignal_code
+    putWord8 _gnssSignal_reserved
 $(deriveJSON defaultOptions {fieldLabelModifier = fromMaybe "_gnssSignal_" . stripPrefix "_gnssSignal_"}
              ''GnssSignal)
 $(makeLenses ''GnssSignal)
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Logging
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Navigation
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -21,13 +22,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Observation
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Piksi
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -15,13 +16,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Settings
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -17,13 +18,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.System
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -14,18 +14,18 @@
 import Control.Lens
 import Data.Binary
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
-import Data.Word
+import Data.ByteString.Lazy hiding (ByteString)
 import Language.Haskell.TH
 import SwiftNav.SBP.Types
 
 -- | Derive ToSBP typeclass, given an SBP message type name and the
 -- name of the implemented type.
 deriveSBP :: Name -> Name -> Q [Dec]
-deriveSBP msgType name = [d|instance ToSBP $(conT name) where
-                              toSBP msg senderID = encoded & msgSBPCrc .~ checkCrc encoded
-                                where
-                                  payload = toStrict $ encode msg
-                                  len = fromIntegral $ Data.ByteString.length payload
-                                  encoded = Msg $(varE msgType) senderID len payload 0
-                           |]
+deriveSBP msgType name =
+  [d|instance ToSBP $(conT name) where
+       toSBP m senderID = encoded & msgSBPCrc .~ checkCrc encoded
+         where
+           payload = toStrict $ encode m
+           len = fromIntegral $ Data.ByteString.length payload
+           encoded = Msg $(varE msgType) senderID len payload 0
+    |]
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.Tracking
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
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
@@ -11,16 +11,15 @@
 
 module SwiftNav.SBP.Types where
 
-import BasicPrelude hiding (lookup)
-import Control.Lens hiding ((.=))
-import Data.Aeson hiding (decode, decode')
+import BasicPrelude            hiding (lookup)
+import Control.Lens            hiding ((.=))
+import Data.Aeson              hiding (decode, decode')
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.Put
-import Data.ByteString.Lazy hiding (ByteString)
 import Data.ByteString.Builder
 import SwiftNav.CRC16
-import SwiftNav.SBP.Encoding
+import SwiftNav.SBP.Encoding   ()
 
 -- | Denotes the start of frame transmission. For v1.0, always 0x55.
 msgSBPPreamble :: Word8
@@ -58,7 +57,7 @@
     -- Preamble)
   } deriving ( Show, Read, Eq )
 
-$(makeLenses ''Msg)
+$(makeClassy ''Msg)
 
 instance Binary Msg where
   get = do
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
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -- |
 -- Module:      SwiftNav.SBP.User
 -- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
@@ -13,13 +14,13 @@
 import BasicPrelude
 import Control.Lens
 import Control.Monad.Loops
-import Data.Aeson.TH (deriveJSON, defaultOptions, fieldLabelModifier)
+import Data.Aeson.TH           (defaultOptions, deriveJSON, fieldLabelModifier)
 import Data.Binary
 import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Binary.Put
 import Data.ByteString
-import Data.ByteString.Lazy hiding ( ByteString )
+import Data.ByteString.Lazy    hiding (ByteString)
 import Data.Int
 import Data.Word
 import SwiftNav.SBP.Encoding
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -1,33 +1,13 @@
 import           BasicPrelude
-import qualified Test.SwiftNav.CRC16 as CRC16
-import qualified Test.SwiftNav.SBP.Acquisition as Acquisition
-import qualified Test.SwiftNav.SBP.Bootload as Bootload
+import qualified Test.SwiftNav.CRC16        as CRC16
 import qualified Test.SwiftNav.SBP.Encoding as Encoding
-import qualified Test.SwiftNav.SBP.ExtEvents as ExtEvents
-import qualified Test.SwiftNav.SBP.Logging as Logging
-import qualified Test.SwiftNav.SBP.Navigation as Navigation
-import qualified Test.SwiftNav.SBP.Observation as Observation
-import qualified Test.SwiftNav.SBP.Piksi as Piksi
-import qualified Test.SwiftNav.SBP.System as System
-import qualified Test.SwiftNav.SBP.Table as Table
-import qualified Test.SwiftNav.SBP.Tracking as Tracking
 import           Test.Tasty
 
 tests :: TestTree
 tests =
   testGroup "Tests"
     [ CRC16.tests
-    , Acquisition.tests
-    , Bootload.tests
     , Encoding.tests
-    , ExtEvents.tests
-    , Logging.tests
-    , Navigation.tests
-    , Observation.tests
-    , Piksi.tests
-    , System.tests
-    , Table.tests
-    , Tracking.tests
     ]
 
 main :: IO ()
diff --git a/test/Test/SwiftNav/SBP/Acquisition.hs b/test/Test/SwiftNav/SBP/Acquisition.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Acquisition.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Acquisition
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Acquisition
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_acquisition.yaml"
-            moduleName = "sbp.acquisition"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Acquisition Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Bootload.hs b/test/Test/SwiftNav/SBP/Bootload.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Bootload.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Bootload
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Bootload
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_bootload.yaml"
-            moduleName = "sbp.bootload"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Bootload Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Encoding.hs b/test/Test/SwiftNav/SBP/Encoding.hs
--- a/test/Test/SwiftNav/SBP/Encoding.hs
+++ b/test/Test/SwiftNav/SBP/Encoding.hs
@@ -1,15 +1,17 @@
+{-# OPTIONS -fno-warn-orphans #-}
+
 module Test.SwiftNav.SBP.Encoding
   ( tests
   ) where
 
-import BasicPrelude
-import Data.ByteString as BS
-import qualified Data.Aeson as A
-import SwiftNav.SBP.Encoding ()
-import Test.QuickCheck
-import Test.Tasty
-import Test.Tasty.HUnit
-import Test.Tasty.QuickCheck as QC
+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
@@ -22,12 +24,12 @@
 testParse =
   testGroup "Empty Test"
     [ testCase "Empty data" $ do
-        (A.decode . A.encode $ ("dddd" :: BS.ByteString)) @?= Just ["dddd" :: String]
+        (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]
+  where prop ws = (A.decode . A.encode $ (ws :: BS.ByteString)) === Just (ws :: BS.ByteString)
 
 tests :: TestTree
 tests = testGroup "Roundtrip JSON serialization"
diff --git a/test/Test/SwiftNav/SBP/ExtEvents.hs b/test/Test/SwiftNav/SBP/ExtEvents.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/ExtEvents.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.ExtEvents
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.ExtEvents
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_ext_events.yaml"
-            moduleName = "sbp.ext_events"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "ExtEvents Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Logging.hs b/test/Test/SwiftNav/SBP/Logging.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Logging.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Logging
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Logging
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_logging.yaml"
-            moduleName = "sbp.logging"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Logging Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Navigation.hs b/test/Test/SwiftNav/SBP/Navigation.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Navigation.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Navigation
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Navigation
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_navigation.yaml"
-            moduleName = "sbp.navigation"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Navigation Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Observation.hs b/test/Test/SwiftNav/SBP/Observation.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Observation.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Observation
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Observation
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_observation.yaml"
-            moduleName = "sbp.observation"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Observation Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Piksi.hs b/test/Test/SwiftNav/SBP/Piksi.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Piksi.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Piksi
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Piksi
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_piksi.yaml"
-            moduleName = "sbp.piksi"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Piksi Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/System.hs b/test/Test/SwiftNav/SBP/System.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/System.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.System
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.System
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_system.yaml"
-            moduleName = "sbp.system"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "System Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Table.hs b/test/Test/SwiftNav/SBP/Table.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Table.hs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Test.SwiftNav.SBP.Table
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Empty Test"
-    [ testCase "Empty data" $ do
-        True @?= False
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Table Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Tracking.hs b/test/Test/SwiftNav/SBP/Tracking.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Tracking.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Test.SwiftNav.SBP.Tracking
-  ( tests
-  ) where
-
-import BasicPrelude
-import SwiftNav.SBP.Tracking
-import Test.SwiftNav.SBP.Utils
-import Test.Tasty
-import Test.Tasty.HUnit
-
-testParse :: TestTree
-testParse =
-  testGroup "Package tests"
-    [ testCase "Parsing tests" $ do
-        let filepath = "../spec/tests/yaml/swiftnav/sbp/test_tracking.yaml"
-            moduleName = "sbp.tracking"
-        val <- assertPackage filepath moduleName
-        assertBool "Fail" val
-    ]
-
-tests :: TestTree
-tests =
-  testGroup "Tracking Tests"
-    [ testParse
-    ]
diff --git a/test/Test/SwiftNav/SBP/Utils.hs b/test/Test/SwiftNav/SBP/Utils.hs
deleted file mode 100644
--- a/test/Test/SwiftNav/SBP/Utils.hs
+++ /dev/null
@@ -1,84 +0,0 @@
--- |
--- Module:      SwiftNav.SBP
--- Copyright:   Copyright (C) 2015 Swift Navigation, Inc.
--- License:     LGPL-3
--- Maintainer:  Mark Fine <dev@swiftnav.com>
--- Stability:   experimental
--- Portability: portable
---
--- A straightforward port of the testing harness stuff for libsbp's
--- Python client:
--- https://github.com/swift-nav/libsbp/blob/master/python/tests/sbp/utils.py.
--- Uses the spec'd out unit tests at
--- https://github.com/swift-nav/libsbp/tree/master/spec/yaml/swiftnav/sbp.
-
-module Test.SwiftNav.SBP.Utils
-  ( assertPackage
-  ) where
-
-import BasicPrelude
-import Data.ByteString
-import Data.Yaml.YamlLight
-
--- -- | Assert that a proper SBP parsing from a raw package of data.
--- assertSBP :: undefined -- ^ SBP message parsed from unit test's raw packet
---           -> undefined -- ^ Unit test case parsed from YAML
---           -> Bool
--- assertSBP sbp testCase = undefined
-
--- -- | Checks the field values of a parsed message for equality against
--- -- some ground truth value.
--- fieldEq :: undefined -- ^ Parsed field contents
---         -> undefined -- ^ Expected field contents
---         -> Bool
--- fieldEq p e = undefined
-
--- -- | Asserts that the parsed payload of an SBP message has the
--- -- expected field values.
--- assertMsg :: undefined -- ^ Parsed SBP message
---           -> undefined -- ^ Unit test case for this message
---           -> Bool
--- assertMsg msg testCase = undefined
-
--- -- | Asserts that a msg gets serialized back into binary with the
--- -- expected value.
--- assertMsgRoundtrip :: undefined
---                    -> undefined
---                    -> undefined
--- assertMsgRoundtrip msg rawPackage = undefined
-
--- -- | Asserts that a msg gets serialized back into JSON with the
--- -- expected value, as well as gets serialized from JSON into an
--- -- expected object.
--- assertMsgRoundtripJson :: undefined
---                        -> undefined
---                        -> undefined
--- assertMsgRoundtripJson msg rawJSON = undefined
-
--- -- | Asserts that a message materialized will get serialized into the
--- -- right JSON object.
--- assertMaterialization :: ByteString
---                       -> undefined
---                       -> undefined
---                       -> undefined
--- assertMaterialization msg sbp rawJSON = undefined
-
--- | Sanity check the package collection of tests before actually
--- running the tests.
-assertSanePackage :: ByteString
-                  -> ByteString
-                  -> Bool
-assertSanePackage pkgName pkg = undefined
-
--- | Runs unit tests for message bindings by reading a YAML unit test
--- specification, parsing a raw packet for each test, and then
--- asserting that SBP messages and parsed payloads have their intended
--- values.
-assertPackage :: String     -- ^ Filepath to unit test specifications
-              -> ByteString -- ^ Name of package to test
-              -> IO Bool
-assertPackage testFilename pkgName = do
-   pkg <- parseYamlFile testFilename
-   case pkg of
-     YMap x -> return True
-     _      -> return False
