hlibBladeRF 0.1.0.3 → 0.1.0.4
raw patch · 10 files changed
+167/−64 lines, 10 files
Files
- ChangeLog +16/−0
- hlibBladeRF.cabal +2/−2
- src/LibBladeRF/Flash.hs +7/−5
- src/LibBladeRF/Frequency.hs +9/−9
- src/LibBladeRF/Gain.hs +18/−18
- src/LibBladeRF/Gpio.hs +3/−3
- src/LibBladeRF/LibBladeRF.hs +42/−7
- src/LibBladeRF/Sync.hs +25/−7
- src/LibBladeRF/Types.hs +26/−2
- src/LibBladeRF/Utils.hs +19/−11
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