Reputation: 1101
There is a functions in the 'C' wiringPi library with type,
extern void (*pinMode) (int pin, int mode) ;
I tried calling it from haskell using the FFI with FunPtr. So I did,
foreign import ccall unsafe "wiringPi.h &pinMode" c_pinMode
:: FunPtr (CInt -> CInt -> IO ())
foreign import ccall "dynamic" dc_pinMode
:: FunPtr (CInt -> CInt -> IO ()) -> (CInt -> CInt -> IO ())
but for some reason, even though it compiles, it doesn't seem to be calling the function that 'pinMode' points to.
So I tried using normal Foreign.Ptr, thinking I might be able to peek at the Ptr to get a reference to the underlying 'C' function pointed to by 'pinMode'. So I tried,
foreign import ccall "wiringPi.h &pinMode" c_pinMode
:: Ptr (Ptr (CInt -> CInt -> IO ()))
And then, in the implementation of the haskell function that calls 'pinMode' I used peek twice to get a reference to the underlying function. But I keep getting compilation errors where the compiler tell me that the function of type (CInt -> CInt -> IO ())
is not an instance of the 'Storable' typeclass.
So I checked out the storable typeclass, to make (CInt -> CInt -> IO ())
an instance of the storable typeclass.. The minimum implementation required is for peek, poke and a few other functions.. I realized, it really shouldn't be so difficult to call a function that is reference by a pointer..
I feel like I am missing something fundamental. Can someone please point me in the right direction?
Thanks and Regards
Upvotes: 1
Views: 590
Reputation: 3393
Suppose we have a C function pointer defined in foo.c.
void foo(int x, int y)
{
printf("foo: sum = %d\n", x+y);
}
typedef void (*FooPtr) (int, int);
FooPtr fooptr = foo;
In order to call the function that fooptr
points to, we need to not only declare a static address import, but also a dynamic import. The dynamic stub can help us convert FunPtr
values to corresponding Haskell functions.
type Foo = CInt -> CInt -> IO ()
foreign import ccall "foo.c &fooptr" fooptr :: Ptr (FunPtr Foo)
foreign import ccall "dynamic" mkFooFun :: FunPtr Foo -> Foo
main = do
funcptr <- peek fooptr
mkFooFun funcptr 1 2
fooptr
is an imported address that points to a foreign function. Its type is neither Ptr (Ptr a)
nor FunPtr a
.
If we import foo
's address, its type will be FunPtr Foo
. In order to use it, we still need the help from mkFooFun
.
foreign import ccall "foo.c &foo" fooptr2 :: FunPtr Foo
main = mkFooFun fooptr2 1 2
In this example, since we can access foo
, the simplest way to call foo
is
foreign import ccall "foo.c foo" foo :: Foo
main = foo 1 2
Upvotes: 2