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 +5/−0
- README.md +72/−2
- System/FTDI/Internal.hs +18/−18
- System/FTDI/MPSSE.hs +4/−3
- System/FTDI/Properties.hs +0/−1
- ftdi.cabal +3/−3
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 [](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 ∷ 'InterfaceHandle' → IO ()+ example :: 'InterfaceHandle' -> IO () example ifHnd = do- (packets1, rest1) ← runChunkedReaderT ('readData' ifHnd (return 'False') 400) 'BS.empty'+ (packets1, rest1) <- runChunkedReaderT ('readData' ifHnd (return 'False') 400) 'BS.empty' print $ 'BS.concat' packets1- (packets2, rest2) ← 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 ∷ 'InterfaceHandle' → IO ()+ example :: 'InterfaceHandle' -> IO () example ifHnd =- 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+ 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) ← '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