I have a fairly thorough understanding of how to open and use a serial
port with the Windows API. In particular, to open a serial port, I
have to use CreateFile, which is the same API call that opens files.
In fact, if I call openFile from GHC, and pass "COM1:" as the
filename, then I can get a writable serial port.
> module Serial
> where
> import System.IO
>
> main = do
> h <- openFile "COM1:" ReadWriteMode
> hPutStrLn h "Hello World"
I can't read from the port (I always get an immediate EOF), and I have
no way of configuring things like the baud rate or the parity
settings. Nevertheless, this demonstrates that openFile can at least
open the serial port.
What I would like to do is create some functions that would allow me
to open and configure a serial port, and get a Handle back so that I
can use the existing IO functions like hGetChar and hPutChar. I am
assuming that hGetChar eventually calls win32::ReadFile and hPutChar
eventually calls win32::WriteFile. These same two API calls would
work for serial ports.
In Windows, there are 23 API functions that apply specifically to
serial ports. Out of these 23 functions, only a few of them are
actually necessary if I just want to send and receive data.
Of course, I don't know how to call Windows API functions from Haskell,
and I have no idea how to hook things to the IO library so that I can
use a Handle for a serial port. I'm looking for some advice on how to
proceed.
-- Ron
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
> Of course, I don't know how to call Windows API functions from Haskell,
> and I have no idea how to hook things to the IO library so that I can
> use a Handle for a serial port. I'm looking for some advice on how to
> proceed.
You can check how I did this in my Lego Mindstorms NXT interface,
pre-beta version:
http://www.forzanka.si/files/NXT.tgz
It is for UNIX (POSIX?) systems but I had similar problems so I had to
use FFI (foreign function interface) to setup a link. You will
probably just have to replace that with Windows API calls. I hope.
Mitar
At the moment, I think it is easier to just use the same Windows API directly,
rather than try to bend GHC's IO system to do it "right".
> have to use CreateFile, which is the same API call that opens files.
> In fact, if I call openFile from GHC, and pass "COM1:" as the
> filename, then I can get a writable serial port.
>
> > module Serial
> > where
> > import System.IO
> >
> > main = do
> > h <- openFile "COM1:" ReadWriteMode
> > hPutStrLn h "Hello World"
>
> I can't read from the port (I always get an immediate EOF), and I have
> no way of configuring things like the baud rate or the parity
> settings. Nevertheless, this demonstrates that openFile can at least
> open the serial port.
>
> What I would like to do is create some functions that would allow me
> to open and configure a serial port, and get a Handle back so that I
> can use the existing IO functions like hGetChar and hPutChar. I am
> assuming that hGetChar eventually calls win32::ReadFile and hPutChar
> eventually calls win32::WriteFile. These same two API calls would
> work for serial ports.
Unfortunately, it goes via extra hoops and uses c runtime instead of
Windows API directly. This extra layer makes sure it's hard to predict
exactly what gets done (and with what options) sometimes.
And even if it did, it'd probably use overlapping io, does that work with
COM ports?
> In Windows, there are 23 API functions that apply specifically to
> serial ports. Out of these 23 functions, only a few of them are
> actually necessary if I just want to send and receive data.
>
> Of course, I don't know how to call Windows API functions from Haskell,
> and I have no idea how to hook things to the IO library so that I can
> use a Handle for a serial port. I'm looking for some advice on how to
> proceed.
I haven't done much work on COM ports, but the little I did, I used bindings
in Win32 and probably some of my own, and didn't use System.IO/Handle
at all. Maybe problems with GHC's IO system are easy to solve, but I have
no idea and wasn't inclined to find out.
Best regards,
Esa
Ideally, we would have something like pyserial (
http://pyserial.sourceforge.net ) for Haskell. It provides a nice
portable abstraction over serial communication. See for example the
windows binding:
http://pyserial.cvs.sourceforge.net/pyserial/pyserial/serial/serialwin32.py?view=markup
regards,
Bas van Dijk
That's really cool! I hope you can upload this to hackage soon.
-- Don
> > You can check how I did this in my Lego Mindstorms NXT interface,
> > pre-beta version:
> >
> > http://www.forzanka.si/files/NXT.tgz
>
> That's really cool! I hope you can upload this to hackage soon.
I do not think it is ready yet. It is working but it is missing
extensive testing (making some bigger programs in practice, to see how
it behaves and to see if the API is sane) and of course documentation
(how to use it, examples, tutorials ...). I will continue with this
project in a few months.
(The main reason is that I do not have any experience with Hackage and
Cabal nor I have time now for this. But if anybody wants to help ...)
I am using it in my AI robot research project where I am using Lego
Mindstorms NXT unit and communicating with it over Bluetooth. And the
AI is made in Haskell. :-)
Mitar
I figured out FFI and marshaling, and I got my serial port to work in
Haskell. See http://ronguida.home.mindspring.com/ for a simple
demonstration. To test this program, I connected my COM1 and COM2
ports with a null-modem cable and I used Hyperterminal to talk to
COM2.
The demo only does a few things: open a serial port, configure it,
write to it, and read from it.
I have some questions regarding this demonstration:
1. In the DCB and COMMTIMEOUTS datatypes and their marshaling code,
is it better to convert Win32 datatypes to Haskell equivalents
(e.g. DWORD to Int), like I did with DCB, or is it better to leave
things in machine types like I did with COMMTIMEOUTS (e.g. DWORD to
Word32) ?
2. Can anyone tell me whether I am making proper use of
unsafeInterleaveIO in my implementation of getContentsSerialPort?
I am interested in creating a library for serial ports under Win32,
and I'm wondering, how should I proceed?