/******************************************************************************!
* \file wiring_digital-gpiod.c
* \author Sebastien Beaugrand
* \sa http://beaugrand.chez.com/
* \copyright CeCILL 2.1 Free Software license
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <gpiod.h>
#include "wiring.h"
#include "debug.h"
#define GPIOD_MAX_PIN_COUNT 24
struct gpiod_line_request* gLines[GPIOD_MAX_PIN_COUNT] = { NULL };
int gOffsets[GPIOD_MAX_PIN_COUNT] = { 0 };
#ifndef NDEBUG
/******************************************************************************!
* \fn debugValues
******************************************************************************/
void
debugValues()
{
int n;
int i;
n = 0;
for (i = 0; i < GPIOD_MAX_PIN_COUNT; ++i) {
if (gLines[i]) {
fprintf(stderr, "%d ",
gpiod_line_request_get_value(gLines[i], gOffsets[i]));
++n;
}
}
if (n > 0) {
fprintf(stderr, "\n");
}
}
#endif
/******************************************************************************!
* \fn digitalInit
******************************************************************************/
int
digitalInit(uint8_t pin, uint8_t mode)
{
struct gpiod_chip* chip = NULL;
struct gpiod_line_request* line;
struct gpiod_line_info* info = NULL;
struct gpiod_line_settings* settings = NULL;
struct gpiod_line_config* cfg = NULL;
char buf[6];
int offset;
int ret = 0;
line = gLines[pin - 1];
if (line) {
offset = gOffsets[pin - 1];
} else {
if (snprintf(buf, 6, "pin%u", pin) >= 6) {
ERROR("snprintf");
ret = 1;
goto finalize;
}
chip = gpiod_chip_open("/dev/gpiochip0");
if (! chip) {
ERRNO("gpiod_chip_open");
ret = 2;
goto finalize;
}
offset = gpiod_chip_get_line_offset_from_name(chip, buf);
if (offset < 0) {
chip = gpiod_chip_open("/dev/gpiochip1");
if (! chip) {
ERRNO("gpiod_chip_open");
ret = 2;
goto finalize;
}
offset = gpiod_chip_get_line_offset_from_name(chip, buf);
}
if (offset < 0) {
ERRNO("gpiod_chip_get_line_offset_from_name");
ret = 3;
goto finalize;
}
info = gpiod_chip_get_line_info(chip, offset);
if (! info) {
ERRNO("gpiod_chip_get_line_info");
ret = 4;
goto finalize;
}
if (gpiod_line_info_is_used(info)) {
ERROR("gpiod_line_info_is_used");
ret = 5;
goto finalize;
}
}
settings = gpiod_line_settings_new();
if (! settings) {
ERRNO("gpiod_line_settings_new");
ret = 6;
goto finalize;
}
if (mode == INPUT) {
if (gpiod_line_settings_set_direction(
settings, GPIOD_LINE_DIRECTION_INPUT) < 0) {
ERRNO("gpiod_line_settings_set_direction");
ret = 7;
goto finalize;
}
} else {
if (gpiod_line_settings_set_direction(
settings, GPIOD_LINE_DIRECTION_OUTPUT) < 0) {
ERRNO("gpiod_line_settings_set_direction");
ret = 7;
goto finalize;
}
}
cfg = gpiod_line_config_new();
if (! cfg) {
ERRNO("gpiod_line_config_new");
ret = 8;
goto finalize;
}
unsigned int offsets = offset;
if (gpiod_line_config_add_line_settings(cfg, &offsets, 1, settings) < 0) {
ERRNO("gpiod_line_config_add_line_settings");
ret = 9;
goto finalize;
}
if (chip) {
struct gpiod_request_config* req_cfg = gpiod_request_config_new();
if (req_cfg) {
gpiod_request_config_set_consumer(req_cfg, __FILE_NAME__);
}
line = gpiod_chip_request_lines(chip, req_cfg, cfg);
if (! line) {
ERRNO("gpiod_chip_request_lines");
ret = 10;
goto finalize;
}
gLines[pin - 1] = line;
gOffsets[pin - 1] = offset;
} else {
if (gpiod_line_request_reconfigure_lines(line, cfg) < 0) {
ERRNO("gpiod_line_request_reconfigure_lines");
ret = 11;
goto finalize;
}
}
finalize:
gpiod_line_config_free(cfg);
gpiod_line_settings_free(settings);
gpiod_line_info_free(info);
gpiod_chip_close(chip);
return ret;
}
/******************************************************************************!
* \fn digitalRead
******************************************************************************/
int
digitalRead(uint8_t pin)
{
struct gpiod_line_request* line;
int val;
# ifndef NDEBUG
debugValues();
# endif
line = gLines[pin - 1];
if (! line) {
ERROR("line == NULL");
return -1;
}
val = gpiod_line_request_get_value(line, gOffsets[pin - 1]);
if (val < 0) {
ERRNO("gpiod_line_request_get_value");
return GPIO_ERROR_READ;
}
return val;
}
/******************************************************************************!
* \fn digitalWrite
******************************************************************************/
void
digitalWrite(uint8_t pin, uint8_t val)
{
struct gpiod_line_request* line;
# ifndef NDEBUG
debugValues();
# endif
line = gLines[pin - 1];
if (! line) {
ERROR("line == NULL");
return;
}
gpiod_line_request_set_value(line, gOffsets[pin - 1], val);
}
/******************************************************************************!
* \fn digitalQuit
******************************************************************************/
int
digitalQuit(uint8_t pin)
{
struct gpiod_line_request* line;
# ifndef NDEBUG
debugValues();
# endif
line = gLines[pin - 1];
if (! line) {
ERROR("line == NULL");
return 1;
}
gpiod_line_request_release(line);
gLines[pin - 1] = NULL;
return 0;
}