Saturday, December 31, 2011

FFI in Haskell, How to Call Impure C Functions Without Pointers

I started off writing this little parallel port toy program in the Haskell programming language. It didn't seem too ambitious and I knew how to implement this directly in C so it seemed like a good project to try.

The first thing I needed to do was wrap up a few C functions to get inputs and outputs from the parallel ports. These three functions in linux are inb(2), outb(2), iopl(2) and ioperms(2). I opted to wrap up only inb, outb and iopl.

These functions are defined by sys/io.h on Linux. They are defined as static functions so I need to wrap them up in a small C file to create an object file with symbols for haskell to use them easily. Here's the wrapper code that places these functions in the hs_ namespace.
/* Copyright 2011 Zac Slade and released under the GNU Public License version 2 or later */
#include <sys/io.h>

int hs_iopl(int perm)
{
return iopl(perm);
}

unsigned char hs_inb(unsigned short int port)
{
return inb(port);
}

void hs_outb(unsigned char value, unsigned short int port)
{
outb(value,port);
}


I found a lot of good Haskell Foreign Function Interface(FFI) intruductions, but they all showed something more complex than what I was using. Or they wrapped up functions like sin(3) that pretends to have no side effects like pure functions in Haskell.

I ended up making the functions map to c_inb, c_outb and c_iopl to make it easier on me to know when I was using a C function wrapped up by Haskell. Here's how I defined those three functions using the boiler plate code required by the Haskell FFI.

{-# LANGUAGE ForeignFunctionInterface -}
{- Copyright 2011 Zac Slade and licensed under the GNU Public License version 2 or later -}
module ParaPortLinuxIO where
import Foreign.C
import Data.Bits

-- This file implements a wrapper interface for inb/outb and iopl all found in sys/io.h on Linux
-- Due to the nature of the include file and the definition of these symbols a small C wrapper
-- was needed and the functions were placed into the hs_ namespace.

-- Type aliases for use with this module
type CByte = CUChar
type Port = CUShort
type SomeBits = [Int]
type IOPorts = [Port]

-- int iopl(int perm)
foreign import ccall unsafe "hs_iopl"
c_iopl :: CInt -> IO CInt

-- unsigned char inb(unsigned short int port)
foreign import ccall unsafe "hs_inb"
c_inb :: Port -> IO CByte

-- void outb(unsigned char value, unsigned short int port)
foreign import ccall "hs_outb"
c_outb :: CByte -> Port -> IO ()


These functions have no illusions about being pure. As you might have noticed if you are already a Haskeller the functions all operate in the IO Monad to inform the programmer that these should not under any circumstances be treated like pure functions. Also in the above definition we see that both c_iopl and c_inb are marked as unsafe as well. This conveys even more information to the programmer alerting them to the fact that these functions read values from the real world and require state to be carried along with the values.

As you can see above it really doesn't take much code to actually wrap up C library function (even functions defined as static functions). From the above two snippets you can begin using inb(2), outb(2) and iopl(2) in your own Haskell programs.

Happy Haskell Hacking!

Saturday, December 24, 2011

Haskell and Linux Parallel Port I/O

I've been working for a day or so on a Haskell program to perform generic I/O on parallel ports under Linux. As I'm still very new to Haskell I needed a real world problem to solve. This problem was one that is very straightforward in C so I took the plunge and started.

You can grab the code at gitorious.

I/O is not Haskell's strong suite from a newbie's perspective. It's not difficult however. All Haskell programs live in the IO monad. This has some good consequences. You then have access to the do notation which looks terribly imperative to me. That's okay as I know how to write this in C and the do notation makes it easy to follow that road until functional solutions appear.

Thoughts on Haskell So Far...
Using the language is a blast! It's syntax is very terse and the expressiveness is immense. You can write haskell programs on a sheet of paper with a marker and have your friends run them in the living room without a computer... Maybe that's just me(bonus he type checking too). Haskell is a HUGE language with a very extensive library. Part of the fun of Haskell is in the learning and you can stay pretty busy just learning the fundamentals. The good news is that as you learn the fundamentals you can quickly begin taking advantage of the libraries to make programs that do very complicated things with just a few type declarations and a handful of generic functions.

Just to show off the flexibility of Haskell, if you use GHC you can compile your programs to native byte code, llvm byte code, run them interactively or use them like shell scripts using the runhaskell tool.