{-| Module : $Header$ Copyright : (c) 2014 Edward O'Callaghan License : LGPL-2.1 Maintainer : eocallaghan@alterapraxis.com Stability : provisional Portability : portable This module encapsulates the foundational libbladeRF functions commonly used into a Monadic style. This Monadic style avoids passing around references of indirection to the device type and so on. -} {-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS_HADDOCK prune #-} module LibBladeRF.LibBladeRF ( withBladeRF , DeviceHandle(..) , BladeRFError(..) , BladeRFReturnType(..) , bladeRFErrorValue , bladeRFErrorTy ) where import Foreign import Foreign.C.Types import Foreign.C.String import Foreign.Ptr import Control.Exception import Data.Typeable (Typeable, cast) import Data.Maybe import Data.Tuple import Bindings.LibBladeRF -- | Error codes returned by internal libbladeRF functions. data BladeRFError = BLADERF_ERR_UNEXPECTED -- ^ An unexpected failure occurred | BLADERF_ERR_RANGE -- ^ Provided parameter is out of range | BLADERF_ERR_INVAL -- ^ Invalid operation/parameter | BLADERF_ERR_MEM -- ^ Memory allocation error | BLADERF_ERR_IO -- ^ File/Device I/O error | BLADERF_ERR_TIMEOUT -- ^ Operation timed out | BLADERF_ERR_NODEV -- ^ No device(s) available | BLADERF_ERR_UNSUPPORTED -- ^ Operation not supported | BLADERF_ERR_MISALIGNED -- ^ Misaligned flash access | BLADERF_ERR_CHECKSUM -- ^ Invalid checksum | BLADERF_ERR_NO_FILE -- ^ File not found | BLADERF_ERR_UPDATE_FPGA -- ^ An FPGA update is required | BLADERF_ERR_UPDATE_FW -- ^ A firmware update is requied | BLADERF_ERR_TIME_PAST -- ^ Requested timestamp is in the past deriving (Eq, Typeable) instance Show BladeRFError where show BLADERF_ERR_UNEXPECTED = "An unexpected failure occurred" show BLADERF_ERR_RANGE = "Provided parameter is out of range" show BLADERF_ERR_INVAL = "Invalid operation/parameter" show BLADERF_ERR_MEM = "Memory allocation error" show BLADERF_ERR_IO = "File/Device I/O error" show BLADERF_ERR_TIMEOUT = "Operation timed out" show BLADERF_ERR_NODEV = "No device(s) available" show BLADERF_ERR_UNSUPPORTED = "Operation not supported" show BLADERF_ERR_MISALIGNED = "Misaligned flash access" show BLADERF_ERR_CHECKSUM = "Invalid checksum" show BLADERF_ERR_NO_FILE = "File not found" show BLADERF_ERR_UPDATE_FPGA = "An FPGA update is required" show BLADERF_ERR_UPDATE_FW = "A firmware update is requied" show BLADERF_ERR_TIME_PAST = "Requested timestamp is in the past" instance Exception BladeRFError -- | Returned C Error codes -- -- bladeRF library routines return negative values to indicate errors. -- Values >= 0 are used to indicate success. instance Enum BladeRFError where fromEnum = fromJust . flip lookup errors toEnum = fromJust . flip lookup (map swap errors) errors = [ (BLADERF_ERR_UNEXPECTED, c'BLADERF_ERR_UNEXPECTED) , (BLADERF_ERR_RANGE, c'BLADERF_ERR_RANGE) , (BLADERF_ERR_INVAL, c'BLADERF_ERR_INVAL) , (BLADERF_ERR_MEM, c'BLADERF_ERR_MEM) , (BLADERF_ERR_IO, c'BLADERF_ERR_IO) , (BLADERF_ERR_TIMEOUT, c'BLADERF_ERR_TIMEOUT) , (BLADERF_ERR_NODEV, c'BLADERF_ERR_NODEV) , (BLADERF_ERR_UNSUPPORTED, c'BLADERF_ERR_UNSUPPORTED) , (BLADERF_ERR_MISALIGNED, c'BLADERF_ERR_MISALIGNED) , (BLADERF_ERR_CHECKSUM, c'BLADERF_ERR_CHECKSUM) , (BLADERF_ERR_NO_FILE, c'BLADERF_ERR_NO_FILE) , (BLADERF_ERR_UPDATE_FPGA, c'BLADERF_ERR_UPDATE_FPGA) , (BLADERF_ERR_UPDATE_FW, c'BLADERF_ERR_UPDATE_FW) , (BLADERF_ERR_TIME_PAST, c'BLADERF_ERR_TIME_PAST) ] -- | (For internal use) Obtain a 'BladeRFError' type of a C value from the Error codes list. bladeRFErrorValue :: CInt -> BladeRFReturnType Int bladeRFErrorValue c | c >= 0 = (Right . fromIntegral) c -- Success (on ret == 0) | c < 0 = (Left . toEnum . fromIntegral) c -- C ret code to typed error -- | (For internal use) Obtain a 'BladeRFError' type of a C value from the Error codes list. bladeRFErrorTy :: CInt -> BladeRFReturnType () bladeRFErrorTy c | c >= 0 = return () -- Success (on ret == 0) | c < 0 = (Left . toEnum . fromIntegral) c -- C ret code to typed error -- | Short-hand type for brevity and clarity. type BladeRFReturnType a = Either BladeRFError a -- | DeviceHandle wrapper around C device descriptor pointer newtype DeviceHandle = DeviceHandle { unDeviceHandle :: Ptr C'bladerf } -- | Essential wrapper withBladeRF :: (DeviceHandle -> IO c) -> IO c withBladeRF = bracket openBladeRF closeBladeRF -- | Handy helper to wrap around Either results openBladeRF :: IO DeviceHandle openBladeRF = do r <- openBladeRF' case r of Left e -> throwIO e Right dev -> return dev -- Open specified device using a device identifier string. -- See bladerf_open_with_devinfo() if a device identifier string -- is not readily available. openBladeRF' :: IO (BladeRFReturnType DeviceHandle) openBladeRF' = alloca $ \ptr -> do ret <- c'bladerf_open ptr nullPtr if ret /= 0 then return $ (Left . toEnum . fromIntegral) ret else do pdev <- peek ptr return (Right (DeviceHandle pdev)) -- | Close device. Deallocates the memory allocated by openBladeRF when called. closeBladeRF :: DeviceHandle -> IO () closeBladeRF d = c'bladerf_close $ unDeviceHandle d