{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module BGLib.Types ( Int8 , UInt8 , UInt16 , UInt32 , UInt8Array(..) , toUInt8Array , BdAddr(..) , BgMessageType(..) , BgTecnologyType(..) , BgCommandClass(..) , BgPacketHeader(..) , bgHeaderMatches , BgPayload , fromBgPayload , toBgPayload , BgPacket(..) , HasSerialPort(..) , askSerialPort , HasBGChan(..) , askBGChan , askDupBGChan , HasDebug(..) , askDebug , bsShowHex , RebootMode(..) , AttributeValueType(..) , AttributeChangeReason(..) , fASNotify , fASIndicate , fCConnected , fCEncrypted , fCCompleted , fCParametersChanged , fADLimitedDiscoverable , fADGeneralDiscoverable , fADBREDRNotSupported , fADSimultaneousLEBREDRCtrl , fADSimultaneousLEBREDRHost , fADMask , GapAdvType(..) , GapAdvPolicy(..) , GapAddressType(..) , GapConnectableMode(..) , GapDiscoverableMode(..) , GapDiscoverMode(..) , GSPScanHeaderFlag(..) , GapScanPolicy(..) , fBKLTK , fBKAddrPublic , fBKAddrStatic , fBKIRK , fBKEDIVRAND , fBKCSRK , fBKMasterId , SMIOCapabilities(..) , SystemEndpoint(..) , BGResult(..) ) where import Control.Concurrent.STM.TChan import Control.Monad.Reader import Control.Concurrent.STM import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.Bits import qualified Data.ByteString as BSS import qualified Data.Int as I import Data.String import qualified Data.Word as W import Numeric import System.Hardware.Serialport import Text.Printf -- int8 1 byte Signed 8-bit integer type Int8 = I.Int8 -- uint8 1 byte Unsigned 8-bit integer type UInt8 = W.Word8 -- uint16 2 bytes Unsigned 16-bit integer type UInt16 = W.Word16 -- uint32 4 bytes Unsigned 32-bit integer type UInt32 = W.Word32 -- uint8array byte array, first byte is array size newtype UInt8Array = UInt8Array { fromUInt8Array :: BSS.ByteString } deriving (Show, IsString) toUInt8Array :: BSS.ByteString -> UInt8Array toUInt8Array s = UInt8Array s instance Binary UInt8Array where put UInt8Array{..} = do putWord8 $ fromIntegral $ BSS.length fromUInt8Array putByteString fromUInt8Array get = do l <- getWord8 bs <- getByteString (fromIntegral l) return $ UInt8Array bs -- bd_addr Bluetooth address in little endian format newtype BdAddr = BdAddr { fromBdAddr :: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) } 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 instance Binary BdAddr where put BdAddr{..} = put fromBdAddr get = get >>= return . BdAddr data BgMessageType = BgMsgCR | BgMsgEvent deriving (Eq, Show, Enum) data BgTecnologyType = BgBlue | BgWifi deriving (Eq, Show, Enum) data BgCommandClass = BgClsSystem | BgClsPersistentStore | BgClsAttributeDatabase | BgClsConnection | BgClsAttributeClient | BgClsSecurityManager | BgClsGenericAccessProfile | BgClsHardware | BgClsTest | BgClsDfu deriving (Eq, Show, Enum) data BgPacketHeader = BgPacketHeader { bghMessageType :: BgMessageType , bghTechnologyType :: BgTecnologyType , bghLength :: UInt16 -- Only 11 bits actually , bghCommandClass :: BgCommandClass , bghCommandId :: UInt8 } deriving Show instance Binary BgPacketHeader where put BgPacketHeader{..} = do putWord8 $ fromIntegral (fromEnum bghMessageType `shift` 7) .|. fromIntegral (fromEnum bghTechnologyType `shift` 3) .|. fromIntegral ((bghLength .&. 0x0700) `shift` (-8)) putWord8 $ fromIntegral $ bghLength .&. 0x00ff putWord8 $ fromIntegral $ fromEnum bghCommandClass putWord8 $ bghCommandId get = do oct0 <- getWord8 lLow <- getWord8 clsId <- getWord8 cmdId <- getWord8 let lHigh = oct0 .&. 0x07 let bghMessageType = toEnum $ fromIntegral $ oct0 `shift` (-7) let bghTechnologyType = toEnum $ fromIntegral $ (oct0 `shift` (-3)) .&. 0x0f let bghLength = (fromIntegral lHigh `shift` 8) + (fromIntegral lLow) :: UInt16 let bghCommandClass = toEnum $ fromIntegral clsId let bghCommandId = cmdId return $ BgPacketHeader{..} bgHeaderMatches :: BgMessageType -> BgTecnologyType -> BgCommandClass -> UInt8 -> BgPacketHeader -> Bool bgHeaderMatches mt tt cc cid BgPacketHeader{..} = mt == bghMessageType && tt == bghTechnologyType && cc == bghCommandClass && cid == bghCommandId newtype BgPayload = BgPayload { fromBgPayload :: BSS.ByteString } toBgPayload :: BSS.ByteString -> BgPayload toBgPayload = BgPayload instance Show BgPayload where show = bsShowHex . fromBgPayload data BgPacket = BgPacket { bgpHeader :: BgPacketHeader , bgpPayload :: BgPayload } deriving Show instance Binary BgPacket where put BgPacket{..} = do put bgpHeader putByteString $ fromBgPayload bgpPayload get = do bgpHeader@BgPacketHeader{..} <- get bgpPayload <- toBgPayload <$> getByteString (fromIntegral bghLength) return BgPacket{..} class HasSerialPort env where getSerialPort :: env -> SerialPort askSerialPort :: (MonadReader env m, HasSerialPort env) => m SerialPort askSerialPort = getSerialPort <$> ask class HasBGChan env where getBGChan :: env -> TChan BgPacket askBGChan :: (MonadReader env m, HasBGChan env) => m (TChan BgPacket) askBGChan = getBGChan <$> ask askDupBGChan :: (MonadIO m, MonadReader env m, HasBGChan env) => m (TChan BgPacket) askDupBGChan = do chan <- getBGChan <$> ask liftIO $ atomically $ dupTChan chan class HasDebug env where getDebug :: env -> Bool askDebug :: (MonadReader env m, HasDebug env) => m (Bool) askDebug = getDebug <$> ask bsShowHex :: BSS.ByteString -> String bsShowHex = concatMap (\n -> ' ' : showHex n "") . BSS.unpack data RebootMode -- Reboot into application = RebootNormal -- Reboot into DFU mode | RebootDfu deriving (Show, Enum) instance Binary RebootMode where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data AttributeValueType -- 0: Value was read = AVTRead -- 1: Value was notified | AVTNotify -- 2: Value was indicated | AVTIndicate -- 3: Value was read | AVTReadByType -- 4: Value was part of a long attribute | AVTReadBlob -- 5: Value was indicated and the remote device is -- waiting for a confirmation | AVTIndicateRsqReq deriving (Show, Enum) instance Binary AttributeValueType where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data AttributeChangeReason -- 0: Value was written by remote device using write request = ACRWriteRequest -- 1: Value was written by remote device using write command | ACRWriteCommand -- 2: Local attribute value was written by the -- remote device, but the Bluetooth Smart -- stack is waiting for the write to be -- confirmed by the application. -- User Write Response command should -- be used to send the confirmation. | ACRWriteRequestUser deriving (Show, Enum) instance Binary AttributeChangeReason where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 -- Attribute status flags -- Notifications are enabled fASNotify :: UInt8 fASNotify = 0x01 -- Indications are enabled fASIndicate :: UInt8 fASIndicate = 0x02 -- Connection status flags -- This status flag tells the connection exists to a remote device. fCConnected :: UInt8 fCConnected = 0x01 -- This flag tells the connection is encrypted. fCEncrypted :: UInt8 fCEncrypted = 0x02 -- Connection completed flag, which is used to tell a new connection -- has been created. fCCompleted :: UInt8 fCCompleted = 0x04 -- This flag tells that connection parameters have changed and. It is -- set when connection parameters have changed due to a link layer -- operation. fCParametersChanged :: UInt8 fCParametersChanged = 0x08 -- 0x01 GAP_AD_FLAG_LIMITED_DISCOVERABLE Limited discoverability fADLimitedDiscoverable :: UInt8 fADLimitedDiscoverable = 0x01 -- 0x02 GAP_AD_FLAG_GENERAL_DISCOVERABLE General discoverability fADGeneralDiscoverable :: UInt8 fADGeneralDiscoverable = 0x02 -- 0x04 GAP_AD_FLAG_BREDR_NOT_SUPPORTED BR/EDR not supported fADBREDRNotSupported :: UInt8 fADBREDRNotSupported = 0x04 -- 0x10 GAP_AD_FLAG_SIMULTANEOUS_LEBREDR_CTRL BR/EDR controller fADSimultaneousLEBREDRCtrl :: UInt8 fADSimultaneousLEBREDRCtrl = 0x10 -- 0x20 GAP_AD_FLAG_SIMULTANEOUS_LEBREDR_HOST BE/EDR host fADSimultaneousLEBREDRHost :: UInt8 fADSimultaneousLEBREDRHost = 0x20 -- 0x1f GAP_AD_FLAG_MASK - fADMask :: UInt8 fADMask = 0x1f data GapAdvType = GATNone | GATFlags | GATServices16bitMore | GATServices16bitAll | GATServices32bitMore | GATServices32bitAll | GATServices128bitMore | GATServices128bitAll | GATLocalnameShort | GATLocalnameComplete | GATTxPower deriving (Show, Enum) instance Binary GapAdvType where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data GapAdvPolicy -- Respond to scan requests from any master, allow connection -- from any master (default) = GAPAll -- Respond to scan requests from whitelist only, allow connection -- from any | GAPWhitelistScan -- Respond to scan requests from any, allow connection from -- whitelist only | GAPWhitelistConnect -- Respond to scan requests from whitelist only, allow connection -- from whitelist only | GAPWhitelistAll deriving (Show, Enum) instance Binary GapAdvPolicy where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data GapAddressType = GATPublic | GATRandom deriving (Show, Enum) instance Binary GapAddressType where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data GapConnectableMode -- Not connectable = GCMNonConnectable -- Directed Connectable | GCMDirectedConnectable -- Undirected connectable | GCMUndirectedConnectable -- Same as non-connectable, but also supports ADV_SCAN_IND -- packets. Device accepts scan requests (active scanning) but is -- not connectable. | GCMScannableNonConnectable deriving (Show, Enum) instance Binary GapConnectableMode where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data GapDiscoverableMode -- Non-discoverable mode: the LE Limited Discoverable Mode and the -- LE General Discoverable Mode bits are NOT set in the Flags AD -- type. A master can still connect to the advertising slave in this mode. = GDMNonDiscoverable -- 1 gap_limited_discoverable Discoverable using limited scanning mode: the advertisement -- packets will carry the LE Limited Discoverable Mode bit set in the -- Flags AD type. | GDMLimitedDiscoverable -- 2 gap_general_discoverable Discoverable using general scanning mode: the advertisement -- packets will carry the LE General Discoverable Mode bit set in the -- Flags AD type. | GDMGeneralDiscoverable -- 3 gap_broadcast Same as gap_non_discoverable above. | GDMBroadcast -- 4 gap_user_data In this advertisement the advertisement and scan response data -- defined by user will be used. The user is responsible of building the -- advertisement data so that it also contains the appropriate desired -- Flags AD type. | GDMUserData -- 0x80 gap_enhanced_broadcasting When turning the most highest bit on in GAP discoverable mode, the -- remote devices that send scan request packets to the advertiser are -- reported back to the application through Scan Response event. -- This is so called Enhanced Broadcasting mode. | GDMEnhancedBroadcasting deriving (Show, Enum) instance Binary GapDiscoverableMode where put m = do putWord8$ case m of GDMEnhancedBroadcasting -> 0x80 _ -> fromIntegral $ fromEnum m get = do x <- getWord8 return $ case x of 5 -> GDMEnhancedBroadcasting _ -> toEnum $ fromIntegral x data GapDiscoverMode -- 0: Discover only limited discoverable devices, that is, Slaves which have the -- LE Limited Discoverable Mode bit set in the Flags AD type of their -- advertisement packets. = GapDiscoverLimited -- Discover limited and generic discoverable devices, that is, Slaves which -- have the LE Limited Discoverable Mode or the LE General Discoverable -- Mode bit set in the Flags AD type of their advertisement packets. | GapDiscoverGeneric -- Discover all devices regardless of the Flags AD typ | GapDiscoverOvservation deriving (Show, Enum) instance Binary GapDiscoverMode where put m = do putWord16le $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord16le -- GAP Scan header flags data GSPScanHeaderFlag -- Connectable undirected advertising event = GSHFAdvInd -- Connectable directed advertising event | GSHFAdvDirectInd -- Non-connectable undirected advertising event | GSHFAdvNonConnInd -- Scanner wants information from Advertiser | GSHFScanReq -- Advertiser gives more information to Scanner | GSHFScanRsp -- Initiator wants to connect to Advertiser | GSHFConnectReq -- Non-connectable undirected advertising event | GSHFAdvDiscoverInd deriving (Show, Enum) instance Binary GSPScanHeaderFlag where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data GapScanPolicy -- All advertisement Packets (default) = GSPAll -- Ignore advertisement packets from remote slaves not in the running -- whitelist | GSPWhitelist deriving (Show, Enum) instance Binary GapScanPolicy where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 -- SM Bonding Key flags -- LTK saved in master fBKLTK :: UInt8 fBKLTK = 0x01 -- Public Address fBKAddrPublic :: UInt8 fBKAddrPublic = 0x02 -- Static Address fBKAddrStatic :: UInt8 fBKAddrStatic = 0x04 -- Identity resolving key for resolvable private addresses fBKIRK :: UInt8 fBKIRK = 0x08 -- EDIV+RAND received from slave fBKEDIVRAND :: UInt8 fBKEDIVRAND = 0x10 -- Connection signature resolving key fBKCSRK :: UInt8 fBKCSRK = 0x20 -- EDIV+RAND sent to master fBKMasterId :: UInt8 fBKMasterId = 0x40 data SMIOCapabilities -- Display Only = SICDisplayOnly -- Display with Yes/No-buttons | SICDisplayYesNo -- Keyboard Only | SICKeyboardOnly -- No Input and No Output | SICNoIO -- Display with Keyboard | SICKeyboardDisplay deriving (Enum, Show) instance Binary SMIOCapabilities where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 data SystemEndpoint -- Command Parser = SECommandParser -- Radio Test | SETest -- BGScript (not used) | SEScript -- USB Interface | SEUSB -- USART 0 | SEUART0 -- USART 1 | SEUART1 deriving (Show, Enum) instance Binary SystemEndpoint where put m = do putWord8 $ fromIntegral $ fromEnum m get = do toEnum . fromIntegral <$> getWord8 -- Operation result data BGResult = BGRSuccess -- Invalid Parameter (0x0180) -- Command contained invalid parameter | BGRInvalidParameter -- Device in Wrong State (0x0181) -- Device is in wrong state to receive command | BGRWrongState -- Out Of Memory (0x0182) -- Device has run out of memory | BGROutOfMemory -- Feature Not Implemented (0x0183) -- Feature is not implemented | BGRNotImplemented -- Command Not Recognized (0x0184) -- Command was not recognized | BGRNotRecognized -- Timeout (0x0185) -- Command or Procedure failed due to timeout | BGRTimeout -- Not Connected (0x0186) -- Connection handle passed is to command is not a valid handle | BGRNotConnected -- Flow (0x0187) -- Command would cause either underflow or overflow error | BGRFlow -- User Attribute (0x0188) -- User attribute was accessed through API which is not supported | BGRUserAttribute -- Invalid License Key (0x0189) -- No valid license key found | BGRInvalidLicenseKey -- Command Too Long (0x018A) -- Command maximum length exceeded | BGRCommandTooLong -- Out of Bonds (0x018B) -- Bonding procedure can't be started because device has no space left for bond. | BGROutOfBonds -- Script Overflow (0x018C) -- Module was reset due to script stack overflow. -- In BLE BGScript there is a script stack overflow detection mechanism. This solution resets module -- when script stack overflow is detected. After next boot script failure event with specific error code is -- generated right after system boot event. -- This feature works only with BLE SDK version 1.7.0 or newer that support script stack overflow -- detection mechanism. For this feature to work correctly update of bootloader is needed. | BGRScriptOverflow -- Authentication Failure (0x0205) -- Pairing or authentication failed due to incorrect results in the pairing or authentication procedure. This could be -- due to an incorrect PIN or Link Key | BGRAuthenticationFailure -- Pin or Key Missing (0x0206) -- Pairing failed because of missing PIN, or authentication failed because of missing Key. -- Silicon Labs | BGRPinOrKeyMissing -- Memory Capacity Exceeded (0x0207) -- Controller is out of memory. | BGRMemoryCapacityExceeded -- Connection Timeout (0x0208) -- Link supervision timeout has expired. | BGRConnectionTimeout -- Connection Limit Exceeded (0x0209) -- Controller is at limit of connections it can support. | BGRConnectionLimitExceeded -- Command Disallowed (0x020C) -- Command requested cannot be executed because the Controller is in a state where it cannot process this -- command at this time. | BGRCommandDisallowed -- Invalid Command Parameters (0x0212) -- Command contained invalid parameters. | BGRInvalidCommandParameters -- Remote User Terminated Connection (0x0213) -- User on the remote device terminated the connection. | BGRRemoteUserTerminatedConnection -- Connection Terminated by Local Host (0x0216) -- Local device terminated the connection. | BGRConnectionTErminagedByLocalHost -- LL Response Timeout (0x0222) -- Connection terminated due to link-layer procedure timeout. | BGRLLResponseTimeout -- LL Instant Passed (0x0228) -- Received link-layer control packet where instant was in the past. | BGRLLInstantPassed -- Controller Busy (0x023A) -- Operation was rejected because the controller is busy and unable to process the request. | BGRControllerBusy -- Unacceptable Connection Interval (0x023B) -- The Unacceptable Connection Interval error code indicates that the remote device terminated the connection -- because of an unacceptable connection interval. | BGRUnacceptableConnectionInterval -- Directed Advertising Timeout (0x023C) -- Directed advertising completed without a connection being created. | BGRDirectedAdvertisingTimeout -- MIC Failure (0x023D) -- Connection was terminated because the Message Integrity Check (MIC) failed on a received packet. | BGRMICFailure -- Connection Failed to be Established (0x023E) -- LL initiated a connection but the connection has failed to be established. Controller did not receive any packets -- from remote end. -- More in detail, an attempt to open a connection is made by the master by sending only one CONNECT_REQ , -- after which the master immediately transitions to connected state (BT4.1 Vol 6 Part B 4.4.4). If the advertiser for -- any reason (like interference) does not catch the packet it will just continue advertising, while the master -- remains in a fast termination mode, where it will only send 6 packets before failing, independent of supervision -- timeout (in fact, a master starts using normal supervision timeout only after it has received at least one packet -- from slave.) If the master does not receive anything by the time its 6 packets are sent, connection establishment -- will be considered failed and this error will be reported to the host or to the BGScript. In a busy environment it is -- normal to see roughly 1-2% error rate when opening connections. | BGRConnectionFailedToBeEstablised -- Passkey Entry Failed (0x0301) -- The user input of passkey failed, for example, the user cancelled the operation | BGRPasskeyEntryFailed -- OOB Data is not available (0x0302) -- Out of Band data is not available for authentication | BGROOBDataIsNotAvailable -- Authentication Requirements (0x0303) -- The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities -- of one or both devices | BGRAuthenticationRequirements -- Confirm Value Failed (0x0304) -- The confirm value does not match the calculated compare value | BGRConfirmValueFailed -- Pairing Not Supported (0x0305) -- Pairing is not supported by the device | BGRPairingNotSupported -- Encryption Key Size (0x0306) -- The resultant encryption key size is insufficient for the security requirements of this device | BGREncryptionKeySize -- Command Not Supported (0x0307) -- The SMP command received is not supported on this device | BGRCommandNotSupported -- Unspecified Reason (0x0308) -- Pairing failed due to an unspecified reason | BGRUnspecifiedReason -- Repeated Attempts (0x0309) -- Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request -- or security request | BGRRepeatedAttempts -- Invalid Parameters (0x030A) -- The Invalid Parameters error code indicates: the command length is invalid or a parameter is outside of the -- specified range. | BGRInvalidParameters -- Invalid Handle (0x0401) -- The attribute handle given was not valid on this server | BGRInvalidHandle -- Read Not Permitted (0x0402) -- The attribute cannot be read | BGRReadNotPermitted -- Write Not Permitted (0x0403) -- The attribute cannot be written | BGRWriteNotPermitted -- Invalid PDU (0x0404) -- The attribute PDU was invalid | BGRInvalidPDU -- Insufficient Authentication (0x0405) -- The attribute requires authentication before it can be read or written. | BGRInsufficientAuthentication -- Request Not Supported (0x0406) -- Attribute Server does not support the request received from the client. | BGRRequestNotSupported -- Invalid Offset (0x0407) -- Offset specified was past the end of the attribute | BGRInvalidOffset -- Insufficient Authorization (0x0408) -- The attribute requires authorization before it can be read or written. | BGRInsufficientAuthorization -- Prepare Queue Full (0x0409) -- Too many prepare writes have been queueud | BGRPrepareQueueFull -- Attribute Not Found (0x040A) -- No attribute found within the given attribute handle range. | BGRAttributeNotFound -- Attribute Not Long (0x040B) -- The attribute cannot be read or written using the Read Blob Request | BGRAttributeNotLong -- Insufficient Encryption Key Size (0x040C) -- The Encryption Key Size used for encrypting this link is insufficient. | BGRInsufficientEncryptionKeySize -- Invalid Attribute Value Length (0x040D) -- The attribute value length is invalid for the operation | BGRInvalidAttributeValueLength -- Unlikely Error (0x040E) -- The attribute request that was requested has encountered an error that was unlikely, and therefore could not be -- completed as requested. | BGRUnlikelyError -- Insufficient Encryption (0x040F) -- The attribute requires encryption before it can be read or written. | BGRInsufficientEncryption -- Unsupported Group Type (0x0410) -- The attribute type is not a supported grouping attribute as defined by a higher layer specification. | BGRUnsupportedGroupType -- Insufficient Resources (0x0411) -- Insufficient Resources to complete the request | BGRInsufficientResources -- Application Error Codes (0x0480) -- Application error code defined by a higher layer specification. -- The error code range 0x80-0x9F is reserved for application level errors. | BGRApplicationErrorCode UInt8 -- And error code unknown by this library | BGRUnknown UInt16 deriving Show instance Binary BGResult where put m = do putWord16le $ case m of BGRSuccess -> 0x0000 BGRInvalidParameter -> 0x0180 BGRWrongState -> 0x0181 BGROutOfMemory -> 0x0182 BGRNotImplemented -> 0x0183 BGRNotRecognized -> 0x0184 BGRTimeout -> 0x0185 BGRNotConnected -> 0x0186 BGRFlow -> 0x0187 BGRUserAttribute -> 0x0188 BGRInvalidLicenseKey -> 0x0189 BGRCommandTooLong -> 0x018A BGROutOfBonds -> 0x018B BGRScriptOverflow -> 0x018C BGRAuthenticationFailure -> 0x0205 BGRPinOrKeyMissing -> 0x0206 BGRMemoryCapacityExceeded -> 0x0207 BGRConnectionTimeout -> 0x0208 BGRConnectionLimitExceeded -> 0x0209 BGRCommandDisallowed -> 0x020C BGRInvalidCommandParameters -> 0x0212 BGRRemoteUserTerminatedConnection -> 0x0213 BGRConnectionTErminagedByLocalHost -> 0x0216 BGRLLResponseTimeout -> 0x0222 BGRLLInstantPassed -> 0x0228 BGRControllerBusy -> 0x023A BGRUnacceptableConnectionInterval -> 0x023B BGRDirectedAdvertisingTimeout -> 0x023C BGRMICFailure -> 0x023D BGRConnectionFailedToBeEstablised -> 0x023E BGRPasskeyEntryFailed -> 0x0301 BGROOBDataIsNotAvailable -> 0x0302 BGRAuthenticationRequirements -> 0x0303 BGRConfirmValueFailed -> 0x0304 BGRPairingNotSupported -> 0x0305 BGREncryptionKeySize -> 0x0306 BGRCommandNotSupported -> 0x0307 BGRUnspecifiedReason -> 0x0308 BGRRepeatedAttempts -> 0x0309 BGRInvalidParameters -> 0x030A BGRInvalidHandle -> 0x0401 BGRReadNotPermitted -> 0x0402 BGRWriteNotPermitted -> 0x0403 BGRInvalidPDU -> 0x0404 BGRInsufficientAuthentication -> 0x0405 BGRRequestNotSupported -> 0x0406 BGRInvalidOffset -> 0x0407 BGRInsufficientAuthorization -> 0x0408 BGRPrepareQueueFull -> 0x0409 BGRAttributeNotFound -> 0x040A BGRAttributeNotLong -> 0x040B BGRInsufficientEncryptionKeySize -> 0x040C BGRInvalidAttributeValueLength -> 0x040D BGRUnlikelyError -> 0x040E BGRInsufficientEncryption -> 0x040F BGRUnsupportedGroupType -> 0x0410 BGRInsufficientResources -> 0x0411 BGRApplicationErrorCode errC -> (fromIntegral errC .&. 0x001f) .|. 0x0480 BGRUnknown errC -> errC get = do errC <- getWord16le return $ case errC of 0x0000 -> BGRSuccess 0x0180 -> BGRInvalidParameter 0x0181 -> BGRWrongState 0x0182 -> BGROutOfMemory 0x0183 -> BGRNotImplemented 0x0184 -> BGRNotRecognized 0x0185 -> BGRTimeout 0x0186 -> BGRNotConnected 0x0187 -> BGRFlow 0x0188 -> BGRUserAttribute 0x0189 -> BGRInvalidLicenseKey 0x018A -> BGRCommandTooLong 0x018B -> BGROutOfBonds 0x018C -> BGRScriptOverflow 0x0205 -> BGRAuthenticationFailure 0x0206 -> BGRPinOrKeyMissing 0x0207 -> BGRMemoryCapacityExceeded 0x0208 -> BGRConnectionTimeout 0x0209 -> BGRConnectionLimitExceeded 0x020C -> BGRCommandDisallowed 0x0212 -> BGRInvalidCommandParameters 0x0213 -> BGRRemoteUserTerminatedConnection 0x0216 -> BGRConnectionTErminagedByLocalHost 0x0222 -> BGRLLResponseTimeout 0x0228 -> BGRLLInstantPassed 0x023A -> BGRControllerBusy 0x023B -> BGRUnacceptableConnectionInterval 0x023C -> BGRDirectedAdvertisingTimeout 0x023D -> BGRMICFailure 0x023E -> BGRConnectionFailedToBeEstablised 0x0301 -> BGRPasskeyEntryFailed 0x0302 -> BGROOBDataIsNotAvailable 0x0303 -> BGRAuthenticationRequirements 0x0304 -> BGRConfirmValueFailed 0x0305 -> BGRPairingNotSupported 0x0306 -> BGREncryptionKeySize 0x0307 -> BGRCommandNotSupported 0x0308 -> BGRUnspecifiedReason 0x0309 -> BGRRepeatedAttempts 0x030A -> BGRInvalidParameters 0x0401 -> BGRInvalidHandle 0x0402 -> BGRReadNotPermitted 0x0403 -> BGRWriteNotPermitted 0x0404 -> BGRInvalidPDU 0x0405 -> BGRInsufficientAuthentication 0x0406 -> BGRRequestNotSupported 0x0407 -> BGRInvalidOffset 0x0408 -> BGRInsufficientAuthorization 0x0409 -> BGRPrepareQueueFull 0x040A -> BGRAttributeNotFound 0x040B -> BGRAttributeNotLong 0x040C -> BGRInsufficientEncryptionKeySize 0x040D -> BGRInvalidAttributeValueLength 0x040E -> BGRUnlikelyError 0x040F -> BGRInsufficientEncryption 0x0410 -> BGRUnsupportedGroupType 0x0411 -> BGRInsufficientResources _ -> if errC >= 0x0480 && errC <= 0x049f then BGRApplicationErrorCode $ fromIntegral (errC .&. 0x1f) else BGRUnknown errC