packages feed

serialport-0.1.0: System/Hardware/Serialport/Windows.hs

module System.Hardware.Serialport.Windows where 

import System.IO
import System.Win32.File
import System.Win32.Types
import Data.Bits
import Control.Concurrent
import System.Win32.Comm
import Foreign.Marshal.Alloc
import Foreign.Marshal.Utils
import Foreign.Storable
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String


data SerialPort = SerialPort HANDLE

openSerial :: String      -- ^ The filename of the serial port, such as @COM5@ or @//./CNCA0@
           -> BaudRate
           -> Int
           -> StopBits
           -> Parity
           -> FlowControl
           -> IO SerialPort
openSerial dev baud bPerB stopBits parity flow = 
    do h <- createFile dev access_mode share_mode security_attr create_mode file_attr template_file
       setSerial h baud bPerB stopBits parity flow
       return $ SerialPort h
    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


setSerial :: HANDLE
           -> BaudRate     
           -> Int          
           -> StopBits     
           -> Parity       
           -> FlowControl
           -> IO ()
setSerial h baud bPerB stopb parit flow = 
    do -- set timeouts
       let ct = COMMTIMEOUTS { 
                    readIntervalTimeout = 0, 
                    readTotalTimeoutMultiplier = 100, 
                    readTotalTimeoutConstant = 0, 
                    writeTotalTimeoutMultiplier = 0, 
                    writeTotalTimeoutConstant = 0 }
       setCommTimeouts h ct
       --print $ show ct

       -- configure DCB structure
       dcb <- getCommState h
       --print $ show dcb

       let dcb' = DCB {
                    baudRate = baud,
                    parity = parit,
                    stopBits = stopb,
                    flowControl = flow,
                    byteSize = bPerB }
       --print $ show dcb'
       setCommState h dcb'

       dcb_check <- getCommState h
       --print $ show dcb_check

       return ()


sendChar :: SerialPort -> Char -> IO ()
sendChar (SerialPort h) s =
    do with s (\ p_s -> do win32_WriteFile h p_s count overlapped 
                           return () )
    where
        count = 1
        overlapped = Nothing


recvChar :: SerialPort -> IO (Maybe Char)
recvChar (SerialPort h) =
    do 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


closeSerial :: SerialPort -> IO ()
closeSerial (SerialPort h) =
    closeHandle h