serialport-0.4.2: System/Hardware/Serialport/Windows.hs
{-# OPTIONS_HADDOCK hide #-}
module System.Hardware.Serialport.Windows where
import Data.Bits
import qualified System.Win32.Comm as Comm
import System.Win32.Types
import System.Win32.File
import Foreign.C.Types
import Foreign.C.String
import Foreign.Marshal.Utils
import Foreign.Marshal.Alloc
import Foreign.Storable
import System.Hardware.Serialport.Types
-- | Open and configure a serial port
openSerial :: String -- ^ The filename of the serial port, such as @COM5@ or @\/\/.\/CNCA0@
-> SerialPortSettings
-> IO SerialPort
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
where
access_mode = gENERIC_READ .|. gENERIC_WRITE
share_mode = fILE_SHARE_NONE
security_attr = Nothing
create_mode = oPEN_EXISTING
file_attr = fILE_ATTRIBUTE_NORMAL -- .|. fILE_FLAG_OVERLAPPED
template_file = Nothing
-- |Possibly receive a character unless the timeout given in openSerial is exceeded.
recvChar :: SerialPort -> IO (Maybe Char)
recvChar (SerialPort h _) =
allocaBytes 1 $ \ p_n -> do
received <- win32_ReadFile h p_n count overlapped
if received == 0
then return Nothing
else do c <- peek p_n :: IO CChar
return $ Just $ castCCharToChar c
where
count = 1
overlapped = Nothing
-- |Receive a string
recvString :: SerialPort -> IO String
recvString (SerialPort h _) =
allocaBytes 128 $ \ p_n -> do
recv_cnt <- win32_ReadFile h p_n count overlapped
peekCStringLen (p_n, fromIntegral recv_cnt)
where
count = 128
overlapped = Nothing
-- |Send a character
sendChar :: SerialPort -> Char -> IO ()
sendChar (SerialPort h _) s =
with s (\ p_s -> do _ <- win32_WriteFile h p_s count overlapped
return () )
where
count = 1
overlapped = Nothing
-- |Send a string
sendString :: SerialPort -> String -> IO ()
sendString (SerialPort h _) s =
withCString s (\ p_s -> do _ <- win32_WriteFile h p_s (fromIntegral count) overlapped
return () )
where
count = length s
overlapped = Nothing
-- |Flush buffers
flush :: SerialPort -> IO ()
flush (SerialPort h _) =
flushFileBuffers h
-- |Close the serial port
closeSerial :: SerialPort -> IO ()
closeSerial (SerialPort h _) =
closeHandle h
-- |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
-- |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
-- |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)
-- |Get configuration from serial port
getSerialSettings :: SerialPort -> SerialPortSettings
getSerialSettings (SerialPort _ settings) = settings