{-# LINE 1 "Network/Bluetooth/Adapter.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}
{-# LINE 2 "Network/Bluetooth/Adapter.hsc" #-}
module Network.Bluetooth.Adapter (
        allAdapters,
        defaultAdapter,
        discover,
        module Network.Bluetooth.Types
    ) where


{-# LINE 12 "Network/Bluetooth/Adapter.hsc" #-}

{-# LINE 13 "Network/Bluetooth/Adapter.hsc" #-}

{-# LINE 14 "Network/Bluetooth/Adapter.hsc" #-}

{-# LINE 15 "Network/Bluetooth/Adapter.hsc" #-}

{-# LINE 16 "Network/Bluetooth/Adapter.hsc" #-}

import Network.Bluetooth.Device
import Network.Bluetooth.Types

{-# LINE 22 "Network/Bluetooth/Adapter.hsc" #-}
import qualified Data.ByteString.Internal as BI

import Control.Applicative
import Control.Exception
import Control.Monad
import Data.Bits
import Data.IORef
import Data.Word
import Foreign
import Foreign.C

{-# LINE 35 "Network/Bluetooth/Adapter.hsc" #-}


{-# LINE 37 "Network/Bluetooth/Adapter.hsc" #-}
foreign import ccall safe "hci_for_each_dev" hci_for_each_dev
    :: CInt -> FunPtr (CInt -> CInt -> CLong -> IO CInt) -> CLong -> IO ()

foreign import ccall safe "wrapper" mkVisitDev
    ::            (CInt -> CInt -> CLong -> IO CInt) ->
       IO (FunPtr (CInt -> CInt -> CLong -> IO CInt))

foreign import ccall safe "hci_open_dev" hci_open_dev
    :: CInt -> IO CInt

{-# LINE 47 "Network/Bluetooth/Adapter.hsc" #-}


{-# LINE 49 "Network/Bluetooth/Adapter.hsc" #-}
openDev :: CInt -> IO Adapter
openDev dev_id = do
    ret <- hci_open_dev dev_id
    if ret < 0 then do
        errno@(Errno errno_) <- getErrno
        if errno == eINTR
            then openDev dev_id
            else do
                err <- peekCString (strerror errno_)
                throwIO $ BluetoothException "openDev" err
      else
        pure $ Adapter dev_id ret

{-# LINE 62 "Network/Bluetooth/Adapter.hsc" #-}

allAdapters :: IO [Adapter]

{-# LINE 67 "Network/Bluetooth/Adapter.hsc" #-}
allAdapters = do
    devsRef <- newIORef []
    cb <- mkVisitDev $ \_ dev_id _ -> do
        modifyIORef devsRef (dev_id:)
        pure 0
    hci_for_each_dev (0) cb 0
{-# LINE 73 "Network/Bluetooth/Adapter.hsc" #-}
      `finally`
        freeHaskellFunPtr cb
    dev_ids <- reverse <$> readIORef devsRef
    mapM openDev dev_ids

{-# LINE 78 "Network/Bluetooth/Adapter.hsc" #-}


{-# LINE 80 "Network/Bluetooth/Adapter.hsc" #-}
foreign import ccall unsafe "hci_get_route" hci_get_route
    :: Ptr BluetoothAddr -> IO CInt

{-# LINE 83 "Network/Bluetooth/Adapter.hsc" #-}

defaultAdapter :: IO (Maybe Adapter)

{-# LINE 88 "Network/Bluetooth/Adapter.hsc" #-}
defaultAdapter = do
    ret <- hci_get_route nullPtr
    if ret < 0 then do
        errno@(Errno errno_) <- getErrno
        if errno == eINTR
            then defaultAdapter
          else if errno == eNODEV
            then pure Nothing
            else do
                err <- peekCString (strerror errno_)
                throwIO $ BluetoothException "defaultAdapter" err
      else
        Just <$> openDev ret

{-# LINE 102 "Network/Bluetooth/Adapter.hsc" #-}


{-# LINE 104 "Network/Bluetooth/Adapter.hsc" #-}
foreign import ccall safe "hci_inquiry" hci_inquiry
    :: CInt -> CInt -> CInt -> Ptr Word8 -> Ptr (Ptr InquiryInfo) -> CLong -> IO CInt

data InquiryInfo = InquiryInfo {
        iiAddr :: BluetoothAddr
    }
    deriving Show

instance Storable InquiryInfo where
    sizeOf _ = (14)
{-# LINE 114 "Network/Bluetooth/Adapter.hsc" #-}
    alignment _ = alignment (undefined :: Word64)
    peek p = InquiryInfo <$> peek (p `plusPtr` (0))
{-# LINE 116 "Network/Bluetooth/Adapter.hsc" #-}
    poke _ _ = fail "InquiryInfo.poke not defined"

{-# LINE 118 "Network/Bluetooth/Adapter.hsc" #-}

discover :: Adapter -> IO [Device]

{-# LINE 127 "Network/Bluetooth/Adapter.hsc" #-}
discover a@(Adapter dev_id _) = go 0  -- (#const IREQ_CACHE_FLUSH)
  where
    go flags = do
        mDevices <- allocaArray 255 $ \ppDevs -> do
            poke ppDevs nullPtr
            n <- hci_inquiry dev_id 8 255 nullPtr ppDevs flags
            if n < 0 then do
                errno@(Errno errno_) <- getErrno
                if errno == eINTR
                    then pure Nothing
                    else do
                        err <- peekCString (strerror errno_)
                        throwIO $ BluetoothException "discover" err
              else do
                pDevs <- peek ppDevs
                iis <- peekArray (fromIntegral n) pDevs
                free pDevs
                pure $ Just $ map (Device a . iiAddr) iis
        case mDevices of
            Just devices -> pure devices
            Nothing      -> go 0  -- eINTR ? Retry.

{-# LINE 149 "Network/Bluetooth/Adapter.hsc" #-}