packages feed

ftdi 0.3.0.1 → 0.3.0.2

raw patch · 6 files changed

+102/−27 lines, 6 filesdep ~generic-randomdep ~transformersPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: generic-random, transformers

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for ftdi +## 0.3.0.2 -- 2021-09-25++* Update README with code samples and additional resources+* Update generic-random, transformers bounds+ ## 0.3.0.1 -- 2021-06-19  * Update README
README.md view
@@ -1,15 +1,85 @@-# ftdi+# FTDI [![Haskell CI](https://github.com/standardsemiconductor/ftdi/workflows/Haskell%20CI/badge.svg?branch=master)](https://github.com/standardsemiconductor/ftdi/actions/workflows/haskell.yml) [![Hackage][hackage-badge]][hackage] [![Hackage Dependencies][hackage-deps-badge]][hackage-deps] -This library enables you to communicate with FTDI devices. It is implemented as a lightweight wrapper around the [usb](https://hackage.haskell.org/package/usb) library.+This library enables you to communicate with FTDI USB devices. It is implemented as a lightweight wrapper around the [usb](https://hackage.haskell.org/package/usb) library.  See [bindings-libusb](https://hackage.haskell.org/package/bindings-libusb) for instructions to install [libusb](https://libusb.info). +## Build Source (Ubuntu)++```bash+$ sudo apt install libusb-1.0-0-dev+$ git clone https://github.com/standardsemiconductor/ftdi.git+$ cd ftdi/+$ cabal build+$ cabal test+```++## Sample Usage++Find the first USB device matching the vendor ID and product ID:++```haskell+import qualified System.USB as USB+import qualified Data.Vector as V (toList)+import Data.List (find)+import System.FTDI++data Failure = FailureNotFound+             | FailureOther++findUSBDevice +  :: USB.VendorId +  -> USB.ProductId +  -> IO (Either Failure (USB.Device, USB.Ctx))+findUSBDevice vendorId productId = do+  ctx <- USB.newCtx+  devDescs <- getDeviceDescs ctx+  return $ case fst <$> find (match . snd) devDescs of+    Nothing -> Left FailureNotFound+    Just dev -> Right (dev, ctx)+  where+    match :: USB.DeviceDesc -> Bool+    match devDesc =  USB.deviceVendorId  devDesc == vendorId+                  && USB.deviceProductId devDesc == productId++getDeviceDescs :: USB.Ctx -> IO [(USB.Device, USB.DeviceDesc)]+getDeviceDescs ctx = do+  devs <- V.toList <$> USB.getDevices ctx+  deviceDescs <- mapM USB.getDeviceDesc devs+  return $ zip devs deviceDescs+```++Setup an FT2232 FTDI device on interface A using MPSSE (Multi-Protocol Synchronous Serial Engine):++```haskell+withFTDI +  :: USB.VendorId +  -> USB.productId+  -> (InterfaceHandle -> IO (Either Failure a) +  -> IO (Either Failure a)+withFTDI vendorId productId action = findUSBDevice vendorId productId >>= \case+  Left failure -> return $ Left failure+  Right (usbDevice, ctx) -> do+    ftdiDevice <- fromUSBDevice usbDevice ChipType_2232H+    withDeviceHandle ftdiDevice $ \devHndl -> do+      resetUSB devHndl+      withDetachedKernelDriver devHndl Interface_A $+        withInterfaceHandle devHndl Interface_A $ \ifHndl -> do+          reset ifHndl+          purgeReadBuffer ifHndl+          purgeWriteBuffer ifHndl+          setLatencyTimer ifHndl 1+          setBitMode ifHndl 0xFF BitMode_MPSSE+          action ifHndl+```+ ## References * [FTDI Website](https://ftdichip.com/) * [Application Note AN_108](https://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf): Command Processor for MPSSE and MCU Host Bus Emulation Modes+* [USB in a NutShell](https://www.beyondlogic.org/usbnutshell/usb1.shtml): Making sense of the USB standard  [hackage]:            <https://hackage.haskell.org/package/ftdi> [hackage-badge]:      <https://img.shields.io/hackage/v/ftdi.svg?color=success>
System/FTDI/Internal.hs view
@@ -358,21 +358,21 @@              , MonadFix              ) -{-| Run the ChunkedReaderT given an initial state.+{-| Run the 'ChunkedReaderT' given an initial state.  The initial state represents excess bytes carried over from a previous-run. When invoking runChunkedReaderT for the first time you can safely pass the+run. When invoking 'runChunkedReaderT' for the first time you can safely pass the 'BS.empty' bytestring as the initial state.  A contrived example showing how you can manually thread the excess bytes-through subsequent invocations of runChunkedReaderT:+through subsequent invocations of 'runChunkedReaderT':  @-  example &#x2237; 'InterfaceHandle' &#x2192; IO ()+  example :: 'InterfaceHandle' -> IO ()   example ifHnd = do-    (packets1, rest1) &#x2190; runChunkedReaderT ('readData' ifHnd (return 'False') 400) 'BS.empty'+    (packets1, rest1) <- runChunkedReaderT ('readData' ifHnd (return 'False') 400) 'BS.empty'     print $ 'BS.concat' packets1-    (packets2, rest2) &#x2190; runChunkedReaderT ('readData' ifHnd (return 'False') 200) rest1+    (packets2, rest2) <- runChunkedReaderT ('readData' ifHnd (return 'False') 200) rest1     print $ 'BS.concat' packets2 @ @@ -380,12 +380,12 @@ plumbing:  @-  example &#x2237; 'InterfaceHandle' &#x2192; IO ()+  example :: 'InterfaceHandle' -> IO ()   example ifHnd =-    let reader = do packets1 &#x2190; 'readData' ifHnd (return 'False') 400-                    liftIO $ print $ 'BS.concat' packets1-                    packets2 &#x2190; 'readData' ifHnd (return 'False') 200-                    liftIO $ print $ 'BS.concat' packets1+    let reader = do packets1 <- 'readData' ifHnd (return 'False') 400+                    'liftIO' $ print $ 'BS.concat' packets1+                    packets2 <- 'readData' ifHnd (return 'False') 200+                    'liftIO' $ print $ 'BS.concat' packets1     in runChunkedReaderT reader 'BS.empty' @ @@ -395,9 +395,9 @@  {-| Reads data from the given FTDI interface by performing bulk reads. -This function produces an action in the @ChunkedReaderT@ monad that+This function produces an action in the 'ChunkedReaderT' monad that will read exactly the requested number of bytes unless it is-explicitly asked to stop early. Executing the @readData@ action will+explicitly asked to stop early. Executing the 'readData' action will block until either:   * All data are read@@ -409,16 +409,16 @@  Data are read in packets. The function may choose to request more than needed in order to get the highest possible bandwidth. The excess of-bytes is kept as the state of the @ChunkedReaderT@ monad. A subsequent-invocation of @readData@ will first return bytes from the stored state+bytes is kept as the state of the 'ChunkedReaderT' monad. A subsequent+invocation of 'readData' will first return bytes from the stored state before requesting more from the device itself. A consequence of this behaviour is that even when you request 100 bytes the function will actually request 512 bytes (depending on the packet size) and /block/ until all 512 bytes are read! There is no workaround since requesting less bytes than the packet size is an error. -USB timeouts will not interrupt @readData@. In case of a timeout-@readData@ will simply resume reading data. A small USB timeout can+USB timeouts will not interrupt 'readData'. In case of a timeout+'readData' will simply resume reading data. A small USB timeout can degrade performance.  The FTDI latency timer can cause poor performance. If the FTDI chip can't fill@@ -438,7 +438,7 @@  @   -- Read 100 data bytes from ifHnd-  (packets, rest) &#x2190; 'runChunkedReaderT' ('readData' ifHnd (return 'False') 100) 'BS.empty'+  (packets, rest) <- 'runChunkedReaderT' ('readData' ifHnd (return 'False') 100) 'BS.empty' @  -}
System/FTDI/MPSSE.hs view
@@ -54,6 +54,7 @@ import qualified Data.ByteString.Builder as BSB  import Control.Concurrent.Async+import Control.Monad (void)  import qualified System.FTDI as FTDI import System.FTDI (InterfaceHandle)@@ -96,11 +97,11 @@ {-# INLINE opCode #-}  byte :: Word8 -> Command ()-byte o = () <$ transfer (BSB.word8 o) 0+byte o = void $ transfer (BSB.word8 o) 0 {-# INLINE byte #-}  word16 :: Word16 -> Command ()-word16 o = () <$ transfer (BSB.word16LE o) 0+word16 o = void $ transfer (BSB.word16LE o) 0 {-# INLINE word16 #-}  transfer :: BSB.Builder -> Int -> Command BS.ByteString@@ -110,7 +111,7 @@ {-# INLINE transfer #-}  writeByteString :: BS.ByteString -> Command ()-writeByteString bs = () <$ transfer (BSB.byteString bs) 0+writeByteString bs = void $ transfer (BSB.byteString bs) 0 {-# INLINE writeByteString #-}  readN :: Int -> Command BS.ByteString
System/FTDI/Properties.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE GeneralizedNewtypeDeriving            , StandaloneDeriving-           , TemplateHaskell            , UnicodeSyntax   #-} 
ftdi.cabal view
@@ -1,5 +1,5 @@ name:          ftdi-version:       0.3.0.1+version:       0.3.0.2 cabal-version: >=1.10 build-type:    Simple stability:     experimental@@ -32,7 +32,7 @@                , base                 >= 4.5   && < 4.16                , base-unicode-symbols >= 0.1.1 && < 0.3                , bytestring           >= 0.10  && < 0.12-               , transformers         >= 0.5   && < 0.6+               , transformers         >= 0.5   && < 0.7                , usb                  >= 1.3   && < 1.4                , vector               >= 0.12  && < 0.13   default-language: Haskell2010@@ -54,7 +54,7 @@                , base-unicode-symbols                , bytestring                , QuickCheck                 >= 2.11  && < 2.15-               , generic-random             >= 1.3   && < 1.5+               , generic-random             >= 1.3   && < 1.6                , random                     >= 1.0.0 && < 1.3                , tagged                     >= 0.8   && < 0.9                , test-framework             >= 0.8   && < 0.9