packages feed

serialport 0.4.7 → 0.6.0

raw patch · 11 files changed

Files

CHANGELOG.md view
@@ -1,6 +1,50 @@+0.6.0 (9/21/2025)+==================+* Remove custom baud rates [22](https://github.com/standardsemiconductor/serialport/pull/22)+* Update package dependency constraints+* Add `serialport` command-line executable [16](https://github.com/standardsemiconductor/serialport/pull/16) +0.5.6 (11/23/2024)+==================+* Add custom baud rates [13](https://github.com/standardsemiconductor/serialport/pull/13)+* Update package dependency constraints -4.7 (28/08/2014)+0.5.5 (1/15/2024)+=================+* Fix runtime error on Windows [6](https://github.com/standardsemiconductor/serialport/pull/6)+* Deprecate String `fdRead` [9](https://github.com/standardsemiconductor/serialport/pull/9)+* Update to unix-2.8 [8](https://github.com/standardsemiconductor/serialport/pull/8)++0.5.4 (12/02/2022)+==================+* Update package dependency constraints+    * base >= 4.12 && < 4.17++0.5.3 (26/09/2021)+==================+* Update package dependency constraints+    * Win32 >= 2.11 && < 2.14+* Add documentation and code samples++0.5.2 (30/3/2021)+=================+* Update package dependency constraints++0.5.1 (16/1/2021)+=================+* Lock Posix serial port for exclusive access+* Simplify internal usage of serial port handles under both Posix and Windows+* Add hWithSerial+* Minor updates to make future refactoring easier++0.5.0 (16/12/2020)+==================+* Derive Show and Read instances for SerialPortSettings, CommSpeed, StopBits, Parity, and FlowControl datatypes.+* Update minimum Cabal-version to 1.10+* Minor syntax changes+* Minor code cleanup++0.4.7 (28/08/2014) ================  * Open in non-blocking mode, immediately reverting to blocking to fix OS-X problem
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 2009, Joris Putcuyps+Copyright (c) 2020, David Cox All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,25 +1,59 @@-Objectives-==========-* Cross platform: at least Linux, Windows and Mac OS.+# Serialport -Tests-=====+[![Haskell CI](https://github.com/standardsemiconductor/serialport/actions/workflows/haskell.yml/badge.svg)](https://github.com/standardsemiconductor/serialport/actions/workflows/haskell.yml)+[![Hackage][hackage-badge]][hackage] -Setup------+Cross platform (Linux, Windows and Mac OS) [serial port](https://en.wikipedia.org/wiki/Serial_port) interface.++## Sample Usage++```haskell+import System.IO+import System.Hardware.Serialport+import qualified Data.ByteString.Char8 as B++let port = "COM3"         -- Windows+let port = "/dev/ttyUSB0" -- Linux+withSerial port defaultSerialSettings $ \s -> do+  send s $ B.pack "AT\r"+  recv s 10 >>= print+```++[Concurrently](https://hackage.haskell.org/package/async) read and write a serial port at 19200 [baud](https://learn.sparkfun.com/tutorials/serial-communication/rules-of-serial) using `hWithSerial`:+```haskell+import Control.Concurrent.Async+import Control.Monad+import System.Hardware.Serialport+import System.IO++com :: String -> IO ()+com portPath = hWithSerial portPath serialPortSettings $ \hndl -> do+  hSetBuffering stdin NoBuffering+  hSetBuffering stdout NoBuffering+  concurrently_ (readUart hndl) (writeUart hndl)+    where+      readUart  hndl = forever $ putChar =<< hGetChar hndl+      writeUart hndl = forever $ hPutChar hndl =<< getChar++serialPortSettings :: SerialPortSettings+serialPortSettings = defaultSerialSettings{ commSpeed = CS19200 }+```++## Tests++### Setup * [Arduino Leonardo](http://arduino.cc/en/Main/arduinoBoardLeonardo) + [Sparkfun FTDI breakout board](https://www.sparkfun.com/products/718). * Connections: TX, RX and GND -Prepare Arduino----------------+### Prepare Arduino * Upload arduino code using Arduino IDE or avrdude -Prepare haskell test program------------------------------* Configure cabal to build the tests: cabal configure --enable-tests.-* Build: cabal build+### Prepare haskell test program+* Configure cabal to build the tests: `cabal configure --enable-tests`.+* Build: `cabal build` -Running the tests-------------------* Run the tests: cabal test --test-options="/dev/ttyACM0 /dev/ttyUSB0"+### Running the tests+* Run the tests: `cabal test --test-options="/dev/ttyACM0 /dev/ttyUSB0"` +[hackage]:       <https://hackage.haskell.org/package/serialport>+[hackage-badge]: <https://img.shields.io/hackage/v/serialport.svg?color=success>
System/Hardware/Serialport.hs view
@@ -6,22 +6,19 @@ -- > import System.Hardware.Serialport -- > let port = "COM3"          -- Windows -- > let port = "/dev/ttyUSB0"  -- Linux--- > s <- openSerial port defaultSerialSettings { commSpeed = CS2400 }--- > send s $ B.pack "AT\r"--- > recv s 10 >>= print--- > closeSerial s+-- > withSerial port defaultSerialSettings{ commSpeed = CS2400 } $ \s -> do+-- >   send s $ B.pack "AT\r"+-- >   recv s 10 >>= print ----- Or use the experimental interface with standard handles:+-- Alternatively, use handles to perform IO: -- -- > import System.IO -- > import System.Hardware.Serialport -- > let port = "COM3"           -- Windows -- > let port = "/dev/ttyUSB0"   -- Linux--- > h <- hOpenSerial port defaultSerialSettings--- > hPutStr h "AT\r"--- > hGetLine h >>= print--- > hClose h-+-- > hWithSerial port defaultSerialSettings $ \h -> do+-- >   hPutStr h "AT\r"+-- >   hGetLine h >>= print  module System.Hardware.Serialport (   -- * Types@@ -42,6 +39,7 @@   ,openSerial   ,closeSerial   ,withSerial+  ,hWithSerial   -- ** Sending & receiving   ,send   ,recv@@ -58,8 +56,14 @@ #endif import System.Hardware.Serialport.Types +import System.IO (Handle, hClose) import qualified Control.Exception as Ex + -- |Safer device function, so you don't forget to close the device-withSerial :: String -> SerialPortSettings -> ( SerialPort -> IO a ) -> IO a+withSerial :: FilePath -> SerialPortSettings -> ( SerialPort -> IO a ) -> IO a withSerial dev settings = Ex.bracket (openSerial dev settings) closeSerial++-- |Like `withSerial` but using `Handle`+hWithSerial :: FilePath -> SerialPortSettings -> (Handle -> IO a) -> IO a+hWithSerial dev settings = Ex.bracket (hOpenSerial dev settings) hClose
+ System/Hardware/Serialport/Cli.hs view
@@ -0,0 +1,114 @@+module System.Hardware.Serialport.Cli+  ( SerialPortCli(..)+  , serialPortCli+  , -- * Parsers+    serialPortCliParser+  , serialPortPathParser+  , serialPortSettingsParser+  , commSpeedParser+  , bitsPerWordParser+  , stopBitsParser+  , parityParser+  , flowControlParser+  , timeoutParser+  ) where++import Data.Word+import Options.Applicative+import System.Hardware.Serialport.Types++data SerialPortCli = SerialPortCli+  { serialPortPath     :: FilePath+  , serialPortSettings :: SerialPortSettings+  }++serialPortCli :: IO SerialPortCli+serialPortCli =+  customExecParser serialPortCliPrefs $+    info (serialPortCliParser <**> helper) mempty++serialPortCliPrefs :: ParserPrefs+serialPortCliPrefs = prefs $ showHelpOnError <> showHelpOnEmpty++serialPortCliParser :: Parser SerialPortCli+serialPortCliParser =+  SerialPortCli+    <$> serialPortPathParser+    <*> serialPortSettingsParser++serialPortPathParser :: Parser FilePath+serialPortPathParser = strArgument $ mconcat+  [ help "serial port file path"+  , metavar "<tty-device>"+  , completer $ bashCompleter "file"+  ]++serialPortSettingsParser :: Parser SerialPortSettings+serialPortSettingsParser =+  SerialPortSettings+    <$> commSpeedParser+    <*> bitsPerWordParser+    <*> stopBitsParser+    <*> parityParser+    <*> flowControlParser+    <*> timeoutParser++commSpeedParser :: Parser CommSpeed+commSpeedParser = option auto $ mconcat+  [ long "baudrate"+  , short 'b'+  , value CS115200+  , showDefault+  , metavar "<bps>"+  , help "Baud rate"+  ]++bitsPerWordParser :: Parser Word8+bitsPerWordParser = option auto $ mconcat+  [ long "databits"+  , short 'd'+  , value $ bitsPerWord defaultSerialSettings+  , showDefault+  , metavar "7|8"+  , help "Data bits"+  ]++stopBitsParser :: Parser StopBits+stopBitsParser = option auto $ mconcat+  [ long "stopbits"+  , short 's'+  , value $ stopb defaultSerialSettings+  , showDefault+  , metavar "One|Two"+  , help "Stop bits"+  ]++parityParser :: Parser Parity+parityParser = option auto $ mconcat+  [ long "parity"+  , short 'p'+  , value $ parity defaultSerialSettings+  , showDefault+  , metavar "Even|Odd|NoParity"+  , help "Parity"+  ]++flowControlParser :: Parser FlowControl+flowControlParser = option auto $ mconcat+  [ long "flow"+  , short 'f'+  , value $ flowControl defaultSerialSettings+  , showDefault+  , metavar "Software|NoFlowControl"+  , help "Flow control"+  ]++timeoutParser :: Parser Int+timeoutParser = option auto $ mconcat+  [ long "timeout"+  , short 't'+  , value $ timeout defaultSerialSettings+  , showDefault+  , metavar "TIME"+  , help "Timeout in tenth-of-seconds"+  ]
System/Hardware/Serialport/Posix.hsc view
@@ -1,82 +1,50 @@-{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable  #-}-{-# OPTIONS_HADDOCK hide #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE DeriveDataTypeable       #-}+{-# LANGUAGE LambdaCase               #-}+{-# OPTIONS_HADDOCK hide              #-} module System.Hardware.Serialport.Posix where -import qualified Data.ByteString.Char8 as B import qualified Control.Exception as Ex-import System.Posix.IO-import System.Posix.Types-import System.Posix.Terminal-import System.Hardware.Serialport.Types-import Foreign (Ptr, castPtr, alloca, peek, with)+import Data.Bits+import qualified Data.ByteString.Char8 as B+import Data.Either+import Data.Typeable+import Foreign (Ptr, nullPtr, castPtr, alloca, peek, with) import Foreign.C import GHC.IO.Handle-import GHC.IO.Device-import GHC.IO.BufferedIO-import Data.Typeable-import GHC.IO.Buffer import GHC.IO.Encoding-import Control.Monad (void)-import Data.Bits---data SerialPort = SerialPort {-                      fd :: Fd,-                      portSettings :: SerialPortSettings-                  }-                  deriving (Typeable)---instance RawIO SerialPort where-  read (SerialPort fd' _) ptr n = return . fromIntegral =<< fdReadBuf fd' ptr (fromIntegral n)-  readNonBlocking _ _ _ = error "readNonBlocking not implemented"-  write (SerialPort fd' _) ptr n = void (fdWriteBuf fd' ptr (fromIntegral n))-  writeNonBlocking _ _ _ = error "writenonblocking not implemented"---instance IODevice SerialPort where-  ready _ _ _ = return True-  close = closeSerial-  isTerminal _ = return False-  isSeekable _ = return False-  seek _ _ _ = return ()-  tell _ = return 0-  getSize _ = return 0-  setSize _ _ = return ()-  setEcho _ _ = return ()-  getEcho _ = return False-  setRaw _ _ = return ()-  devType _ = return Stream---instance BufferedIO SerialPort where-  newBuffer _ = newByteBuffer 100-  fillReadBuffer = readBuf-  fillReadBuffer0 = readBufNonBlocking-  flushWriteBuffer = writeBuf-  flushWriteBuffer0 = writeBufNonBlocking+import System.Hardware.Serialport.Types+import System.Posix.IO+import qualified System.Posix.IO.ByteString as BIO+import System.Posix.Types (Fd)+import System.Posix.Terminal +data SerialPort = SerialPort+  { fd           :: Fd+  , portSettings :: SerialPortSettings+  } deriving (Show, Typeable)  -- |Open and configure a serial port returning a standard Handle hOpenSerial :: FilePath            -> SerialPortSettings            -> IO Handle hOpenSerial dev settings = do-  ser <- openSerial dev settings-  h <- mkDuplexHandle ser dev Nothing noNewlineTranslation+  h <- fdToHandle . fd =<< openSerial dev settings   hSetBuffering h NoBuffering   return h   -- |Open and configure a serial port-openSerial :: FilePath            -- ^ Serial port, such as @\/dev\/ttyS0@ or @\/dev\/ttyUSB0@-           -> SerialPortSettings-           -> IO SerialPort+openSerial+  :: FilePath            -- ^ Serial port, such as @\/dev\/ttyS0@ or @\/dev\/ttyUSB0@+  -> SerialPortSettings+  -> IO SerialPort openSerial dev settings = do-  fd' <- openFd dev ReadWrite Nothing defaultFileFlags { noctty = True, nonBlock = True }+  fd' <- openFd dev ReadWrite defaultFileFlags { noctty = True, nonBlock = True }+  setTIOCEXCL fd'   setFdOption fd' NonBlockingRead False   let serial_port = SerialPort fd' defaultSerialSettings-  return =<< setSerialSettings serial_port settings+  setSerialSettings serial_port settings   -- |Use specific encoding for an action and restore old encoding afterwards@@ -95,28 +63,24 @@  -- |Receive bytes, given the maximum number recv :: SerialPort -> Int -> IO B.ByteString-recv (SerialPort fd' _) n = do-  result <- withEncoding char8 $ Ex.try $ fdRead fd' count :: IO (Either IOError (String, ByteCount))-  case result of-     Right (str, _) -> return $ B.pack str-     Left _         -> return B.empty+recv port n = do+  result <- withEncoding char8 $ Ex.try $ BIO.fdRead (fd port) count :: IO (Either IOError B.ByteString)+  return $ fromRight B.empty result   where     count = fromIntegral n - -- |Send bytes-send :: SerialPort-        -> B.ByteString-        -> IO Int          -- ^ Number of bytes actually sent-send (SerialPort fd' _ ) msg = do-  ret <- withEncoding char8 (fdWrite fd' (B.unpack msg))-  return $ fromIntegral ret+send+  :: SerialPort+  -> B.ByteString+  -> IO Int          -- ^ Number of bytes actually sent+send port msg =+  fromIntegral <$> withEncoding char8 (fdWrite (fd port) (B.unpack msg))   -- |Flush buffers flush :: SerialPort -> IO ()-flush (SerialPort fd' _) =-  discardData fd' BothQueues+flush port = discardData (fd port) BothQueues   -- |Close the serial port@@ -144,6 +108,10 @@   with val $ cIoctl' fd' #{const TIOCMSET}  +setTIOCEXCL :: Fd -> IO ()+setTIOCEXCL fd' = cIoctl' fd' #{const TIOCEXCL} nullPtr++ -- |Set the Data Terminal Ready level setDTR :: SerialPort -> Bool -> IO () setDTR (SerialPort fd' _) set = do@@ -166,11 +134,11 @@ setSerialSettings :: SerialPort           -- ^ The currently opened serial port                   -> SerialPortSettings   -- ^ The new settings                   -> IO SerialPort        -- ^ New serial port-setSerialSettings (SerialPort fd' _) new_settings = do-  termOpts <- getTerminalAttributes fd'+setSerialSettings port new_settings = do+  termOpts <- getTerminalAttributes $ fd port   let termOpts' = configureSettings termOpts new_settings-  setTerminalAttributes fd' termOpts' Immediately-  return (SerialPort fd' new_settings)+  setTerminalAttributes (fd port) termOpts' Immediately+  return $ SerialPort (fd port) new_settings   -- |Get configuration from serial port@@ -230,18 +198,15 @@   commSpeedToBaudRate :: CommSpeed -> BaudRate-commSpeedToBaudRate speed =-    case speed of-      CS110 -> B110-      CS300 -> B300-      CS600 -> B600-      CS1200 -> B1200-      CS2400 -> B2400-      CS4800 -> B4800-      CS9600 -> B9600-      CS19200 -> B19200-      CS38400 -> B38400-      CS57600 -> B57600-      CS115200 -> B115200--+commSpeedToBaudRate = \case+  CS110    -> B110+  CS300    -> B300+  CS600    -> B600+  CS1200   -> B1200+  CS2400   -> B2400+  CS4800   -> B4800+  CS9600   -> B9600+  CS19200  -> B19200+  CS38400  -> B38400+  CS57600  -> B57600+  CS115200 -> B115200
System/Hardware/Serialport/Types.hs view
@@ -3,7 +3,6 @@  import Data.Word - -- | Supported baudrates data CommSpeed   = CS110@@ -17,23 +16,27 @@   | CS38400   | CS57600   | CS115200-  deriving (Show, Eq, Bounded)+  deriving (Show, Read, Eq, Bounded) +data StopBits = One | Two+  deriving (Show, Read, Eq, Bounded) -data StopBits = One | Two deriving (Show, Eq, Bounded)-data Parity = Even | Odd | NoParity deriving (Show, Eq)-data FlowControl = Software | NoFlowControl deriving (Show, Eq)+data Parity = Even | Odd | NoParity+  deriving (Show, Read, Eq) -data SerialPortSettings = SerialPortSettings {-                      commSpeed    :: CommSpeed,   -- ^ baudrate-                      bitsPerWord  :: Word8,       -- ^ Number of bits in a word-                      stopb        :: StopBits,    -- ^ Number of stop bits-                      parity       :: Parity,      -- ^ Type of parity-                      flowControl  :: FlowControl, -- ^ Type of flowcontrol-                      timeout      :: Int          -- ^ Timeout when receiving a char in tenth of seconds-                  }+data FlowControl = Software | NoFlowControl+  deriving (Show, Read, Eq) +data SerialPortSettings = SerialPortSettings+  { commSpeed   :: CommSpeed,   -- ^ baudrate+    bitsPerWord :: Word8,       -- ^ Number of bits in a word+    stopb       :: StopBits,    -- ^ Number of stop bits+    parity      :: Parity,      -- ^ Type of parity+    flowControl :: FlowControl, -- ^ Type of flowcontrol+    timeout     :: Int          -- ^ Timeout when receiving a char in tenth of seconds+  } deriving (Show, Read, Eq) + -- | Most commonly used configuration -- --  - 9600 baud@@ -51,4 +54,3 @@ defaultSerialSettings :: SerialPortSettings defaultSerialSettings =   SerialPortSettings CS9600 8 One NoParity NoFlowControl 1-
System/Hardware/Serialport/Windows.hs view
@@ -2,70 +2,36 @@ {-# OPTIONS_HADDOCK hide #-} module System.Hardware.Serialport.Windows where -import Data.Bits-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Unsafe as BU-import qualified System.Win32.Comm as Comm-import System.Win32.Types-import System.Win32.File-import Foreign.Marshal.Alloc-import System.Hardware.Serialport.Types-import Control.Monad import GHC.IO.Handle-import GHC.IO.Device-import GHC.IO.BufferedIO-import Data.Typeable-import GHC.IO.Buffer --data SerialPort = SerialPort {-                      handle :: HANDLE,-                      portSettings :: SerialPortSettings-                  }-                  deriving (Typeable)+import System.Win32.Types+import System.Win32.File+import qualified System.Win32.Comm as Comm +import Foreign.Marshal.Alloc -instance RawIO SerialPort where-  read (SerialPort h _) ptr n = return . fromIntegral =<< win32_ReadFile h ptr (fromIntegral n) Nothing-  readNonBlocking _ _ _ = error "readNonBlocking not implemented"-  write (SerialPort h _) ptr n = void (win32_WriteFile h ptr (fromIntegral n) Nothing)-  writeNonBlocking _ _ _ = error "writenonblocking not implemented"+import Control.Monad (unless) +import Data.Typeable+import Data.Bits+import qualified Data.ByteString.Char8  as B+import qualified Data.ByteString.Unsafe as BU -instance IODevice SerialPort where-  ready _ _ _ = return True-  close = closeSerial-  isTerminal _ = return False-  isSeekable _ = return False-  seek _ _ _ = return ()-  tell _ = return 0-  getSize _ = return 0-  setSize _ _ = return ()-  setEcho _ _ = return ()-  getEcho _ = return False-  setRaw _ _ = return ()-  devType _ = return Stream+import System.Hardware.Serialport.Types  -instance BufferedIO SerialPort where-  newBuffer _ = newByteBuffer 100-  fillReadBuffer = readBuf-  fillReadBuffer0 = readBufNonBlocking-  flushWriteBuffer = writeBuf-  flushWriteBuffer0 = writeBufNonBlocking-+data SerialPort = SerialPort+  { handle       :: HANDLE+  , portSettings :: SerialPortSettings+  } deriving (Show, Typeable)  -- |Open and configure a serial port returning a standard Handle.-hOpenSerial :: String-           -> SerialPortSettings-           -> IO Handle+hOpenSerial :: String -> SerialPortSettings -> IO Handle hOpenSerial dev settings = do-  ser <- openSerial dev settings-  h <- mkDuplexHandle ser dev Nothing noNewlineTranslation+  h <- hANDLEToHandle . handle =<< openSerial dev settings   hSetBuffering h NoBuffering   return h - -- | Open and configure a serial port openSerial :: String      -- ^ Serial port, such as @COM5@ or @CNCA0@            -> SerialPortSettings@@ -73,7 +39,7 @@ openSerial dev settings = do   h <- createFile ("\\\\.\\" ++ dev) access_mode share_mode security_attr create_mode file_attr template_file   let serial_port = SerialPort h defaultSerialSettings-  return =<< setSerialSettings serial_port settings+  setSerialSettings serial_port settings   where     access_mode = gENERIC_READ .|. gENERIC_WRITE     share_mode = fILE_SHARE_NONE@@ -85,10 +51,9 @@  -- |Receive bytes, given the maximum number recv :: SerialPort -> Int -> IO B.ByteString-recv (SerialPort h _) n =-  allocaBytes n $ \p -> do-    recv_cnt <- win32_ReadFile h p count overlapped-    B.packCStringLen (p, fromIntegral recv_cnt)+recv port n = allocaBytes n $ \p -> do+  recv_cnt <- win32_ReadFile (handle port) p count overlapped+  B.packCStringLen (p, fromIntegral recv_cnt)   where     count = fromIntegral n     overlapped = Nothing@@ -98,9 +63,8 @@ send :: SerialPort         -> B.ByteString         -> IO Int          -- ^ Number of bytes actually sent-send (SerialPort h _) msg =-  BU.unsafeUseAsCString msg $ \p ->-    fromIntegral `fmap` win32_WriteFile h p count overlapped+send port msg = BU.unsafeUseAsCString msg $ \p ->+  fromIntegral `fmap` win32_WriteFile (handle port) p count overlapped   where     count = fromIntegral $ B.length msg     overlapped = Nothing@@ -108,12 +72,10 @@  -- |Flush buffers flush :: SerialPort -> IO ()-flush s@(SerialPort h _) =-  flushFileBuffers h-  >> consumeIncomingChars+flush port = flushFileBuffers (handle port) >> consumeIncomingChars   where     consumeIncomingChars = do-      ch <- recv s 1+      ch <- recv port 1       unless (ch == B.empty) consumeIncomingChars  @@ -124,33 +86,32 @@  -- |Set the Data Terminal Ready level setDTR :: SerialPort -> Bool -> IO ()-setDTR (SerialPort h _ ) True =  Comm.escapeCommFunction h Comm.setDTR-setDTR (SerialPort h _ ) False =  Comm.escapeCommFunction h Comm.clrDTR+setDTR port True  =  Comm.escapeCommFunction (handle port) Comm.setDTR+setDTR port False =  Comm.escapeCommFunction (handle port) Comm.clrDTR   -- |Set the Ready to send level setRTS :: SerialPort -> Bool -> IO ()-setRTS (SerialPort h _ ) True = Comm.escapeCommFunction h Comm.setRTS-setRTS (SerialPort h _ ) False = Comm.escapeCommFunction h Comm.clrRTS+setRTS port True  = Comm.escapeCommFunction (handle port) Comm.setRTS+setRTS port False = Comm.escapeCommFunction (handle port) Comm.clrRTS   -- |Configure the serial port setSerialSettings :: SerialPort           -- ^ The currently opened serial port                   -> SerialPortSettings   -- ^ The new settings                   -> IO SerialPort        -- ^ New serial port-setSerialSettings (SerialPort h _) new_settings = do-  let ct = Comm.COMMTIMEOUTS {-                    Comm.readIntervalTimeout = maxBound :: DWORD,-                    Comm.readTotalTimeoutMultiplier = maxBound :: DWORD,-                    Comm.readTotalTimeoutConstant = fromIntegral (timeout new_settings) * 100,-                    Comm.writeTotalTimeoutMultiplier = 0,-                    Comm.writeTotalTimeoutConstant = 0 }-  Comm.setCommTimeouts h ct--  Comm.setCommState h new_settings--  return (SerialPort h new_settings)-+setSerialSettings port new_settings = do+  Comm.setCommTimeouts (handle port) commTimeouts+  Comm.setCommState (handle port) new_settings+  return $ SerialPort (handle port) new_settings+  where+    commTimeouts = Comm.COMMTIMEOUTS+      { Comm.readIntervalTimeout = maxBound :: DWORD+      , Comm.readTotalTimeoutMultiplier = maxBound :: DWORD+      , Comm.readTotalTimeoutConstant = fromIntegral (timeout new_settings) * 100+      , Comm.writeTotalTimeoutMultiplier = 0+      , Comm.writeTotalTimeoutConstant = 0 +      }  -- |Get configuration from serial port getSerialSettings :: SerialPort -> SerialPortSettings
System/Win32/Comm.hsc view
@@ -37,7 +37,7 @@  instance Storable SerialPortSettings where   sizeOf _ = #{size DCB}-  alignment = sizeOf+  alignment _ = 16   poke buf settings = do     #{poke DCB, DCBlength} buf (sizeOf settings)     #{poke DCB, BaudRate} buf (fromIntegral (commSpeedToBaudRate (commSpeed settings)) :: DWORD)@@ -138,7 +138,7 @@  instance Storable COMMTIMEOUTS where   sizeOf _ = #{size COMMTIMEOUTS}-  alignment = sizeOf+  alignment _ = 16   poke buf ct = do     #{poke COMMTIMEOUTS, ReadIntervalTimeout} buf (readIntervalTimeout ct)     #{poke COMMTIMEOUTS, ReadTotalTimeoutMultiplier} buf ( readTotalTimeoutMultiplier ct)
+ exe/Main.hs view
@@ -0,0 +1,19 @@+import Control.Concurrent.Async+import Control.Monad+import System.Hardware.Serialport+import System.Hardware.Serialport.Cli+import System.IO++main :: IO ()+main = do+  opts <- serialPortCli+  hWithSerial (serialPortPath opts) (serialPortSettings opts) com++com :: Handle -> IO ()+com hndl = do+  hSetBuffering stdin NoBuffering+  hSetBuffering stdout NoBuffering+  concurrently_ readUart writeUart+  where+    readUart  = forever $ putChar =<< hGetChar hndl+    writeUart = forever $ hPutChar hndl =<< getChar
serialport.cabal view
@@ -1,14 +1,15 @@ Name:           serialport-Version:        0.4.7-Cabal-Version:  >= 1.8+Version:        0.6.0+Cabal-Version:  >= 1.10 Build-Type:     Simple license:        BSD3 license-file:   LICENSE-copyright:      (c) 2009-2011 Joris Putcuyps-author:         Joris Putcuyps-maintainer:     Joris.Putcuyps@gmail.com-homepage:       https://github.com/jputcu/serialport-bug-reports:    https://github.com/jputcu/serialport/issues+copyright:      (c) 2009-2011 Joris Putcuyps,+                (c) 2020-2025 David Cox+author:         Joris Putcuyps, David Cox+maintainer:     David Cox <standard.semiconductor@gmail.com>+homepage:       https://github.com/standardsemiconductor/serialport+bug-reports:    https://github.com/standardsemiconductor/serialport/issues synopsis:       Cross platform serial port library. description:    Cross platform haskell library for using the serial port. category:       Hardware@@ -18,26 +19,41 @@  source-repository head   type:     git-  location: git://github.com/jputcu/serialport.git+  location: https://github.com/standardsemiconductor/serialport  Library   Exposed-Modules:    System.Hardware.Serialport+                      System.Hardware.Serialport.Cli   Other-Modules:      System.Hardware.Serialport.Types-  Build-Depends:      base >= 4 && < 5, bytestring-  ghc-options:        -Wall -fno-warn-orphans-+  Build-Depends:      base                 >= 4.12 && < 4.22,+                      bytestring           >= 0.11 && < 0.13,+                      optparse-applicative >= 0.18 && < 0.20+  ghc-options:        -Wall+  default-language: Haskell2010+       if !os(windows)-    Build-Depends:    unix+    Build-Depends:    unix >= 2.8 && < 2.9     Other-Modules:    System.Hardware.Serialport.Posix   else-    Build-Depends:    Win32+    Build-Depends:    Win32 >= 2.11 && < 2.15     Other-Modules:    System.Hardware.Serialport.Windows                       System.Win32.Comm +executable serialport+  ghc-options:        -Wall -O2 -threaded+  main-is:            Main.hs+  hs-source-dirs:     exe+  default-language:   Haskell2010+  build-depends:      async >= 2.2 && < 2.3,+                      base,+                      optparse-applicative >= 0.18 && < 0.19,+                      serialport+ Test-Suite Tests   type:               exitcode-stdio-1.0   main-is:            Tests.hs   hs-source-dirs:     tests+  default-language:   Haskell2010   build-depends:      base,                       HUnit,                       bytestring,