module System.USB.IO.Synchronous.Enumerator
( enumReadBulk
, enumReadInterrupt
) where
import System.USB.Internal
import Prelude ( (*), fromIntegral, undefined )
import Data.Function ( ($), (.) )
import Data.Eq ( (/=) )
import Data.Bool ( (&&) )
import Data.Int ( Int )
import Data.Maybe ( Maybe(Nothing, Just) )
import Control.Monad ( Monad, return, (>>=), fail )
import System.IO ( IO )
import Text.Show ( show )
import Foreign.Marshal.Alloc ( malloc, mallocBytes, free )
import Foreign.Storable ( Storable, peek, sizeOf )
import Foreign.Ptr ( Ptr, castPtr )
import Bindings.Libusb
import Control.Monad.Trans ( liftIO )
import Control.Monad.CatchIO ( MonadCatchIO, bracket )
import Data.Iteratee.Base ( EnumeratorGM
, StreamG( Chunk )
, IterGV( Done, Cont )
, runIter
, enumErr
, throwErr
)
import Data.Iteratee.Base.StreamChunk ( ReadableChunk (readFromPtr) )
enumReadBulk :: (ReadableChunk s el, MonadCatchIO m)
=> DeviceHandle
-> EndpointAddress
-> Timeout
-> Size
-> EnumeratorGM s el m a
enumReadBulk = enumRead c'libusb_bulk_transfer
enumReadInterrupt :: (ReadableChunk s el, MonadCatchIO m)
=> DeviceHandle
-> EndpointAddress
-> Timeout
-> Size
-> EnumeratorGM s el m a
enumReadInterrupt = enumRead c'libusb_interrupt_transfer
enumRead :: forall s el m a. (ReadableChunk s el, MonadCatchIO m)
=> C'TransferFunc -> DeviceHandle
-> EndpointAddress
-> Timeout
-> Size
-> EnumeratorGM s el m a
enumRead c'transfer devHndl
endpoint
timeout
chunkSize
iter =
genAlloca $ \transferredPtr ->
let bufferSize = chunkSize * sizeOf (undefined :: el)
in genAllocaBytes bufferSize $ \dataPtr ->
let loop i1 = do
err <- liftIO $ c'transfer (getDevHndlPtr devHndl)
(marshalEndpointAddress endpoint)
(castPtr dataPtr)
(fromIntegral bufferSize)
transferredPtr
(fromIntegral timeout)
if err /= c'LIBUSB_SUCCESS &&
err /= c'LIBUSB_ERROR_TIMEOUT
then enumErr (show $ convertUSBException err) i1
else do
t <- liftIO $ peek transferredPtr
s <- liftIO $ readFromPtr dataPtr $ fromIntegral t
r <- runIter i1 $ Chunk s
case r of
Done x _ -> return $ return x
Cont i2 Nothing -> loop i2
Cont _ (Just e) -> return $ throwErr e
in loop iter
genAlloca :: (Storable a, MonadCatchIO m) => (Ptr a -> m b) -> m b
genAlloca = bracketIO malloc free
genAllocaBytes :: (Storable a, MonadCatchIO m) => Int -> (Ptr a -> m b) -> m b
genAllocaBytes n = bracketIO (mallocBytes n) free
bracketIO :: MonadCatchIO m => IO a -> (a -> IO c) -> (a -> m b) -> m b
bracketIO before after = bracket (liftIO before) (liftIO . after)