packages feed

hlibBladeRF 0.1.0.3 → 0.1.0.4

raw patch · 10 files changed

+167/−64 lines, 10 files

Files

ChangeLog view
@@ -1,3 +1,19 @@+Changes in 0.1.0.4++* No need to explicitly pass #. of samples to bladeRFSyncTx+  since we already have length encoded in the ByteString.+* Ensure we close the device resource on exception within+  the bracket of 'withBladeRF'.+* Generalise bladerf_open() error handling.+* Wrap C return error codes such that they are translated+  into typed values of BladeRFError.+* Provide a primitives to wrap C rets.+* Map C err values to BladeRFError type.+* Docs - Make a note about the pre-conditions of+  bladeRFSynx{R,T}x action calls.+* Bind bladerf_log_set_verbosity().+* Use 'BLADERF_SERIAL_LENGTH' const over hard-coded const '33'.+ Changes in 0.1.0.3  * HLint clean project.
hlibBladeRF.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                hlibBladeRF-version:             0.1.0.3+version:             0.1.0.4 synopsis:            Haskell binding to libBladeRF SDR library description:         IO Monadic binding for libbladeRF software defined radio. homepage:            https://victoredwardocallaghan.github.io/hlibBladeRF@@ -77,4 +77,4 @@   type:                git   location:            git://github.com/victoredwardocallaghan/hlibBladeRF   branch:              master-  tag:                 v0.1.0.3+  tag:                 v0.1.0.4
src/LibBladeRF/Flash.hs view
@@ -31,8 +31,10 @@ bladeRFEraseFlash :: DeviceHandle  -- ^ Device handle                   -> Word32        -- ^ Erase block to start erasing at                   -> Word32        -- ^ Number of blocks to erase.-                  -> IO CInt-bladeRFEraseFlash dev = c'bladerf_erase_flash (unDeviceHandle dev)+                  -> IO (Either BladeRFError ())+bladeRFEraseFlash dev b n = do+  ret <- c'bladerf_erase_flash (unDeviceHandle dev) b n+  return $ bladeRFErrorTy ret  -- | Read data from the bladeRF's SPI flash. --@@ -51,9 +53,9 @@                   -> BS.ByteString    -- ^ Data to write to flash                   -> Word32           -- ^ page  Page to begin writing at                   -> Word32           -- ^ count-                  -> IO ()+                  -> IO (Either BladeRFError ()) bladeRFWriteFlash dev b p c = allocaBytes (fromIntegral $ p * c'BLADERF_FLASH_PAGE_SIZE) $ \bptr -> do   -- XXX - Buffer allocation size must be `page` * BLADERF_FLASH_PAGE_SIZE bytes or larger.   pokeArray bptr (BS.unpack b) -- XXX can we overflow here??-  _ <- c'bladerf_write_flash (unDeviceHandle dev) bptr p c-  return () -- ignore ret+  ret <- c'bladerf_write_flash (unDeviceHandle dev) bptr p c+  return $ bladeRFErrorTy ret
src/LibBladeRF/Frequency.hs view
@@ -28,10 +28,10 @@ -- | Write value to VCTCXO DAC. bladeRFDACWrite :: DeviceHandle -- ^ Device handle                 -> Word16       -- ^ Data to write to DAC register-                -> IO ()+                -> IO (Either BladeRFError ()) bladeRFDACWrite dev v = do-  c'bladerf_dac_write (unDeviceHandle dev) v-  return () -- ignores ret+  ret <- c'bladerf_dac_write (unDeviceHandle dev) v+  return $ bladeRFErrorTy ret  -- | Get module's current frequency in Hz. bladeRFGetFrequency :: DeviceHandle  -- ^ Device handle@@ -47,10 +47,10 @@ bladeRFSetFrequency :: DeviceHandle  -- ^ Device handle                     -> BladeRFModule -- ^ Module to configure                     -> Int           -- ^ Desired frequency-                    -> IO ()+                    -> IO (Either BladeRFError ()) bladeRFSetFrequency dev m f = do-  c'bladerf_set_frequency (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral f)-  return () -- ignores ret+  ret <- c'bladerf_set_frequency (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral f)+  return $ bladeRFErrorTy ret  -- | Obtain the current value of the specified configuration parameter. bladeRFGetCorrection :: DeviceHandle       -- ^ Device handle@@ -66,7 +66,7 @@                      -> BladeRFModule     -- ^ Module to apply correction to                      -> BladeRFCorrection -- ^ Correction type                      -> Word16            -- ^ Value to apply-                     -> IO ()+                     -> IO (Either BladeRFError ()) bladeRFSetCorrection dev m c v = do-  c'bladerf_set_correction (unDeviceHandle dev) ((fromIntegral . fromEnum) m) ((fromIntegral . fromEnum) c) v-  return () -- ignores ret+  ret <- c'bladerf_set_correction (unDeviceHandle dev) ((fromIntegral . fromEnum) m) ((fromIntegral . fromEnum) c) v+  return $ bladeRFErrorTy ret
src/LibBladeRF/Gain.hs view
@@ -40,10 +40,10 @@ -- | Set the PA gain in dB. bladeRFSetTXVGA2 :: DeviceHandle -- ^ Device handle                  -> Int          -- ^ Desired gain-                 -> IO ()+                 -> IO (Either BladeRFError ()) bladeRFSetTXVGA2 dev g = do-  c'bladerf_set_txvga2 (unDeviceHandle dev) (fromIntegral g)-  return () -- ignores ret+  ret <- c'bladerf_set_txvga2 (unDeviceHandle dev) (fromIntegral g)+  return $ bladeRFErrorTy ret  -- | Get the PA gain in dB. bladeRFGetTXVGA2 :: DeviceHandle -- ^ Device handle@@ -57,10 +57,10 @@ -- | Set the post-LPF gain in dB. bladeRFSetTXVGA1 :: DeviceHandle         -- ^ Device handle                  -> BladeRFVGAGainBounds -- ^ Desired gain-                 -> IO ()+                 -> IO (Either BladeRFError ()) bladeRFSetTXVGA1 dev g = do-  c'bladerf_set_txvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)-  return () -- ignores ret+  ret <- c'bladerf_set_txvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)+  return $ bladeRFErrorTy ret  -- | Get the post-LPF gain in dB. bladeRFGetTXVGA1 :: DeviceHandle -- ^ Device handle@@ -74,10 +74,10 @@ -- | Set the post-LPF VGA gain. bladeRFSetRXVGA2 :: DeviceHandle         -- ^ Device handle                  -> BladeRFVGAGainBounds -- ^ Desired gain-                 -> IO ()+                 -> IO (Either BladeRFError ()) bladeRFSetRXVGA2 dev g = do-  c'bladerf_set_rxvga2 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)-  return () -- ignores ret+  ret <- c'bladerf_set_rxvga2 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)+  return $ bladeRFErrorTy ret  -- | Get the post-LPF VGA gain. bladeRFGetRXVGA2 :: DeviceHandle -- ^ Device handle@@ -91,10 +91,10 @@ -- | Set the pre-LPF VGA gain. bladeRFSetRXVGA1 :: DeviceHandle         -- ^ Device handle                  -> BladeRFVGAGainBounds -- ^ Desired gain-                 -> IO ()+                 -> IO (Either BladeRFError ()) bladeRFSetRXVGA1 dev g = do-  c'bladerf_set_rxvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)-  return () -- ignores ret+  ret <- c'bladerf_set_rxvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)+  return $ bladeRFErrorTy ret  -- | Get the pre-LPF VGA gain. bladeRFGetRXVGA1 :: DeviceHandle -- ^ Device handle@@ -108,10 +108,10 @@ -- | Set LNA Gain. bladeRFSetLNAGain :: DeviceHandle   -- ^ Device handle                   -> BladeRFLNAGain -- ^ Desired gain level-                  -> IO ()+                  -> IO (Either BladeRFError ()) bladeRFSetLNAGain dev g = do-  c'bladerf_set_lna_gain (unDeviceHandle dev) ((fromIntegral . fromEnum) g)-  return () -- ignores ret+  ret <- c'bladerf_set_lna_gain (unDeviceHandle dev) ((fromIntegral . fromEnum) g)+  return $ bladeRFErrorTy ret  -- | Get LNA Gain. bladeRFGetLNAGain :: DeviceHandle      -- ^ Device handle@@ -130,7 +130,7 @@ bladeRFSetGain :: DeviceHandle  -- ^ Device handle                -> BladeRFModule -- ^ Module                -> Int           -- ^ Desired gain-               -> IO ()+               -> IO (Either BladeRFError ()) bladeRFSetGain dev m g = do-  c'bladerf_set_gain (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral g)-  return () -- ignores ret+  ret <- c'bladerf_set_gain (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral g)+  return $ bladeRFErrorTy ret
src/LibBladeRF/Gpio.hs view
@@ -35,7 +35,7 @@ -- accidentally clearing other GPIO bits that may be set by the library internally. bladeRFConfigGPIOWrite :: DeviceHandle -- ^ Device handle                        -> Word32       -- ^ Data to write to GPIO register-                       -> IO ()+                       -> IO (Either BladeRFError ()) bladeRFConfigGPIOWrite dev v = do-  c'bladerf_config_gpio_write (unDeviceHandle dev) v-  return () -- ignores ret+  ret <- c'bladerf_config_gpio_write (unDeviceHandle dev) v+  return $ bladeRFErrorTy ret
src/LibBladeRF/LibBladeRF.hs view
@@ -18,6 +18,8 @@ module LibBladeRF.LibBladeRF ( withBladeRF                              , DeviceHandle(..)                              , BladeRFError(..)+                             , bladeRFErrorValue+                             , bladeRFErrorTy                              ) where  import Foreign@@ -27,6 +29,8 @@  import Control.Exception import Data.Typeable (Typeable, cast)+import Data.Maybe+import Data.Tuple  import Bindings.LibBladeRF @@ -46,7 +50,7 @@                   | 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 (Typeable)+                   deriving (Eq, Typeable)  instance Show BladeRFError where   show BLADERF_ERR_UNEXPECTED  = "An unexpected failure occurred"@@ -66,15 +70,46 @@  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 -> Either BladeRFError 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 -> Either BladeRFError ()+bladeRFErrorTy c | c >= 0 = return ()                        -- Success (on ret == 0)+                 | c <  0 = (Left . toEnum . fromIntegral) c -- C ret code to typed error+ -- | DeviceHandle wrapper around C device descriptor pointer newtype DeviceHandle = DeviceHandle { unDeviceHandle :: Ptr C'bladerf }  -- | Essential wrapper-withBladeRF :: (DeviceHandle -> IO a) -> IO ()-withBladeRF body = do-  dev <- openBladeRF-  body dev-  closeBladeRF dev+withBladeRF :: (DeviceHandle -> IO c) -> IO c+withBladeRF  = bracket openBladeRF closeBladeRF  -- | Handy helper to wrap around Either results openBladeRF :: IO DeviceHandle@@ -91,7 +126,7 @@ openBladeRF'  = alloca $ \ptr -> do   ret <- c'bladerf_open ptr nullPtr   if ret /= 0 then-    return (Left BLADERF_ERR_NODEV) -- is this the right error in every case?+    return $ (Left . toEnum . fromIntegral) ret   else do     pdev <- peek ptr     return (Right (DeviceHandle pdev))
src/LibBladeRF/Sync.hs view
@@ -44,11 +44,11 @@                   -> Int           -- ^ The size of the underlying stream buffers, in samples. This value must be a multiple of 1024.                   -> Int           -- ^ The number of active USB transfers that may be in-flight at any given time.                   -> Int           -- ^ Timeout (milliseconds) for transfers in the underlying data stream.-                  -> IO ()+                  -> IO (Either BladeRFError ())  bladeRFSyncConfig dev m f nb sz tr to = do-  c'bladerf_sync_config (unDeviceHandle dev) ((fromIntegral . fromEnum) m) ((fromIntegral . fromEnum) f) (fromIntegral nb) (fromIntegral sz) (fromIntegral tr) (fromIntegral to)-  return () -- ignores ret+  ret <- c'bladerf_sync_config (unDeviceHandle dev) ((fromIntegral . fromEnum) m) ((fromIntegral . fromEnum) f) (fromIntegral nb) (fromIntegral sz) (fromIntegral tr) (fromIntegral to)+  return $ bladeRFErrorTy ret  -- | Transmit IQ samples. --@@ -59,20 +59,29 @@ -- Samples will only be sent to the FPGA when a buffer have been filled. The -- number of samples required to fill a buffer corresponds to the `buffer_size` -- parameter passed to 'bladeRFSyncConfig'.+--+-- Precondition:+--+--   1. A 'bladeRFSyncConfig' call has been to configure the device+--      for synchronous data transfer.+--+--   2. A call to 'LibBladeRF.Utils.bladeRFEnableModule' should be+--      made before attempting to transmit samples. Failing to do+--      this may result in timeouts and other errors. bladeRFSyncTx :: DeviceHandle          -- ^ Device handle               -> BS.ByteString         -- ^ Array of samples-              -> Int                   -- ^ Number of samples to write               -> Maybe BladeRFMetadata -- ^ Sample metadata. This must be provided when using                                        --   the 'FORMAT_SC16_Q11_META' format, but may                                        --   be 'Nothing' when the interface is configured for                                        --   the 'FORMAT_SC16_Q11' format.               -> Int                   -- ^ Timeout (milliseconds) for this call to complete. Zero implies infinite.               -> IO ()-bladeRFSyncTx dev s n md t = do+bladeRFSyncTx dev s md t = do+  -- The number of samples to write is the length of the bytestring `div` by (|IQ|=2 * |int16_t|=2)=4   alloca $ \pmd ->     case md of       Nothing -> BS.useAsCStringLen s $-                   \(p, _len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral n) nullPtr (fromIntegral t)+                   \(p, len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral $ len `div` 4) nullPtr (fromIntegral t)       Just md -> do                  -- Use the following instead when switching to ghc7.8 later..                  -- bladeRFMetadataToCBladeRFMetadata :: BladeRFMetadata -> C'bladerf_metadata@@ -84,7 +93,7 @@                                                }                  poke pmd meta                  BS.useAsCStringLen s $-                   \(p, _len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral n) pmd (fromIntegral t)+                   \(p, len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral $ len `div` 4) pmd (fromIntegral t)   return () -- XXX ignores ret  -- | Receive IQ samples.@@ -92,6 +101,15 @@ -- Underthe hood, this call starts up an underlying asynchronous stream as -- needed. This stream can be stopped by disabling the RX module. (See -- 'LibBladeRF.Utils.bladeRFEnableModule' for more details.)+--+-- Precondition:+--+--   1. A 'bladeRFSyncConfig' call has been to configure the device+--      for synchronous data transfer.+--+--   2. A call to 'LibBladeRF.Utils.bladeRFEnableModule' should be+--      made before attempting to transmit samples. Failing to do+--      this may result in timeouts and other errors. bladeRFSyncRx :: DeviceHandle    -- ^ Device handle               -> Int             -- ^ Number of samples to read               -> Int             -- ^ Timeout (milliseconds) for this call to complete. Zero implies infinite.
src/LibBladeRF/Types.hs view
@@ -12,7 +12,8 @@ -- {-# LANGUAGE Trustworthy, DeriveGeneric #-} {-# LANGUAGE Trustworthy #-} -module LibBladeRF.Types ( BladeRFVersion(..)+module LibBladeRF.Types ( BladeRFLogLevel(..)+                        , BladeRFVersion(..)                         , BladeRFDeviceInfo(..)                         , BladeRFFPGASize(..)                         , BladeRFBackend(..)@@ -40,6 +41,29 @@ --import Data.Coerce --import GHC.Generics +-- | Severity levels for logging actions+data BladeRFLogLevel = LOG_LEVEL_VERBOSE  -- ^ Verbose level logging+                     | LOG_LEVEL_DEBUG    -- ^ Debug level logging+                     | LOG_LEVEL_INFO     -- ^ Information level logging+                     | LOG_LEVEL_WARNING  -- ^ Warning level logging+                     | LOG_LEVEL_ERROR    -- ^ Error level logging+                     | LOG_LEVEL_CRITICAL -- ^ Fatal error level logging+                     | LOG_LEVEL_SILENT   -- ^ No output+                     deriving (Eq)++instance Enum BladeRFLogLevel where+  fromEnum = fromJust . flip lookup loglevels+  toEnum   = fromJust . flip lookup (map swap loglevels)++loglevels = [ (LOG_LEVEL_VERBOSE, c'BLADERF_LOG_LEVEL_VERBOSE)+            , (LOG_LEVEL_DEBUG, c'BLADERF_LOG_LEVEL_DEBUG)+            , (LOG_LEVEL_INFO, c'BLADERF_LOG_LEVEL_INFO)+            , (LOG_LEVEL_WARNING, c'BLADERF_LOG_LEVEL_WARNING)+            , (LOG_LEVEL_ERROR, c'BLADERF_LOG_LEVEL_ERROR)+            , (LOG_LEVEL_CRITICAL, c'BLADERF_LOG_LEVEL_CRITICAL)+            , (LOG_LEVEL_SILENT, c'BLADERF_LOG_LEVEL_SILENT)+            ]+ -- | Version structure for FPGA, firmware, libbladeRF, and associated utilities. data BladeRFVersion = BladeRFVersion { major :: Word16 -- ^ Major version                                      , minor :: Word16 -- ^ Minor version@@ -145,7 +169,7 @@        Samples consist of interleaved IQ value pairs, with I being the first       value in the pair. Each value in the pair is a right-aligned,-      little-endian int16_t. The FPGA ensures that these values are+      little-endian 'Int16'. The FPGA ensures that these values are       sign-extended.        When using this format the minimum required buffer size, in bytes, is:
src/LibBladeRF/Utils.hs view
@@ -9,7 +9,8 @@   This module encapsulates misc libbladeRF library functions. -} -module LibBladeRF.Utils ( bladeRFLibVersion+module LibBladeRF.Utils ( bladeRFLogSetVerbosity+                        , bladeRFLibVersion                         , bladeRFFwVersion                         , bladeRFFPGAVersion                         , bladeRFDeviceSpeed@@ -30,6 +31,13 @@ import LibBladeRF.LibBladeRF import LibBladeRF.Types +-- | Sets the filter level for displayed log messages.+--+-- Messages that are at or above the specified log level will be printed, while+-- messages with a lower log level will be suppressed.+bladeRFLogSetVerbosity :: BladeRFLogLevel -- ^ The new log level filter value+                       -> IO ()+bladeRFLogSetVerbosity l = c'bladerf_log_set_verbosity $ (fromIntegral . fromEnum) l  -- internal use only toBladeRFVer :: C'bladerf_version -> String -> BladeRFVersion@@ -83,11 +91,11 @@ -- power cycle. Pass Full path to FPGA bitstream. bladeRFLoadFPGA :: DeviceHandle -- ^ Device handle                 -> String       -- ^ Full path to FPGA bitstream-                -> IO ()+                -> IO (Either BladeRFError ()) bladeRFLoadFPGA dev s = do   p <- newCString s-  _ <- c'bladerf_load_fpga (unDeviceHandle dev) p-  return ()+  ret <- c'bladerf_load_fpga (unDeviceHandle dev) p+  return $ bladeRFErrorTy ret  -- | Obtain the bus speed at which the device is operating. bladeRFDeviceSpeed :: DeviceHandle    -- ^ Device handle@@ -115,7 +123,7 @@ -- | Query a device's serial number. bladeRFGetSerial :: DeviceHandle -- ^ Device handle                  -> IO String    -- ^ Returned serial number.-bladeRFGetSerial dev = allocaBytes 34 $ \cstring -> do+bladeRFGetSerial dev = allocaBytes (c'BLADERF_SERIAL_LENGTH + 1) $ \cstring -> do   -- API bug bladerf_get_serial() should be allocating the buffer itself, not the call site!   -- See upstream report: https://github.com/Nuand/bladeRF/issues/382   -- device serial is 33 bytes long + null terminating byte.@@ -138,10 +146,10 @@ bladeRFEnableModule :: DeviceHandle  -- ^ Device handle                     -> BladeRFModule -- ^ Device module                     -> Bool          -- ^ 'True' to enable, 'False' to disable-                    -> IO ()+                    -> IO (Either BladeRFError ()) bladeRFEnableModule dev m t = do-  c'bladerf_enable_module (unDeviceHandle dev) ((fromIntegral . fromEnum) m) t-  return () -- XXX ignore ret+  ret <- c'bladerf_enable_module (unDeviceHandle dev) ((fromIntegral . fromEnum) m) t+  return $ bladeRFErrorTy ret  -- | Apply specified loopback mode. --@@ -151,10 +159,10 @@ bladeRFSetLoopback :: DeviceHandle    -- ^ Device handle                    -> BladeRFLoopback -- ^ Loopback mode. Note that 'LB_NONE'                                       --   disables the use of loopback functionality.-                   -> IO ()+                   -> IO (Either BladeRFError ()) bladeRFSetLoopback dev l = do-  c'bladerf_set_loopback (unDeviceHandle dev) ((fromIntegral . fromEnum) l)-  return () -- XXX ignore ret+  ret <- c'bladerf_set_loopback (unDeviceHandle dev) ((fromIntegral . fromEnum) l)+  return $ bladeRFErrorTy ret  -- | Get current loopback mode. bladeRFGetLoopback :: DeviceHandle       -- ^ Device handle