Access to GPIO on Raspberry Pi?

I am doing a little reading around before beginning a project and looking to use Prolog for a control system.

Does SWI-Prolog give you access to the GPIO pins on a Raspberry Pi? Is it possible to initiate Prolog searches by a GPIO input and produce a signal on a pin as the result of a rule?

I don’t think you can access the pin directly from Prolog but if there exists a c based library to access the pins, then the FFI package could possibly be used.

Edit –

Perhaps its possible to use a setup that is combined with Python. Python accessess the pins and forwards the values to Prolog --with Prolog embedded or called from Python.

A quick Google search leads me to How to Control GPIO Hardware from C or C++ | ICS, which tells me that the GPIO pins are simply controlled through the filesystem. Translating the code there gives something like below. Not tested (I have a Pi, but nothing
to connect to the GPIO pins directly ready :frowning: ).

blink :-
        open('/sys/class/gpio/export', write, Out1),
        write(Out1, 24),

        open('/sys/class/gpio24/direction', write, Out2),
        write(Out2, out2),

        open('/sys/class/gpio/gpio24/value', write, Out3),
        blink(100, Out3),

blink(N, Out) :-
    N > 0,
    write(Out, 1),
    write(Out, 0),
    N2 is N - 1,
    blink(N2, Out).

thats great.

I tried to see if reading from the file system would then be reading input – and i guess the approach is polling driven … to identify a change in input.

A more complete overview of the fs API is at GPIO Programming: Using the sysfs Interface | ICS. Seems you can read '/sys/class/gpio/gpioNN/value' and get a 0 or a 1. That seems to be a polling interface :frowning: I don’t see what you need to poll again, i.e., do you have to go through the open/close or maybe you can use seek/4 to go back to the start and try again. One needs better docs or a Pi to tell :slight_smile:

Easy enough to build a nice library and submit as a pack. Someone?

1 Like

The sysfs gpio interface has been deprecated.

The new kernel inteface is through a character device that can be easily accessible using libgpiod. It is easy enough to use by calling the executables included with libgpiod or it can be called directly from C with ffi.

One of the nice executables provided by libgpiod (besides gpioget and gpioset) is called gpiomon. It allows monitoring rising edges, falling edges and even setup pull down or pull up biases, printing to stdout as events happen:

       lt-gpiomon - manual page for lt-gpiomon v1.6.3

       lt-gpiomon [OPTIONS] <chip name/number> <offset 1> <offset 2> ...

       Wait for events on GPIO lines and print them to standard output

       -h, --help:
              display this message and exit

       -v, --version:
              display the version and exit

       -l, --active-low:
              set the line active state to low

       -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):

              set the line bias

       -n, --num-events=NUM: exit after processing NUM events

       -s, --silent:
              don't print event info

       -r, --rising-edge:
              only process rising edge events

       -f, --falling-edge:
              only process falling edge events

       -b, --line-buffered:
              set standard output as line buffered

       -F, --format=FMT
              specify custom output format

       as-is: leave bias unchanged

              disable bias

              enable pull-up

              enable pull-down

Here is an article showing why libgpiod is much better than sysfs.

A short tutorial on the use of FFI to directly access c would be great.


Check out the ffi add-on page.

It has a simple example to call the statfs libc function:

:- use_module(library(ffi)).
:- use_module(library(cerror)).

:- c_import("#include <sys/vfs.h>",    % include file where C functions are found
            [ libc ],                  % dynamic library(ies) to load
            [ statfs(string, -struct(statfs), [int]) % function(s) to import, and description
                                                     % of parameters and return value

statfs(File, FsStat) :-               % regular prolog predicate
    statfs(File, FsStat, Status),     % now we call the C function
    posix_status(Status, statfs, file, File). % covert posix errors to prolog exception


?- statfs(".", FsStat), c_load(FsStat[f_bavail], A).
FsStat = <C struct statfs[1]>(0x55a2c9d5bae0),
A = 66197957.

More detailed documentation for the ffi add-on is found in this pdf.

EDIT: By the way, strictly speaking you don’t have to use posix_status/4 above, it is just used to convert posix error codes into prolog exceptions.

1 Like

Possibly simply opening, reading and writing to this character device is easier than using libgpio? Sometimes it is … The advantage of using a library is than mostly that if the kernel interface changes again, the library is probably changed to deal with that. Usually, kernel interfaces are pretty stable though.

The advantage of using libgpiod, instead of the character device directly, is that libgpiod provides for managing for simultaneous access to the gpio from several processes/threads. As it says in the linux docs:

For structured and managed applications, we recommend that you make use of the libgpiod library. This provides helper abstractions, command line utlities and arbitration for multiple simultaneous consumers on the same GPIO chip.

1 Like

Is this example slightly incomplete ?

As far as I can see
posix_status/4 is defined in ffi/prolog/
and should be loaded with something like

:- use_module(library(cerror)).



Nicos Angelopoulos

1 Like

Nicos, you are correct, fixed the example above. Should probably be fixed on the ffi add-ons README also.

Thanks for pointing it out.

Fixed. Also updated version and pushed a new version with the issue solved for Nicos using this package on the Raspberry pi using Ubuntu 21.04 (variation in ldconfig output and deal with systems where char is by default unsigned). The library now provides a primitive type schar next to uchar and char, where schar is explicitly signed and char does what the compiler does by default.

1 Like