Creating some custom vapi defs with the help of the excellent write up in the Vala manual as my guide. But I'm not sure how to translate C function-like macros like these:
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
#define GPIO_PULL *(gpio+37) // Pull up/pull down
#define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
The C code declares gpio
this way:
// I/O access
volatile unsigned *gpio;
Should I declare the macro INP_GPIO(g)
as a void function, i.e.
[CCode (cname = "INP_GPIO")]
public void inp_gpio(int val);
or as a delegate, like below?
public delegate void inp_gpio(int val);
Which conditions should I follow when deriving the Vala type from C code for a VAPI file?
Update: As I continue to work on my valaIOT project, the vapis mentioned below are maintained at https://gitlab.com/gpaslanis/valaiot/tree/master/vapis. Please post recommendations/corrections at the site. I hope you find them helpful.
Good question! The code looks like it is directly accessing the GPIO memory address and seems to be from RPi GPIO Code Samples - Direct register access. The C pre-processor is exchanging INP_GPIO(g)
for an expression using the &=
operator. The expression does a bitwise operation on the memory location calculated on the left hand side of the operator.
All Vala needs to do is make sure INP_GPIO(g)
is written to the C file and then the C pre-processor does the exchange. So the correct binding would be something like:
[CCode (cname = "INP_GPIO")]
public void inp_gpio(int pin);
A delegate in Vala is a function pointer in C and the code isn't going to call the memory address, but write a value to it. It's not a function pointer in C and so shouldn't be bound as a delegate in Vala.
Using GPIOs is a great use case for Vala. You may want to consider using the Linux kernel user space API instead. This recently changed with Linux 4.8 and isn't in the Vala linux.vapi
. So a patch would be welcome for using linux/include/uapi/linux/gpio.h with Vala. It's essentially a file interface to /dev/gpiochipx
with various IOCTLs to manipulate it. For more details see these slides. If you understand GMainContext and GSource I think it would be possible to write a Vala GSource with g_source_add_unix_fd. This would trigger an event in the GMainContext when there is a change in a GPIO line. An event being just another name for a callback. This would be a good way of implementing higher level application code in response to inputs on GPIO lines. A GMainContext is created behind the scenes when using GMainLoop or GApplication. The documentation for Vala needs to done though.
There is also libgpiod
that provides a user space library to interface with the kernel character device interface. For Vala this would mean writing a libgpiod.vapi to use gpiod.h. libgpiod also has command line tools and this article give a nice summary of those.