diff --git a/bglib.cabal b/bglib.cabal
--- a/bglib.cabal
+++ b/bglib.cabal
@@ -1,49 +1,67 @@
-name:                bglib
-version:             2.0.0.0
-synopsis:            Implementation of the BGAPI serial protocol
-description:         This library implements Silicon Labs' (formerly BlueGiga)
-                     serial protocol to communicate with certain Bluetooth and
-                     Wifi products such as the BLED112 USB dongle or the BLE112
-                     and BLE113 Bluetooth Low Energy modules.
-homepage:            https://github.com/netom/bgapi#readme
-license:             MIT
-license-file:        LICENSE
-author:              Tamas Fabian
-maintainer:          giganetom@gmail.com
-copyright:           MIT
-category:            library
-build-type:          Simple
-extra-source-files:  README.md
-cabal-version:       >=1.10
+cabal-version: 1.12
 
-library
-  hs-source-dirs:      src
-  ghc-options:         -Wall
-  exposed-modules:     BGLib.Commands
-                     , BGLib.Types
-  build-depends:       base >= 4.7 && < 5
-                     , binary
-                     , bytestring
-                     , monad-loops
-                     , mtl
-                     , serialport
-                     , stm
-  default-language:    Haskell2010
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 0876ee6ed8f697bada423cc7990b1db5664acfcc57ed2ba9b4e740c272439747
 
-executable bgapitest
-  hs-source-dirs:      examples
-  main-is:             bgapitest.hs
-  ghc-options:         -Wall -threaded
-  build-depends:       base >= 4.7 && < 5
-                     , async
-                     , bglib
-                     , bytestring
-                     , mtl
-                     , optparse-applicative
-                     , serialport
-                     , stm
-  default-language:    Haskell2010
+name:           bglib
+version:        3.0.0.0
+synopsis:       Implementation of the BGAPI serial protocol
+description:    This library implements Silicon Labs' (formerly BlueGiga) serial protocol to communicate with certain Bluetooth and Wifi products such as the BLED112 USB dongle or the BLE112 and BLE113 Bluetooth Low Energy modules.
+category:       library
+homepage:       https://github.com/netom/bgapi#readme
+bug-reports:    https://github.com/netom/bgapi/issues
+author:         Tamas Fabian
+maintainer:     giganetom@gmail.com
+copyright:      2019 Tamas Fabian
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    LICENSE
 
 source-repository head
-  type:     git
-  location: https://github.com/netom/haskell-bglib
+  type: git
+  location: https://github.com/netom/bgapi
+
+library
+  exposed-modules:
+      BGLib.Commands
+      BGLib.Types
+  other-modules:
+      Paths_bglib
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base >=4.7 && <5
+    , binary
+    , bytestring
+    , monad-loops
+    , mtl
+    , serialport
+    , stm
+  default-language: Haskell2010
+
+executable bglibtest
+  main-is: bglibtest.hs
+  other-modules:
+      Paths_bglib
+  hs-source-dirs:
+      examples
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      async
+    , base >=4.7 && <5
+    , bglib
+    , binary
+    , bytestring
+    , monad-loops
+    , mtl
+    , optparse-applicative
+    , serialport
+    , stm
+  default-language: Haskell2010
diff --git a/examples/bgapitest.hs b/examples/bgapitest.hs
deleted file mode 100644
--- a/examples/bgapitest.hs
+++ /dev/null
@@ -1,189 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-
-import           BGLib.Commands
-import           BGLib.Types
-import           Control.Concurrent
-import           Control.Concurrent.Async
-import           Control.Concurrent.STM
-import           Control.Monad.IO.Class
-import           Control.Monad.Reader
-import qualified Data.ByteString.Char8 as BSS
-import           Data.Semigroup ((<>))
-import           Options.Applicative
-import           Prelude hiding (print, putStrLn)
-import qualified Prelude as P
-import           System.Exit
-import           System.IO hiding (print, putStrLn)
-
--- This is our monad stack, most of the application runs inside this.
-type AppM env a = ReaderT env IO a
-
--- We store the command line options here
-data AppOptions = AppOptions
-    { appOptSerialPort :: String
-    , appOptDebug      :: Bool
-    }
-
--- The data structure will be our "env", the environment stored in the
--- ReaderT env IO monad stack
-data App = App
-    { appOptions :: AppOptions
-    , appHandle  :: Handle
-    , appBGChan  :: TChan BgPacket
-    }
-
--- Instances for our environment to properly serve the library
--- functions.
-
-instance HasHandle App where
-    getHandle = appHandle
-
-instance HasBGChan App where
-    getBGChan = appBGChan
-    updateBGChan chan app = app{ appBGChan = chan }
-
-instance HasDebug App where
-    getDebug = appOptDebug . appOptions
-
--- Command line parser
-optParser :: Parser AppOptions
-optParser = AppOptions
-        <$> argument str 
-            (  metavar "PORT"
-            <> help "Serial port" )
-        <*> switch
-            ( long "debug"
-            <> short 'd'
-            <> help "Whether to be quiet" )
-
--- Takes an environment and runs a program with it inside the IO monad.
-execApp :: env -> AppM env a -> IO a
-execApp = flip runReaderT
-
--- RUns a program in a new thread inside out AppM stack
-forkApp :: AppM env () -> AppM env ThreadId
-forkApp act = do
-    env <- ask
-    liftIO $ forkIO $ execApp env act
-
--- Can be used to wait for an event handler to return a value.
--- Waiting for a specific BLE device advertisement to appear for
--- example. Timeout is in microseconds.
-withTimeOut :: Int -> AppM env a -> AppM env (Maybe a)
-withTimeOut t a = do
-    env <- ask
-    res <- liftIO $ race (threadDelay t) (execApp env a)
-    return $ case res of
-        Left () -> Nothing
-        Right x -> Just x
-
--- A few lifted functions
-
-putStrLn :: MonadIO m => String -> m ()
-putStrLn = liftIO . P.putStrLn
-
-print :: (MonadIO m, Show a) => a -> m ()
-print = liftIO . P.print
-
-main :: IO ()
-main = do
-    -- Run the command line parser
-    appOpts <- execParser $
-        info
-            ( optParser <**> helper )
-            (  fullDesc
-            <> progDesc "Execute a short battery of test on port PORT"
-            <> header "bgapitest - a short text / example for haskell-bglib"
-            )
-
-    -- Build the application environment
-    -- With certain hardware, you probably want to set baud rate,
-    -- stop and parity bits. You can extract the file descriptor
-    -- from the Handle and use System.Posix.Terminal functions
-    -- to do that, or use the Serial library to open a serial port
-    -- and build a Handle out of the file descriptor of the serial
-    -- port.
-    app <- App
-        <$> return appOpts
-        <*> openFile (appOptSerialPort appOpts) ReadWriteMode
-        <*> atomically newBroadcastTChan
-
-    -- Run the application
-    execApp app $ do
-
-        -- Register an event handler for protocol errors.
-        -- Event handlers are blocking. We use forkApp to make it
-        -- "run in the background".
-        -- The command 'packetBlock' creates a barrier, so new packets
-        -- after this are guaranteed to be picked up by the event handlers
-        -- in the block.
-        packetBlock_ $ forkApp $ evtSystemProtocolError $ \reason -> do
-            liftIO $ die $ "*** PROTOCOL ERROR " ++ show reason
-
-        -- Starts a thread that keeps reading packets from the serial port,
-        -- pushing them to the broadcast TChan
-        startPacketReader
-
-        putStrLn "Running hello"
-        systemHello
-        putStrLn "If you can read this, we're fine. :)"
-        putStrLn ""
-
-        putStrLn "Getting system information:"
-        (major, minor, patch, build, llVersion, protocolVersion, hw) <- systemGetInfo
-        putStrLn $ "Major version:      " ++ show major
-        putStrLn $ "Minor version:      " ++ show minor
-        putStrLn $ "Patch version:      " ++ show patch
-        putStrLn $ "Build Version:      " ++ show build
-        putStrLn $ "Link Layer version: " ++ show llVersion
-        putStrLn $ "Protocol version:   " ++ show protocolVersion
-        putStrLn $ "Hardware version:   " ++ show hw
-        putStrLn ""
-
-        putStrLn "We should get a \"not connected\" error:"
-        attclientAttributeWrite 0 0 "e" >>= print
-        putStrLn ""
-
-        putStrLn "Getting Bluetooth Address:"
-        systemAddressGet >>= print
-        putStrLn ""
-
-        putStrLn "Running some encryption-decription tests"
-        putStrLn ""
-
-        let aeskey = "abcdefgh12345678"
-        putStrLn $ "Setting AES key to " ++ aeskey
-        systemAesSetkey $ toUInt8Array $ BSS.pack $ aeskey
-        putStrLn ""
-
-        let plaintext = "This is plain"
-        putStrLn $ "Encrypting: " ++ plaintext
-        encrypted <- systemAesEncrypt $ toUInt8Array $ BSS.pack $ plaintext
-        putStrLn $ "Encrypted: " ++ bsShowHex (fromUInt8Array encrypted)
-        putStrLn ""
-
-        putStrLn $ "Decrypting"
-        decrypted <- systemAesDecrypt encrypted
-        putStrLn $ "Decrypted: " ++ BSS.unpack (fromUInt8Array decrypted)
-        putStrLn ""
-        
-        packetBlock_ $ do
-            _ <- gapDiscover GapDiscoverGeneric
-
-            -- Register an event handler for scan responses. Can be done anywhere.
-            -- The handler forks a thread that runs forever, and can be terminated
-            -- later if necessary.
-            _ <- withTimeOut 5000000 $ evtGapScanResponse $ \rssi _ sender _ _ _ -> do
-                    print rssi
-                    print sender
-                    putStrLn ""
-                    return $ Nothing -- We'd like to listen to further events.
-
-            gapEndProcedure
-
-        putStrLn "Let's cause trouble:"
-        h <- askHandle
-        _ <- liftIO $ BSS.hPut h "a"
-        liftIO $ threadDelay 2000000
diff --git a/examples/bglibtest.hs b/examples/bglibtest.hs
new file mode 100644
--- /dev/null
+++ b/examples/bglibtest.hs
@@ -0,0 +1,188 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+import           BGLib.Commands
+import           BGLib.Types
+import           Control.Concurrent
+import           Control.Concurrent.Async
+import           Control.Concurrent.STM
+import           Control.Monad.IO.Class
+import           Control.Monad.Reader
+import qualified Data.ByteString.Char8 as BSS
+import           Options.Applicative
+import           Prelude hiding (print, putStrLn)
+import qualified Prelude as P
+import           System.Exit
+import           System.Hardware.Serialport
+
+-- This is our monad stack, most of the application runs inside this.
+type AppM env a = ReaderT env IO a
+
+-- We store the command line options here
+data AppOptions = AppOptions
+    { appOptSerialPort :: String
+    , appOptDebug      :: Bool
+    }
+
+-- The data structure will be our "env", the environment stored in the
+-- ReaderT env IO monad stack
+data App = App
+    { appOptions    :: AppOptions
+    , appSerialPort :: SerialPort
+    , appBGChan     :: TChan BgPacket
+    }
+
+-- Instances for our environment to properly serve the library
+-- functions.
+
+instance HasSerialPort App where
+    getSerialPort = appSerialPort
+
+instance HasBGChan App where
+    getBGChan = appBGChan
+    updateBGChan chan app = app{ appBGChan = chan }
+
+instance HasDebug App where
+    getDebug = appOptDebug . appOptions
+
+-- Command line parser
+optParser :: Parser AppOptions
+optParser = AppOptions
+        <$> argument str 
+            (  metavar "PORT"
+            <> help "Serial port" )
+        <*> switch
+            ( long "debug"
+            <> short 'd'
+            <> help "Whether to be quiet" )
+
+-- Takes an environment and runs a program with it inside the IO monad.
+execApp :: env -> AppM env a -> IO a
+execApp = flip runReaderT
+
+-- RUns a program in a new thread inside out AppM stack
+forkApp :: AppM env () -> AppM env ThreadId
+forkApp act = do
+    env <- ask
+    liftIO $ forkIO $ execApp env act
+
+-- Can be used to wait for an event handler to return a value.
+-- Waiting for a specific BLE device advertisement to appear for
+-- example. Timeout is in microseconds.
+withTimeOut :: Int -> AppM env a -> AppM env (Maybe a)
+withTimeOut t a = do
+    env <- ask
+    res <- liftIO $ race (threadDelay t) (execApp env a)
+    return $ case res of
+        Left () -> Nothing
+        Right x -> Just x
+
+-- A few lifted functions
+
+putStrLn :: MonadIO m => String -> m ()
+putStrLn = liftIO . P.putStrLn
+
+print :: (MonadIO m, Show a) => a -> m ()
+print = liftIO . P.print
+
+main :: IO ()
+main = do
+    -- Run the command line parser
+    appOpts <- execParser $
+        info
+            ( optParser <**> helper )
+            (  fullDesc
+            <> progDesc "Execute a short battery of test on port PORT"
+            <> header "bgapitest - a short text / example for haskell-bglib"
+            )
+
+    -- Build the application environment
+    -- With certain hardware, you probably want to set baud rate,
+    -- stop and parity bits. You can extract the file descriptor
+    -- from the Handle and use System.Posix.Terminal functions
+    -- to do that, or use the Serial library to open a serial port
+    -- and build a Handle out of the file descriptor of the serial
+    -- port.
+    app <- App
+        <$> return appOpts
+        <*> openSerial (appOptSerialPort appOpts) defaultSerialSettings { commSpeed = CS115200 }
+        <*> atomically newBroadcastTChan
+
+    -- Run the application
+    execApp app $ do
+
+        -- Register an event handler for protocol errors.
+        -- Event handlers are blocking. We use forkApp to make it
+        -- "run in the background".
+        -- The command 'packetBlock' creates a barrier, so new packets
+        -- after this are guaranteed to be picked up by the event handlers
+        -- in the block.
+        packetBlock_ $ forkApp $ evtSystemProtocolError $ \reason -> do
+            liftIO $ die $ "*** PROTOCOL ERROR " ++ show reason
+
+        -- Starts a thread that keeps reading packets from the serial port,
+        -- pushing them to the broadcast TChan
+        startPacketReader $ \err -> fail err
+
+        putStrLn "Running hello"
+        systemHello
+        putStrLn "If you can read this, we're fine. :)"
+        putStrLn ""
+
+        putStrLn "Getting system information:"
+        (major, minor, patch, build, llVersion, protocolVersion, hw) <- systemGetInfo
+        putStrLn $ "Major version:      " ++ show major
+        putStrLn $ "Minor version:      " ++ show minor
+        putStrLn $ "Patch version:      " ++ show patch
+        putStrLn $ "Build Version:      " ++ show build
+        putStrLn $ "Link Layer version: " ++ show llVersion
+        putStrLn $ "Protocol version:   " ++ show protocolVersion
+        putStrLn $ "Hardware version:   " ++ show hw
+        putStrLn ""
+
+        putStrLn "We should get a \"not connected\" error:"
+        attclientAttributeWrite 0 0 "e" >>= print
+        putStrLn ""
+
+        putStrLn "Getting Bluetooth Address:"
+        systemAddressGet >>= print
+        putStrLn ""
+
+        putStrLn "Running some encryption-decription tests"
+        putStrLn ""
+
+        let aeskey = "abcdefgh12345678"
+        putStrLn $ "Setting AES key to " ++ aeskey
+        systemAesSetkey $ toUInt8Array $ BSS.pack $ aeskey
+        putStrLn ""
+
+        let plaintext = "This is plain"
+        putStrLn $ "Encrypting: " ++ plaintext
+        encrypted <- systemAesEncrypt $ toUInt8Array $ BSS.pack $ plaintext
+        putStrLn $ "Encrypted: " ++ bsShowHex (fromUInt8Array encrypted)
+        putStrLn ""
+
+        putStrLn $ "Decrypting"
+        decrypted <- systemAesDecrypt encrypted
+        putStrLn $ "Decrypted: " ++ BSS.unpack (fromUInt8Array decrypted)
+        putStrLn ""
+        
+        packetBlock_ $ do
+            _ <- gapDiscover GapDiscoverGeneric
+
+            -- Register an event handler for scan responses. Can be done anywhere.
+            -- The handler forks a thread that runs forever, and can be terminated
+            -- later if necessary.
+            _ <- withTimeOut 5000000 $ evtGapScanResponse $ \rssi _ sender _ _ _ -> do
+                    print rssi
+                    print sender
+                    putStrLn ""
+                    return $ Nothing -- We'd like to listen to further events.
+
+            gapEndProcedure
+
+        putStrLn "Let's cause trouble:"
+        h <- askSerialPort
+        _ <- liftIO $ send h "a"
+        liftIO $ threadDelay 2000000
diff --git a/src/BGLib/Commands.hs b/src/BGLib/Commands.hs
--- a/src/BGLib/Commands.hs
+++ b/src/BGLib/Commands.hs
@@ -152,39 +152,50 @@
 import           Data.Binary
 import qualified Data.ByteString.Lazy as BSL
 import qualified Data.ByteString as BSS
-import           System.IO
+import           System.Hardware.Serialport
 
+-- Read an exact amount of bytes from a serial port
+readData :: SerialPort -> Int -> IO BSS.ByteString
+readData s n = do
+    bs <- recv s n
+    let received = BSS.length bs
+    if  received < n
+        then BSS.append bs <$> readData s ( n - received )
+        else return bs
+
+-- Write all the data to a serial port
+writeData :: SerialPort -> BSS.ByteString -> IO ()
+writeData s bs = do
+    sent <- send s bs
+    if sent < BSS.length bs
+        then writeData s ( BSS.drop sent bs )
+        else return ()
+
 -- Write the BgPacket to the Handle in env asked from the MonadReader
-writeBGPacket :: (MonadIO m, MonadReader env m, HasHandle env, HasDebug env) => BgPacket -> m ()
+writeBGPacket :: (MonadIO m, MonadReader env m, HasSerialPort env, HasDebug env) => BgPacket -> m ()
 writeBGPacket p = do
-    h <- askHandle
+    s <- askSerialPort
     dbg <- askDebug
     liftIO $ do
         let packetBS = BSL.toStrict $ encode p
         when dbg $ do
             putStr "[DEBUG] WRITE: "
             putStrLn $ show p
-        BSS.hPut h packetBS
+        writeData s packetBS
         return ()
-    
-readData :: Handle -> Int -> IO BSS.ByteString
-readData h n = do
-    bs <- BSS.hGet h n
-    if  BSS.length bs == n
-        then return bs
-        else fail "Could not read enough data"
 
 -- Read one BgPacket from a Handle
-readBGPacket :: Bool -> Handle -> IO (Maybe BgPacket)
+readBGPacket :: Bool -> SerialPort -> IO (Either String BgPacket)
 readBGPacket dbg h = do
     bsHeader <- readData h 4
     let eHeader = decodeOrFail $ BSL.fromStrict bsHeader
 
     case eHeader of
         Left _ -> do
+            let err = "could not decode header: " ++ bsShowHex bsHeader
             when dbg $ do
-                putStr $ "[DEBUG] ERROR: decoding header: " ++ bsShowHex bsHeader
-            return Nothing
+                putStr $ "[DEBUG] ERROR: " ++ err
+            return $ Left err
         Right (_, _, bgpHeader@BgPacketHeader{..}) -> do
             bsPayload <- readData h (fromIntegral bghLength)
             let bgpPayload = toBgPayload bsPayload
@@ -192,17 +203,19 @@
             when dbg $ do
                 putStr "[DEBUG]  READ: "
                 putStrLn $ show p
-            return $ Just p
+            return $ Right p
 
 -- Launch a thread that reads packets and sends them down a TChan BgPacket
-startPacketReader :: (MonadIO m, MonadReader env m, HasBGChan env, HasHandle env, HasDebug env) => m () 
-startPacketReader = do
+startPacketReader :: (MonadIO m, MonadReader env m, HasBGChan env, HasSerialPort env, HasDebug env) => (String -> IO ()) -> m () 
+startPacketReader errorHandler = do
     c <- askBGChan
-    h <- askHandle
+    h <- askSerialPort
     dbg <- askDebug
     _ <- liftIO $ forkIO $ forever $ do
-        Just p <- readBGPacket dbg h
-        atomically $ writeTChan c p
+        packetOrErr <- readBGPacket dbg h
+        case packetOrErr of
+            Left err -> errorHandler err
+            Right p -> atomically $ writeTChan c p
     return ()
 
 -- Waits for any BgPacket to appear on the TChan
@@ -218,13 +231,13 @@
         return $ if bgHeaderMatches mt tt cc cid bgpHeader then Just p else Nothing
 
 -- eXecute a Command, don't wait for answer
-xCmd' :: (MonadIO m, MonadReader env m, HasHandle env, HasDebug env, Binary a ) => BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> a -> m ()
+xCmd' :: (MonadIO m, MonadReader env m, HasSerialPort env, HasDebug env, Binary a ) => BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> a -> m ()
 xCmd' mt tt cc cid inp = do
     let inpBS = BSL.toStrict $ encode inp
     writeBGPacket $ BgPacket (BgPacketHeader mt tt (fromIntegral $ BSS.length inpBS) cc cid) (toBgPayload inpBS)
 
 -- Execute a command, wait for the appropriate answer
-xCmd :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env, Binary a, Binary b) => BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> a -> m b
+xCmd :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env, Binary a, Binary b) => BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> a -> m b
 xCmd mt tt cc cid inp = do
     -- We need to duplicate the channel BEFORE sending the command, so we don't miss the answer by accident
     chan <- askDupBGChan
@@ -244,7 +257,7 @@
 -- independent threads, or use race with threadDelay to wait for an
 -- event with a timeout.
 handlePacket
-    :: (Binary a, MonadIO m, MonadReader env m, HasHandle env, HasBGChan env)
+    :: (Binary a, MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env)
     => BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> (a -> m (Maybe b)) -> m b
 handlePacket mt tt cc cid handler = do
     chan <- askBGChan
@@ -292,97 +305,97 @@
 -----------------------------------------------------------------------
 
 attclientAttributeWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientAttributeWrite = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x05
 
 attclientExecuteWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> Bool -> m (UInt8, BGResult)
 attclientExecuteWrite = curry $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x0a
 
 attclientFindByTypeValue
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientFindByTypeValue = curry5 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x00
 
 attclientFindInformation
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> m (UInt8, BGResult)
 attclientFindInformation = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x03
 
 attclientIndicateConfirm
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m BGResult
 attclientIndicateConfirm = xCmd BgMsgCR BgBlue BgClsAttributeClient 0x07
 
 attclientPrepareWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientPrepareWrite = curry4 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x09
 
 attclientReadByGroupType
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientReadByGroupType = curry4 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x01
 
 attclientReadByHandle
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> m (UInt8, BGResult)
 attclientReadByHandle = curry $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x04
 
 attclientReadByType
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientReadByType = curry4 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x02
 
 attclientReadLong
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> m (UInt8, BGResult)
 attclientReadLong = curry $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x08
 
 attclientReadMultiple
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8Array -> m (UInt8, BGResult)
 attclientReadMultiple = curry $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x0b
 
 attclientWriteCommand
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt8Array -> m (UInt8, BGResult)
 attclientWriteCommand = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeClient 0x06
 
 evtAttclientAttributeValue
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> UInt8 -> UInt8Array -> m (Maybe a)) -> m a
 evtAttclientAttributeValue
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x05 . uncurry4
 
 evtAttclientFindInformationFound
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> UInt8Array -> m (Maybe a)) -> m a
 evtAttclientFindInformationFound
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x04 . uncurry3
 
 evtAttclientGroupFound
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> UInt16 -> UInt8Array -> m (Maybe a)) -> m a
 evtAttclientGroupFound
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x02 . uncurry4
 
 evtAttclientIndicated
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> m (Maybe a)) -> m a
 evtAttclientIndicated
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x00 . uncurry
 
 evtAttclientProcedureCompleted
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> BGResult -> UInt16 -> m (Maybe a)) -> m a
 evtAttclientProcedureCompleted
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x01 . uncurry3
 
 evtAttclientReadMultipleResponse
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8Array -> m (Maybe a)) -> m a
 evtAttclientReadMultipleResponse
     = handlePacket BgMsgEvent BgBlue BgClsAttributeClient 0x06 . uncurry
@@ -392,49 +405,49 @@
 -----------------------------------------------------------------------
 
 attributesRead
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt16 -> m (UInt16, UInt16, BGResult, UInt8Array)
 attributesRead = curry $ xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x01
 
 attributesReadType
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> m (UInt16, BGResult, UInt8Array)
 attributesReadType = xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x02
 
 attributesSend
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt8Array -> m BGResult
 attributesSend = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x05
 
 attributesUserReadResponse
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8Array -> m ()
 attributesUserReadResponse = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x03
 
 attributesUserWriteResponse
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m ()
 attributesUserWriteResponse = curry $ xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x04
 
 attributesWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt8 -> UInt8Array -> m BGResult
 attributesWrite = curry3 $ xCmd BgMsgCR BgBlue BgClsAttributeDatabase 0x00
 
 evtAttributesStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt16 -> UInt8 -> m (Maybe a)) -> m a
 evtAttributesStatus
     = handlePacket BgMsgEvent BgBlue BgClsAttributeDatabase 0x02 . uncurry
 
 evtAttributesUserReadRequest
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> UInt16 -> UInt8 -> m (Maybe a)) -> m a
 evtAttributesUserReadRequest
     = handlePacket BgMsgEvent BgBlue BgClsAttributeDatabase 0x01 . uncurry4
 
 evtAttributesValue
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> UInt16 -> UInt16 -> UInt8Array -> m (Maybe a)) -> m a
 evtAttributesValue
     = handlePacket BgMsgEvent BgBlue BgClsAttributeDatabase 0x00 . uncurry5
@@ -444,64 +457,64 @@
 -----------------------------------------------------------------------
 
 connectionChannelMapGet
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m (UInt8, UInt8Array)
 connectionChannelMapGet = xCmd BgMsgCR BgBlue BgClsConnection 0x04
 
 connectionChannelMapSet
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8Array -> m (UInt8, BGResult)
 connectionChannelMapSet = curry $ xCmd BgMsgCR BgBlue BgClsConnection 0x05
 
 connectionDisconnect
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m (UInt8, BGResult)
 connectionDisconnect = xCmd BgMsgCR BgBlue BgClsConnection 0x00
 
 connectionGetRssi
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m (UInt8, Int8)
 connectionGetRssi = xCmd BgMsgCR BgBlue BgClsConnection 0x01
 
 connectionGetStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m UInt8
 connectionGetStatus = xCmd BgMsgCR BgBlue BgClsConnection 0x07
 
 connectionSlaveLatencyDisable
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m BGResult
 connectionSlaveLatencyDisable = xCmd BgMsgCR BgBlue BgClsConnection 0x09
 
 connectionUpdate
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt16 -> UInt16 -> UInt16 -> UInt16 -> m (UInt8, BGResult)
 connectionUpdate = curry5 $ xCmd BgMsgCR BgBlue BgClsConnection 0x02
 
 connectionVersionUpdate
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m (UInt8, BGResult)
 connectionVersionUpdate = xCmd BgMsgCR BgBlue BgClsConnection 0x03
 
 evtConnectionDisconnected
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> BGResult -> m (Maybe a)) -> m a
 evtConnectionDisconnected
     = handlePacket BgMsgEvent BgBlue BgClsConnection 0x04 . uncurry
 
 evtConnectionFeatureInd
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8Array -> m (Maybe a)) -> m a
 evtConnectionFeatureInd = handlePacket BgMsgEvent BgBlue BgClsConnection 0x02 . uncurry
 
 evtConnectionStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> BdAddr -> UInt8 -> UInt16 -> UInt16 -> UInt16 -> UInt8 -> m (Maybe a))
     -> m a
 evtConnectionStatus = handlePacket BgMsgEvent BgBlue BgClsConnection 0x00 . uncurry8
 
 evtConnectionVersionInd
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> UInt16 -> UInt16 -> m (Maybe a)) -> m a
 evtConnectionVersionInd = handlePacket BgMsgEvent BgBlue BgClsConnection 0x01 . uncurry4
 
@@ -510,73 +523,73 @@
 -----------------------------------------------------------------------
 
 gapConnectDirect
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => BdAddr -> GapAddressType -> UInt16 -> UInt16 -> UInt16 -> UInt16 -> m (BGResult, UInt8)
 gapConnectDirect = curry6 $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x03
 
 gapConnectSelective
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt16 -> UInt16 -> UInt16 -> m (BGResult, UInt8)
 gapConnectSelective = curry4 $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x05
 
 gapDiscover
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => GapDiscoverMode -> m UInt16
 gapDiscover = xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x02
 
 gapEndProcedure
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt16
 gapEndProcedure = xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x04 ()
 
 gapSetAdvData
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8Array -> m BGResult
 gapSetAdvData = curry $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x09
 
 gapSetAdvParameters
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt16 -> UInt8 -> m BGResult
 gapSetAdvParameters = curry3 $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x08
 
 gapSetDirectedConnectableMode
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => BdAddr -> GapAddressType -> m BGResult
 gapSetDirectedConnectableMode = curry $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x0a
 
 gapSetFiltering
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => GapScanPolicy -> GapAdvPolicy -> UInt8 -> m BGResult
 gapSetFiltering = curry3 $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x06
 
 gapSetInitiatingConParameters
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt16 -> m BGResult
 gapSetInitiatingConParameters = curry $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x0b
 
 gapSetMode
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => GapDiscoverableMode -> GapConnectableMode -> m BGResult
 gapSetMode = curry $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x01
 
 gapSetNonresolvableAddress
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => BdAddr -> m BGResult
 gapSetNonresolvableAddress = xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x0c
 
 gapSetPrivacyFlags
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m ()
 gapSetPrivacyFlags = curry $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x00
 
 gapSetScanParameters
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt16 -> UInt8 -> m BGResult
 gapSetScanParameters = curry3 $ xCmd BgMsgCR BgBlue BgClsGenericAccessProfile 0x07
 
 -- Register an event handler for GAP scan responses
 evtGapScanResponse
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (Int8 -> UInt8 -> BdAddr -> GapAddressType -> UInt8 -> UInt8Array -> m (Maybe a)) -> m a
 evtGapScanResponse
     = handlePacket BgMsgEvent BgBlue BgClsGenericAccessProfile 0x00 . uncurry6
@@ -586,140 +599,140 @@
 -----------------------------------------------------------------------
 
 hardwareAdcRead
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8 -> m BGResult
 hardwareAdcRead = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x02
 
 hardwareAnalogComparatorConfigIrq
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m BGResult
 hardwareAnalogComparatorConfigIrq = xCmd BgMsgCR BgBlue BgClsHardware 0x12
 
 hardwareAnalogComparatorEnable
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m ()
 hardwareAnalogComparatorEnable = xCmd BgMsgCR BgBlue BgClsHardware 0x10
 
 hardwareAnalogComparatorRead
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m (BGResult, UInt8)
 hardwareAnalogComparatorRead = xCmd BgMsgCR BgBlue BgClsHardware 0x11 ()
 
 hardwareGetTimestamp
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt32
 hardwareGetTimestamp = xCmd BgMsgCR BgBlue BgClsHardware 0x16 ()
 
 hardwareI2cRead
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> Bool -> UInt8 -> m (UInt16, UInt8Array)
 hardwareI2cRead = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x0a
 
 hardwareI2cWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> Bool -> UInt8Array -> m UInt8
 hardwareI2cWrite = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x0b
 
 hardwareIoPortConfigDirection
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m BGResult
 hardwareIoPortConfigDirection = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x03
 
 hardwareIoPortConfigFunction
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m BGResult
 hardwareIoPortConfigFunction = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x04
 
 hardwareIoPortConfigIrq
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> Bool -> m BGResult
 hardwareIoPortConfigIrq = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x00
 
 hardwareIoPortConfigPull
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> Bool -> m BGResult
 hardwareIoPortConfigPull = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x05
 
 hardwareIoPortIrqDirection
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> Bool -> m BGResult
 hardwareIoPortIrqDirection = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x0f
 
 hardwareIoPortIrqEnable
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m BGResult
 hardwareIoPortIrqEnable = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x0e
 
 hardwareIoPortRead
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m (BGResult, UInt8, UInt8)
 hardwareIoPortRead = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x07
 
 hardwareIoPortWrite
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8 -> m BGResult
 hardwareIoPortWrite = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x06
 
 hardwareSetRxgain
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m ()
 hardwareSetRxgain = xCmd BgMsgCR BgBlue BgClsHardware 0x13
 
 hardwareSetSoftTimer
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt32 -> UInt8 -> Bool -> m BGResult
 hardwareSetSoftTimer = curry3 $ xCmd BgMsgCR BgBlue BgClsHardware 0x01
 
 hardwareSetTxpower
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m ()
 hardwareSetTxpower = xCmd BgMsgCR BgBlue BgClsHardware 0x0c
 
 hardwareSleepEnable
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m BGResult
 hardwareSleepEnable = xCmd BgMsgCR BgBlue BgClsHardware 0x15
 
 hardwareSpiConfig
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> Bool -> Bool -> Bool -> UInt8 -> UInt8 -> m BGResult
 hardwareSpiConfig = curry6 $ xCmd BgMsgCR BgBlue BgClsHardware 0x08
 
 hardwareSpiTransfer
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8Array -> m (BGResult, UInt8, UInt8Array)
 hardwareSpiTransfer = curry $ xCmd BgMsgCR BgBlue BgClsHardware 0x09
 
 hardwareTimerComparator
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8 -> UInt16 -> m BGResult
 hardwareTimerComparator = curry4 $ xCmd BgMsgCR BgBlue BgClsHardware 0x0d
 
 hardwareUsbEnable
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m BGResult
 hardwareUsbEnable = xCmd BgMsgCR BgBlue BgClsHardware 0x14
 
 evtHardwareAdcResult
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt16 -> m (Maybe a)) -> m a
 evtHardwareAdcResult
     = handlePacket BgMsgEvent BgBlue BgClsHardware 0x02 . uncurry
 
 evtHardwareAnalogComparatorStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt32 -> UInt8 -> m (Maybe a)) -> m a
 evtHardwareAnalogComparatorStatus
     = handlePacket BgMsgEvent BgBlue BgClsHardware 0x03 . uncurry
 
 evtHardwareIoPortStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt32 -> UInt8 -> UInt8 -> UInt8 -> m (Maybe a)) -> m a
 evtHardwareIoPortStatus
     = handlePacket BgMsgEvent BgBlue BgClsHardware 0x00 . uncurry4
 
 evtHardwareSoftTimer
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> m (Maybe a)) -> m a
 evtHardwareSoftTimer
     = handlePacket BgMsgEvent BgBlue BgClsHardware 0x01
@@ -729,52 +742,52 @@
 -----------------------------------------------------------------------
 
 flashErasePage
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m BGResult
 flashErasePage = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x06
 
 flashPsDefrag
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m ()
 flashPsDefrag = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x00 ()
 
 flashPsDump
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m ()
 flashPsDump = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x01 ()
 
 flashPsEraseAll
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m ()
 flashPsEraseAll = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x02 ()
 
 flashPsErase
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> m ()
 flashPsErase = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x05
 
 flashPsLoad
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> m (BGResult, UInt8Array)
 flashPsLoad = xCmd BgMsgCR BgBlue BgClsPersistentStore 0x04
 
 flashPsSave
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt16 -> UInt8Array -> m BGResult
 flashPsSave = curry $ xCmd BgMsgCR BgBlue BgClsPersistentStore 0x03
 
 flashReadData
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt32 -> UInt8 -> m UInt8Array
 flashReadData = curry $ xCmd BgMsgCR BgBlue BgClsPersistentStore 0x08
 
 flashWriteData
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt32 -> UInt8Array -> m BGResult
 flashWriteData = curry $ xCmd BgMsgCR BgBlue BgClsPersistentStore 0x07
 
 evtFlashPsKey
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt16 -> UInt8Array -> m (Maybe a)) -> m a
 evtFlashPsKey
     = handlePacket BgMsgEvent BgBlue BgClsPersistentStore 0x00 . uncurry
@@ -784,70 +797,70 @@
 -----------------------------------------------------------------------
 
 smDeleteBonding
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m BGResult
 smDeleteBonding = xCmd BgMsgCR BgBlue BgClsSecurityManager 0x02
 
 smEncryptStart
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> Bool -> m (UInt8, BGResult)
 smEncryptStart = curry $ xCmd BgMsgCR BgBlue BgClsSecurityManager 0x00
 
 smGetBonds
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt8
 smGetBonds = xCmd BgMsgCR BgBlue BgClsSecurityManager 0x05 ()
 
 smPasskeyEntry
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt32 -> m BGResult
 smPasskeyEntry = curry $ xCmd BgMsgCR BgBlue BgClsSecurityManager 0x04
 
 setBondableMode
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m ()
 setBondableMode = xCmd BgMsgCR BgBlue BgClsSecurityManager 0x01
 
 smSetOobData
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8Array -> m ()
 smSetOobData = xCmd BgMsgCR BgBlue BgClsSecurityManager 0x06
 
 smSetPairingDistributionKeys
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m BGResult
 smSetPairingDistributionKeys = curry $ xCmd BgMsgCR BgBlue BgClsSecurityManager 0x08
 
 smSetParameters
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> UInt8 -> SMIOCapabilities -> m ()
 smSetParameters = curry3 $ xCmd BgMsgCR BgBlue BgClsSecurityManager 0x03
 
 smWhitelistBonds
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m (BGResult, UInt8)
 smWhitelistBonds = xCmd BgMsgCR BgBlue BgClsSecurityManager 0x07 ()
 
 evtSmBondingFail
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> BGResult -> m (Maybe a)) -> m a
 evtSmBondingFail
     = handlePacket BgMsgEvent BgBlue BgClsSecurityManager 0x01 . uncurry
 
 evtSmBondStatus
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> Bool -> UInt8 -> m (Maybe a)) -> m a
 evtSmBondStatus
     = handlePacket BgMsgEvent BgBlue BgClsSecurityManager 0x04 . uncurry4
 
 evtSmPasskeyDisplay
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt32 -> m (Maybe a)) -> m a
 evtSmPasskeyDisplay
     = handlePacket BgMsgEvent BgBlue BgClsSecurityManager 0x02 . uncurry
 
 evtSmPasskeyRequest
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> m (Maybe a)) -> m a
 evtSmPasskeyRequest
     = handlePacket BgMsgEvent BgBlue BgClsSecurityManager 0x03
@@ -857,133 +870,133 @@
 -----------------------------------------------------------------------
 
 systemAddressGet
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m BdAddr
 systemAddressGet = xCmd BgMsgCR BgBlue BgClsSystem 0x02 ()
 
 systemAesDecrypt
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8Array -> m UInt8Array
 systemAesDecrypt = xCmd BgMsgCR BgBlue BgClsSystem 0x11
 
 systemAesEncrypt
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8Array -> m UInt8Array
 systemAesEncrypt = xCmd BgMsgCR BgBlue BgClsSystem 0x10
 
 systemAesSetkey
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8Array -> m ()
 systemAesSetkey = xCmd BgMsgCR BgBlue BgClsSystem 0x0f
 
 systemDelayReset
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => RebootMode -> UInt16 -> m ()
 systemDelayReset = curry $ xCmd' BgMsgCR BgBlue BgClsSystem 0x14
 
 systemEndpointRx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> m (BGResult, UInt8Array)
 systemEndpointRx = curry $ xCmd BgMsgCR BgBlue BgClsSystem 0x0d
 
 systemEndpointSetWatermarks
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8 -> m BGResult
 systemEndpointSetWatermarks = curry3 $ xCmd BgMsgCR BgBlue BgClsSystem 0x0e
 
 systemEndpointTx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8Array -> m BGResult
 systemEndpointTx = curry $ xCmd BgMsgCR BgBlue BgClsSystem 0x09
 
 systemGetBootloaderCrc
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt16
 systemGetBootloaderCrc = xCmd BgMsgCR BgBlue BgClsSystem 0x13 ()
 
 systemGetConnections
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt8
 systemGetConnections = xCmd BgMsgCR BgBlue BgClsSystem 0x06 ()
 
 systemGetCounters
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m (UInt8, UInt8, UInt8, UInt8, UInt8)
 systemGetCounters = xCmd BgMsgCR BgBlue BgClsSystem 0x05 ()
 
 systemGetInfo
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m (UInt16, UInt16, UInt16, UInt16, UInt16, UInt8, UInt8)
 systemGetInfo = xCmd BgMsgCR BgBlue BgClsSystem 0x08 ()
 
 systemHello
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m ()
 systemHello = xCmd BgMsgCR BgBlue BgClsSystem 0x01 ()
 
 systemReset
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasDebug env)
     => RebootMode -> m ()
 systemReset = xCmd' BgMsgCR BgBlue BgClsSystem 0x01
 
 systemUsbEnumerationStatusGet
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m (BGResult, Bool)
 systemUsbEnumerationStatusGet = xCmd BgMsgCR BgBlue BgClsSystem 0x12 ()
 
 systemWhitelistAppend
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => BdAddr -> GapAddressType -> m BGResult
 systemWhitelistAppend = curry $ xCmd BgMsgCR BgBlue BgClsSystem 0x0a
 
 systemWhitelistClear
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m ()
 systemWhitelistClear = xCmd BgMsgCR BgBlue BgClsSystem 0x0c ()
 
 systemWhitelistRemove
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => BdAddr -> GapAddressType -> m BGResult
 systemWhitelistRemove = curry $ xCmd BgMsgCR BgBlue BgClsSystem 0x0b
 
 evtSystemBoot
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt16 -> UInt16 -> UInt16 -> UInt16 -> UInt16 -> UInt8 -> UInt8 -> m (Maybe a)) -> m a
 evtSystemBoot
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x00 . uncurry7
 
 evtSystemEndpointWatermarkRx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> m (Maybe a)) -> m a
 evtSystemEndpointWatermarkRx
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x02 . uncurry
 
 evtSystemEndpointWatermarkTx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt8 -> UInt8 -> m (Maybe a)) -> m a
 evtSystemEndpointWatermarkTx
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x03 . uncurry
 
 evtSystemNoLicenseKey
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (() -> m (Maybe a)) -> m a
 evtSystemNoLicenseKey
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x05
 
 evtSystemProtocolError
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (BGResult -> m (Maybe a)) -> m a
 evtSystemProtocolError
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x06
 
 evtSystemScriptFailure
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt16 -> BGResult -> m (Maybe a)) -> m a
 evtSystemScriptFailure
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x04 . uncurry
 
 evtSystemUsbEnumerated
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (Bool -> m (Maybe a)) -> m a
 evtSystemUsbEnumerated
     = handlePacket BgMsgEvent BgBlue BgClsSystem 0x07
@@ -993,27 +1006,27 @@
 -----------------------------------------------------------------------
 
 testChannelMode
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m ()
 testChannelMode = xCmd BgMsgCR BgBlue BgClsTest 0x06
 
 testGetChannelMap
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt8Array
 testGetChannelMap = xCmd BgMsgCR BgBlue BgClsTest 0x04 ()
 
 testPhyEnd
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m UInt16
 testPhyEnd = xCmd BgMsgCR BgBlue BgClsTest 0x02 ()
 
 testPhyRx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> m ()
 testPhyRx = xCmd BgMsgCR BgBlue BgClsTest 0x01
 
 testPhyTx
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8 -> UInt8 -> UInt8 -> m ()
 testPhyTx = curry3 $ xCmd BgMsgCR BgBlue BgClsTest 0x00
 
@@ -1022,26 +1035,26 @@
 -----------------------------------------------------------------------
 
 dfuFlashSetAddress
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt32 -> m BGResult
 dfuFlashSetAddress = xCmd BgMsgCR BgBlue BgClsDfu 0x01
 
 dfuFlashUpload
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => UInt8Array -> m BGResult
 dfuFlashUpload = xCmd BgMsgCR BgBlue BgClsDfu 0x02
 
 dfuFlashUploadFinish
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => m BGResult
 dfuFlashUploadFinish = xCmd BgMsgCR BgBlue BgClsDfu 0x03 ()
 
 dfuReset
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => Bool -> m ()
 dfuReset = xCmd' BgMsgCR BgBlue BgClsDfu 0x00
 
 evtDfuBoot
-    :: (MonadIO m, MonadReader env m, HasHandle env, HasBGChan env, HasDebug env)
+    :: (MonadIO m, MonadReader env m, HasSerialPort env, HasBGChan env, HasDebug env)
     => (UInt32 -> m (Maybe a)) -> m a
 evtDfuBoot = handlePacket BgMsgEvent BgBlue BgClsDfu 0x00
diff --git a/src/BGLib/Types.hs b/src/BGLib/Types.hs
--- a/src/BGLib/Types.hs
+++ b/src/BGLib/Types.hs
@@ -20,13 +20,16 @@
     , fromBgPayload
     , toBgPayload
     , BgPacket(..)
-    , HasHandle(..)
-    , askHandle
+    , HasSerialPort(..)
+    , askSerialPort
     , HasBGChan(..)
     , askBGChan
     , askDupBGChan
+    , askCloneBGChan
     , packetBlock
     , packetBlock_
+    , packetBlock'
+    , packetBlock'_
     , HasDebug(..)
     , askDebug
     , bsShowHex
@@ -80,8 +83,8 @@
 import qualified Data.Word as W
 import           Foreign.Storable
 import           Numeric
-import           System.IO
-import           Text.Printf
+import           System.Hardware.Serialport
+import           Text.Printf 
 
 -- int8           1 byte Signed 8-bit integer
 type Int8 = I.Int8
@@ -106,11 +109,14 @@
     put = putWord32le . fromUInt32
 
 -- uint8array     byte array, first byte is array size
-newtype UInt8Array = UInt8Array { fromUInt8Array :: BSS.ByteString } deriving (Show, IsString)
+newtype UInt8Array = UInt8Array { fromUInt8Array :: BSS.ByteString } deriving (Eq, Ord, IsString)
 
 toUInt8Array :: BSS.ByteString -> UInt8Array
 toUInt8Array s = UInt8Array s
 
+instance Show UInt8Array where
+    show = bsShowHex . fromUInt8Array
+
 instance Binary UInt8Array where
     put UInt8Array{..} = do
         putWord8 $ fromIntegral $ BSS.length fromUInt8Array
@@ -123,6 +129,7 @@
 
 -- bd_addr        Bluetooth address in little endian format
 newtype BdAddr = BdAddr { fromBdAddr :: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) }
+    deriving (Eq, Ord)
 
 instance Show BdAddr where
     show (BdAddr (_5, _4, _3, _2, _1, _0)) = printf "%02x:%02x:%02x:%02x:%02x:%02x" _0 _1 _2 _3 _4 _5
@@ -154,7 +161,7 @@
     , bghLength         :: UInt16 -- Only 11 bits actually
     , bghCommandClass   :: BgCommandClass
     , bghCommandId      :: UInt8
-    } deriving Show
+    } deriving (Eq, Show)
 
 enumFromIntegral :: forall a b. (Integral a, Bounded b, Enum b) => a -> Get b
 enumFromIntegral i = do
@@ -198,7 +205,7 @@
     && cc  == bghCommandClass
     && cid == bghCommandId
 
-newtype BgPayload = BgPayload { fromBgPayload :: BSS.ByteString }
+newtype BgPayload = BgPayload { fromBgPayload :: BSS.ByteString } deriving Eq
 
 toBgPayload :: BSS.ByteString -> BgPayload
 toBgPayload = BgPayload
@@ -209,7 +216,7 @@
 data BgPacket = BgPacket
     { bgpHeader  :: BgPacketHeader
     , bgpPayload :: BgPayload
-    } deriving Show
+    } deriving (Eq, Show)
 
 instance Binary BgPacket where
     put BgPacket{..} = do
@@ -221,11 +228,11 @@
         bgpPayload <- toBgPayload <$> getByteString (fromIntegral bghLength)
         return BgPacket{..}
 
-class HasHandle env where
-    getHandle :: env -> Handle
+class HasSerialPort env where
+    getSerialPort :: env -> SerialPort
 
-askHandle :: (MonadReader env m, HasHandle env) => m Handle
-askHandle = getHandle <$> ask
+askSerialPort :: (MonadReader env m, HasSerialPort env) => m SerialPort
+askSerialPort = getSerialPort <$> ask
 
 class HasBGChan env where
     getBGChan :: env -> TChan BgPacket
@@ -239,6 +246,11 @@
     chan <- getBGChan <$> ask
     liftIO $ atomically $ dupTChan chan
 
+askCloneBGChan :: (MonadIO m, MonadReader env m, HasBGChan env) => m (TChan BgPacket)
+askCloneBGChan = do
+    chan <- getBGChan <$> ask
+    liftIO $ atomically $ cloneTChan chan
+    
 packetBlock :: (MonadIO m, MonadReader env m, HasBGChan env) => m a -> m a
 packetBlock act = do
     newChan <- askDupBGChan
@@ -246,7 +258,15 @@
 
 packetBlock_ :: (MonadIO m, MonadReader env m, HasBGChan env) => m a -> m ()
 packetBlock_ act = packetBlock act >> return ()
-    
+
+packetBlock' :: (MonadIO m, MonadReader env m, HasBGChan env) => m a -> m a
+packetBlock' act = do
+    newChan <- askCloneBGChan
+    local (updateBGChan newChan) act
+
+packetBlock'_ :: (MonadIO m, MonadReader env m, HasBGChan env) => m a -> m ()
+packetBlock'_ act = packetBlock' act >> return ()
+
 class HasDebug env where
     getDebug :: env -> Bool
 
@@ -261,7 +281,7 @@
     = RebootNormal
     -- Reboot into DFU mode
     | RebootDfu
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary RebootMode where
     put m = do
@@ -283,7 +303,7 @@
     -- 5: Value was indicated and the remote device is
     -- waiting for a confirmation
     | AVTIndicateRsqReq
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary AttributeValueType where
     put m = do
@@ -303,7 +323,7 @@
     -- User Write Response command should
     -- be used to send the confirmation.
     | ACRWriteRequestUser
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary AttributeChangeReason where
     put m = do
@@ -378,7 +398,7 @@
     | GATLocalnameShort
     | GATLocalnameComplete
     | GATTxPower
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapAdvType where
     put m = do
@@ -399,7 +419,7 @@
     -- Respond to scan requests from whitelist only, allow connection
     -- from whitelist only
     | GAPWhitelistAll
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapAdvPolicy where
     put m = do
@@ -411,7 +431,7 @@
 data GapAddressType
     = GATPublic
     | GATRandom
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapAddressType where
     put m = do
@@ -430,7 +450,7 @@
     -- packets. Device accepts scan requests (active scanning) but is
     -- not connectable.
     | GCMScannableNonConnectable
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapConnectableMode where
     put m = do
@@ -464,7 +484,7 @@
     -- reported back to the application through Scan Response event.
     -- This is so called Enhanced Broadcasting mode.
     | GDMEnhancedBroadcasting
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapDiscoverableMode where
     put m = do
@@ -488,7 +508,7 @@
     | GapDiscoverGeneric
     -- Discover all devices regardless of the Flags AD typ
     | GapDiscoverOvservation
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapDiscoverMode where
     put m = do
@@ -513,7 +533,7 @@
     | GSHFConnectReq
     -- Non-connectable undirected advertising event
     | GSHFAdvDiscoverInd
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GSPScanHeaderFlag where
     put m = do
@@ -527,7 +547,7 @@
     -- Ignore advertisement packets from remote slaves not in the running
     -- whitelist
     | GSPWhitelist
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary GapScanPolicy where
     put m = do
@@ -576,7 +596,7 @@
     | SICNoIO
     -- Display with Keyboard
     | SICKeyboardDisplay
-    deriving (Enum, Show)
+    deriving (Eq, Enum, Show)
 
 instance Binary SMIOCapabilities where
     put m = do
@@ -597,7 +617,7 @@
     | SEUART0
     -- USART 1
     | SEUART1
-    deriving (Show, Enum)
+    deriving (Eq, Show, Enum)
 
 instance Binary SystemEndpoint where
     put m = do
@@ -861,7 +881,7 @@
 
     -- And error code unknown by this library
     | BGRUnknown UInt16
-    deriving Show
+    deriving (Eq, Show)
 
 instance Binary BGResult where
     put m = do
