mirror of
https://github.com/vsergeev/c-periphery.git
synced 2026-08-18 11:52:08 +08:00
gpio: add advanced open functions for cdev implementation
resolves #22.
This commit is contained in:
@@ -11,6 +11,8 @@ GPIO wrapper functions for Linux userspace character device `gpio-cdev` and sysf
|
||||
gpio_t *gpio_new(void);
|
||||
int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction);
|
||||
int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config);
|
||||
int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config);
|
||||
int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_read(gpio_t *gpio, bool *value);
|
||||
int gpio_write(gpio_t *gpio, bool value);
|
||||
@@ -111,6 +113,46 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
|
||||
------
|
||||
|
||||
``` c
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
const char *label;
|
||||
} gpio_config_t;
|
||||
|
||||
int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config);
|
||||
```
|
||||
Open the character device GPIO with the specified GPIO line and configuration at the specified character device GPIO chip path (e.g. `/dev/gpiochip0`).
|
||||
|
||||
`gpio` should be a valid pointer to an allocated GPIO handle structure. `path` is the GPIO chip character device path. `line` is the GPIO line number. `config` should be a valid pointer to a `gpio_config_t` structure with valid values. `label` can be `NULL` for a default consumer label.
|
||||
|
||||
Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
|
||||
------
|
||||
|
||||
``` c
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
const char *label;
|
||||
} gpio_config_t;
|
||||
|
||||
int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config);
|
||||
```
|
||||
Open the character device GPIO with the specified GPIO name and configuration at the specified character device GPIO chip path (e.g. `/dev/gpiochip0`).
|
||||
|
||||
`gpio` should be a valid pointer to an allocated GPIO handle structure. `path` is the GPIO chip character device path. `name` is the GPIO line name. `config` should be a valid pointer to a `gpio_config_t` structure with valid values. `label` can be `NULL` for a default consumer label.
|
||||
|
||||
Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
|
||||
------
|
||||
|
||||
``` c
|
||||
int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction);
|
||||
```
|
||||
|
||||
+51
-23
@@ -1247,12 +1247,27 @@ static const struct gpio_ops gpio_cdev_ops = {
|
||||
.tostring = gpio_cdev_tostring,
|
||||
};
|
||||
|
||||
int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction) {
|
||||
int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config) {
|
||||
int ret, fd;
|
||||
|
||||
if (direction != GPIO_DIR_IN && direction != GPIO_DIR_OUT && direction != GPIO_DIR_OUT_LOW && direction != GPIO_DIR_OUT_HIGH)
|
||||
if (config->direction != GPIO_DIR_IN && config->direction != GPIO_DIR_OUT && config->direction != GPIO_DIR_OUT_LOW && config->direction != GPIO_DIR_OUT_HIGH)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO direction (can be in, out, low, high)");
|
||||
|
||||
if (config->edge != GPIO_EDGE_NONE && config->edge != GPIO_EDGE_RISING && config->edge != GPIO_EDGE_FALLING && config->edge != GPIO_EDGE_BOTH)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)");
|
||||
|
||||
if (config->direction != GPIO_DIR_IN && config->edge != GPIO_EDGE_NONE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO edge for output GPIO");
|
||||
|
||||
if (config->bias != GPIO_BIAS_DEFAULT && config->bias != GPIO_BIAS_PULL_UP && config->bias != GPIO_BIAS_PULL_DOWN && config->bias != GPIO_BIAS_DISABLE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line bias (can be default, pull_up, pull_down, disable)");
|
||||
|
||||
if (config->drive != GPIO_DRIVE_DEFAULT && config->drive != GPIO_DRIVE_OPEN_DRAIN && config->drive != GPIO_DRIVE_OPEN_SOURCE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line drive (can be default, open_drain, open_source)");
|
||||
|
||||
if (config->direction == GPIO_DIR_IN && config->drive != GPIO_DRIVE_DEFAULT)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line drive for input GPIO");
|
||||
|
||||
/* Open GPIO chip */
|
||||
if ((fd = open(path, 0)) < 0)
|
||||
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO chip");
|
||||
@@ -1262,10 +1277,11 @@ int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_
|
||||
gpio->u.cdev.line = line;
|
||||
gpio->u.cdev.line_fd = -1;
|
||||
gpio->u.cdev.chip_fd = fd;
|
||||
strncpy(gpio->u.cdev.label, "periphery", sizeof(gpio->u.cdev.label));
|
||||
strncpy(gpio->u.cdev.label, config->label ? config->label : "periphery", sizeof(gpio->u.cdev.label));
|
||||
gpio->u.cdev.label[sizeof(gpio->u.cdev.label) - 1] = '\0';
|
||||
|
||||
/* Open GPIO line */
|
||||
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, GPIO_BIAS_DEFAULT, GPIO_DRIVE_DEFAULT, false);
|
||||
ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->bias, config->drive, config->inverted);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return ret;
|
||||
@@ -1274,11 +1290,8 @@ int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction) {
|
||||
int ret, fd;
|
||||
|
||||
if (direction != GPIO_DIR_IN && direction != GPIO_DIR_OUT && direction != GPIO_DIR_OUT_LOW && direction != GPIO_DIR_OUT_HIGH)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO direction (can be in, out, low, high)");
|
||||
int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config) {
|
||||
int fd;
|
||||
|
||||
/* Open GPIO chip */
|
||||
if ((fd = open(path, 0)) < 0)
|
||||
@@ -1316,19 +1329,34 @@ int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direct
|
||||
return _gpio_error(gpio, GPIO_ERROR_NOT_FOUND, 0, "GPIO line \"%s\" not found by name", name);
|
||||
}
|
||||
|
||||
memset(gpio, 0, sizeof(gpio_t));
|
||||
gpio->ops = &gpio_cdev_ops;
|
||||
gpio->u.cdev.line = line;
|
||||
gpio->u.cdev.line_fd = -1;
|
||||
gpio->u.cdev.chip_fd = fd;
|
||||
strncpy(gpio->u.cdev.label, "periphery", sizeof(gpio->u.cdev.label));
|
||||
if (close(fd) < 0)
|
||||
return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO chip");
|
||||
|
||||
/* Open GPIO line */
|
||||
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, GPIO_BIAS_DEFAULT, GPIO_DRIVE_DEFAULT, false);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return gpio_open_advanced(gpio, path, line, config);
|
||||
}
|
||||
|
||||
int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction) {
|
||||
gpio_config_t config = {
|
||||
.direction = direction,
|
||||
.edge = GPIO_EDGE_NONE,
|
||||
.bias = GPIO_BIAS_DEFAULT,
|
||||
.drive = GPIO_DRIVE_DEFAULT,
|
||||
.inverted = false,
|
||||
.label = NULL,
|
||||
};
|
||||
|
||||
return gpio_open_advanced(gpio, path, line, &config);
|
||||
}
|
||||
|
||||
int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction) {
|
||||
gpio_config_t config = {
|
||||
.direction = direction,
|
||||
.edge = GPIO_EDGE_NONE,
|
||||
.bias = GPIO_BIAS_DEFAULT,
|
||||
.drive = GPIO_DRIVE_DEFAULT,
|
||||
.inverted = false,
|
||||
.label = NULL,
|
||||
};
|
||||
|
||||
return gpio_open_name_advanced(gpio, path, name, &config);
|
||||
}
|
||||
|
||||
+12
@@ -54,12 +54,24 @@ typedef enum gpio_drive {
|
||||
GPIO_DRIVE_OPEN_SOURCE, /* Open source */
|
||||
} gpio_drive_t;
|
||||
|
||||
/* Configuration structure for gpio_open_*advanced() functions */
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
const char *label; /* Can be NULL for default consumer label */
|
||||
} gpio_config_t;
|
||||
|
||||
typedef struct gpio_handle gpio_t;
|
||||
|
||||
/* Primary Functions */
|
||||
gpio_t *gpio_new(void);
|
||||
int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction);
|
||||
int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config);
|
||||
int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config);
|
||||
int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_read(gpio_t *gpio, bool *value);
|
||||
int gpio_write(gpio_t *gpio, bool value);
|
||||
|
||||
@@ -173,6 +173,43 @@ void test_open_config_close(void) {
|
||||
/* Close GPIO */
|
||||
passert(gpio_close(gpio) == 0);
|
||||
|
||||
/* Open GPIO with advanced open */
|
||||
gpio_config_t config = {
|
||||
.direction = GPIO_DIR_IN,
|
||||
.edge = GPIO_EDGE_RISING,
|
||||
.bias = GPIO_BIAS_DEFAULT,
|
||||
.drive = GPIO_DRIVE_DEFAULT,
|
||||
.inverted = false,
|
||||
.label = "test123",
|
||||
};
|
||||
passert(gpio_open_advanced(gpio, device, pin_input, &config) == 0);
|
||||
|
||||
/* Check properties */
|
||||
passert(gpio_line(gpio) == pin_input);
|
||||
passert(gpio_fd(gpio) >= 0);
|
||||
passert(gpio_chip_fd(gpio) >= 0);
|
||||
/* Check direction */
|
||||
passert(gpio_get_direction(gpio, &direction) == 0);
|
||||
passert(direction == GPIO_DIR_IN);
|
||||
/* Check edge */
|
||||
passert(gpio_get_edge(gpio, &edge) == 0);
|
||||
passert(edge == GPIO_EDGE_RISING);
|
||||
/* Check bias */
|
||||
passert(gpio_get_bias(gpio, &bias) == 0);
|
||||
passert(bias == GPIO_BIAS_DEFAULT);
|
||||
/* Check drive */
|
||||
passert(gpio_get_drive(gpio, &drive) == 0);
|
||||
passert(drive == GPIO_DRIVE_DEFAULT);
|
||||
/* Check inverted */
|
||||
passert(gpio_get_inverted(gpio, &inverted) == 0);
|
||||
passert(inverted == false);
|
||||
/* Check label */
|
||||
passert(gpio_label(gpio, label, sizeof(label)) == 0);
|
||||
passert(strncmp(label, "test123", sizeof(label)) == 0);
|
||||
|
||||
/* Close GPIO */
|
||||
passert(gpio_close(gpio) == 0);
|
||||
|
||||
/* Free GPIO */
|
||||
gpio_free(gpio);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user