2

借助Vala 手册中出色的文章作为我的指南,创建一些自定义 vapi defs 。但我不确定如何翻译这些类似 C 函数的宏:

// 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

C 代码gpio这样声明:

// I/O access
volatile unsigned *gpio;

我应该将宏声明INP_GPIO(g)为 void 函数,即

[CCode (cname = "INP_GPIO")]
public void inp_gpio(int val);

或作为代表,如下所示?

public delegate void inp_gpio(int val);

从 VAPI 文件的 C 代码派生 Vala 类型时,我应该遵循哪些条件?

更新:随着我继续从事我的 valaIOT 项目,下面提到的 vapis 维护在https://gitlab.com/gpaslanis/valaiot/tree/master/vapis。请在网站上发布建议/更正。我希望你觉得他们有帮助。

4

1 回答 1

2

好问题!该代码看起来像是直接访问 GPIO 内存地址,并且似乎来自RPi GPIO Code Samples - Direct register access。C 预处理器正在INP_GPIO(g)使用运算符交换表达式&=。该表达式对在运算符左侧计算的内存位置进行按位运算。

Vala 需要做的就是确保INP_GPIO(g)写入 C 文件,然后 C 预处理器进行交换。所以正确的绑定应该是这样的:

[CCode (cname = "INP_GPIO")]
public void inp_gpio(int pin);

Vala 中的委托是 C 中的函数指针,代码不会调用内存地址,而是向其写入值。它不是 C 中的函数指针,因此不应在 Vala 中绑定为委托。

使用 GPIO 是 Vala 的一个很好的用例。您可能需要考虑改用 Linux 内核用户空间 API。这最近在 Linux 4.8 中发生了变化,并且不在 Vala 中linux.vapi。因此,欢迎使用带有 Vala的linux/include/uapi/linux/gpio.h的补丁。它本质上是一个文件接口,可以/dev/gpiochipx使用各种 IOCTL 来操作它。有关更多详细信息,请参阅这些幻灯片。如果您了解 GMainContext 和 GSource,我认为可以使用g_source_add_unix_fd编写 Vala GSource. 当 GPIO 线路发生变化时,这将触发 GMainContext 中的事件。事件只是回调的另一个名称。这将是实现更高级别应用程序代码以响应 GPIO 线路上的输入的好方法。使用 GMainLoop 或 GApplication 时会在后台创建 GMainContext。不过需要完成 Vala 的文档。

还有libgpiod一个提供用户空间库来与内核字符设备接口接口。对于 Vala,这意味着编写一个libgpiod.vapi来使用gpiod.h。libgpiod 也有命令行工具,本文对这些工具进行了很好的总结。

于 2019-07-04T19:43:46.327 回答