Skip to content

Commit

Permalink
Refactor GPIO library
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Ondráček <ondracek.roman@centrum.cz>
  • Loading branch information
Roman3349 committed Oct 19, 2022
1 parent b46f3d3 commit 9fdf1a2
Show file tree
Hide file tree
Showing 5 changed files with 413 additions and 383 deletions.
21 changes: 21 additions & 0 deletions include/iqrf_debug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#ifdef NDEBUG
#ifndef IQRF_DEBUG_PRINT
#define IQRF_DEBUG_PRINT(fmt, ...)
#endif
#ifndef IQRF_DEBUG_PRINTF
#define IQRF_DEBUG_PRINTF(fmt, ...)
#endif
#else
#ifndef IQRF_DEBUG_PRINT
#define IQRF_DEBUG_PRINT(str) do { \
fprintf(stderr, "%s:%d - %s(): " str "\n", __FILE__, __LINE__, __func__); \
} while (0)
#endif
#ifndef IQRF_DEBUG_PRINTF
#define IQRF_DEBUG_PRINTF(fmt, ...) do { \
fprintf(stderr, "%s:%d - %s(): " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while (0)
#endif
#endif
124 changes: 124 additions & 0 deletions include/iqrf_gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#ifndef IQRF_GPIO_H
#define IQRF_GPIO_H

#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#ifndef WIN32
#include <fcntl.h>
#include <unistd.h>
#endif

#include "iqrf_debug.h"
#include "sleepWrapper.h"

#define IQRF_GPIO_SYSFS_BASE_PATH "/sys/class/gpio/"
#define IQRF_GPIO_SYSFS_BUFFER_SIZE 64
#define IQRF_GPIO_DIRECTION_BUFFER_SIZE 4
#define IQRF_GPIO_PIN_BUFFER_SIZE 20
#define IQRF_GPIO_VALUE_BUFFER_SIZE 2

static const int64_t IQRF_GPIO_PIN_UNKNOWN = -1;

typedef enum {
IQRF_GPIO_ACTION_DIRECTION,
IQRF_GPIO_ACTION_VALUE,
} iqrf_gpio_action_t;

typedef enum {
IQRF_GPIO_DIRECTION_UNKNOWN = -1,
IQRF_GPIO_DIRECTION_IN,
IQRF_GPIO_DIRECTION_OUT,
} iqrf_gpio_direction_t;

typedef enum {
IQRF_GPIO_ERROR_OK,
IQRF_GPIO_ERROR_INVALID_PIN,
IQRF_GPIO_ERROR_OPEN_FAILED,
IQRF_GPIO_ERROR_WRITE_FAILED,
IQRF_GPIO_ERROR_NULL_POINTER,
} iqrf_gpio_error_t;

/**
* Exports the GPIO pin
* @param pin GPIO pin to export
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_export(int64_t pin);

/**
* Unexports the GPIO pin
* @param pin GPIO pin to unexport
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_unexport(int64_t pin);

/**
* Retrieves the direction for GPIO pin
* @param pin GPIO pin
* @param direction GPIO pin direction
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_get_direction(int64_t pin, iqrf_gpio_direction_t *direction);

/**
* Sets the direction for GPIO pin
* @param pin GPIO pin
* @param direction GPIO pin direction
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_set_direction(int64_t pin, iqrf_gpio_direction_t direction);

/**
* Retrieves the direction for GPIO pin
* @param pin GPIO pin
* @param value GPIO pin output value
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_get_value(int64_t pin, bool *value);

/**
* Sets the direction for GPIO pin
* @param pin GPIO pin
* @param value GPIO pin output value
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_set_value(int64_t pin, bool value);

/**
* Creates sysfs path
* @param pin GPIO pin
* @param action GPIO action
* @param targetPath
*/
void iqrf_gpio_create_sysfs_path(int64_t pin, iqrf_gpio_action_t action, char *targetPath);

/**
* Initializes a GPIO pin
* @param pin GPIO pin number
* @param direction GPIO pin direction
* @param initialValue Initial output value
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_init(int64_t pin, iqrf_gpio_direction_t direction, bool initialValue);

/**
* Initializes a GPIO pin as an input
* @param pin GPIO pin number
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_init_input(int64_t pin);

/**
* Initializes a GPIO pin as an output
* @param pin GPIO pin
* @param initialValue Initial output value
* @return Execution status
*/
iqrf_gpio_error_t iqrf_gpio_init_output(int64_t pin, bool initialValue);

#endif
4 changes: 1 addition & 3 deletions spi_iqrf/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
project(spi_iqrf)

set(_SRC_FILES
spi_iqrf.c
)
set(_SRC_FILES iqrf_gpio.c spi_iqrf.c)

add_library(${PROJECT_NAME} STATIC ${_SRC_FILES})
230 changes: 230 additions & 0 deletions spi_iqrf/iqrf_gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#include "iqrf_gpio.h"

#ifdef WIN32
#define snprintf _snprintf
#endif

static const char* IQRF_GPIO_ACTION_DIRECTION_STR = "direction";
static const char* IQRF_GPIO_ACTION_VALUE_STR = "value";
static const char* IQRF_GPIO_DIRECTION_IN_STR = "in";
static const char* IQRF_GPIO_DIRECTION_OUT_STR = "out";

void iqrf_gpio_create_sysfs_path(int64_t pin, iqrf_gpio_action_t action, char *targetPath) {
const char *actionString = action == IQRF_GPIO_ACTION_DIRECTION ? IQRF_GPIO_ACTION_DIRECTION_STR : IQRF_GPIO_ACTION_VALUE_STR;
snprintf(targetPath, IQRF_GPIO_SYSFS_BUFFER_SIZE, IQRF_GPIO_SYSFS_BASE_PATH"gpio%"PRId64"/%s", pin, actionString);
}

iqrf_gpio_error_t iqrf_gpio_export(int64_t pin) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char *path = IQRF_GPIO_SYSFS_BASE_PATH"export";
int fd = open(path, O_WRONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
char buffer[IQRF_GPIO_PIN_BUFFER_SIZE] = "";
snprintf(buffer, IQRF_GPIO_PIN_BUFFER_SIZE, "%"PRId64, pin);
ssize_t writtenSize = write(fd, buffer, IQRF_GPIO_PIN_BUFFER_SIZE);
if (writtenSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to write '%s' into \"%s\". Reason: %s", buffer, path, strerror(errno));
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_unexport(int64_t pin) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char *path = IQRF_GPIO_SYSFS_BASE_PATH"unexport";
int fd = open(path, O_WRONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
char buffer[IQRF_GPIO_PIN_BUFFER_SIZE] = "";
snprintf(buffer, IQRF_GPIO_PIN_BUFFER_SIZE, "%"PRId64, pin);
ssize_t writtenSize = write(fd, buffer, IQRF_GPIO_PIN_BUFFER_SIZE);
if (writtenSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to write '%s' into \"%s\". Reason: %s", buffer, path, strerror(errno));
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_get_direction(int64_t pin, iqrf_gpio_direction_t *direction) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (direction == NULL) {
return IQRF_GPIO_ERROR_NULL_POINTER;
}
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char path[IQRF_GPIO_SYSFS_BUFFER_SIZE] = "";
iqrf_gpio_create_sysfs_path(pin, IQRF_GPIO_ACTION_DIRECTION, path);
int fd = open(path, O_RDONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
char buffer[IQRF_GPIO_DIRECTION_BUFFER_SIZE] = "";
ssize_t readSize = read(fd, buffer, IQRF_GPIO_DIRECTION_BUFFER_SIZE);
if (readSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to read from %s", path);
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
if (strncmp(buffer, IQRF_GPIO_DIRECTION_IN_STR, IQRF_GPIO_DIRECTION_BUFFER_SIZE - 1) == 0) {
*direction = IQRF_GPIO_DIRECTION_IN;
} else if (strncmp(buffer, IQRF_GPIO_DIRECTION_OUT_STR, IQRF_GPIO_DIRECTION_BUFFER_SIZE - 1) == 0) {
*direction = IQRF_GPIO_DIRECTION_OUT;
} else {
*direction = IQRF_GPIO_DIRECTION_UNKNOWN;
}
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_set_direction(int64_t pin, iqrf_gpio_direction_t direction) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char path[IQRF_GPIO_SYSFS_BUFFER_SIZE] = "";
iqrf_gpio_create_sysfs_path(pin, IQRF_GPIO_ACTION_DIRECTION, path);
int fd = open(path, O_WRONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
const char *buffer = direction == IQRF_GPIO_DIRECTION_IN ? IQRF_GPIO_DIRECTION_IN_STR : IQRF_GPIO_DIRECTION_OUT_STR;
ssize_t writtenSize = write(fd, buffer, strlen(buffer));
if (writtenSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to write '%s' into \"%s\". Reason: %s", buffer, path, strerror(errno));
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_get_value(int64_t pin, bool *value) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (value == NULL) {
return IQRF_GPIO_ERROR_NULL_POINTER;
}
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char path[IQRF_GPIO_SYSFS_BUFFER_SIZE] = "";
iqrf_gpio_create_sysfs_path(pin, IQRF_GPIO_ACTION_VALUE, path);
int fd = open(path, O_RDONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
char buffer[IQRF_GPIO_VALUE_BUFFER_SIZE] = "";
ssize_t readSize = read(fd, buffer, IQRF_GPIO_VALUE_BUFFER_SIZE);
if (readSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to read from %s", path);
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
*value = strncmp(buffer, "1", IQRF_GPIO_VALUE_BUFFER_SIZE - 1) == 0;
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_set_value(int64_t pin, bool value) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
if (pin < 0) {
IQRF_DEBUG_PRINTF("Invalid GPIO pin number: %"PRId64, pin);
return IQRF_GPIO_ERROR_INVALID_PIN;
}
char path[IQRF_GPIO_SYSFS_BUFFER_SIZE] = "";
iqrf_gpio_create_sysfs_path(pin, IQRF_GPIO_ACTION_VALUE, path);
int fd = open(path, O_WRONLY);
if (fd == -1) {
IQRF_DEBUG_PRINTF("Unable to open path \"%s\". Reason: %s", path, strerror(errno));
return IQRF_GPIO_ERROR_OPEN_FAILED;
}
const char *buffer = value ? "1" : "0";
ssize_t writtenSize = write(fd, buffer, 2);
if (writtenSize == -1) {
close(fd);
IQRF_DEBUG_PRINTF("Unable to write '%s' into \"%s\". Reason: %s", buffer, path, strerror(errno));
return IQRF_GPIO_ERROR_WRITE_FAILED;
}
close(fd);
return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_init(int64_t pin, iqrf_gpio_direction_t direction, bool initialValue) {
#ifdef WIN32
return IQRF_GPIO_ERROR_OK;
#else
iqrf_gpio_error_t error = iqrf_gpio_export(pin);
if (error) {
return error;
}

char *directionStr = direction == IQRF_GPIO_DIRECTION_IN ? "input" : "output";
for (uint8_t i = 1; i <= 10; i++) {
error = iqrf_gpio_set_direction(pin, direction);
if (!error) {
IQRF_DEBUG_PRINTF("GPIO pin #%"PRId64" direction \"%s\" is successfully set. Attempt: %d", pin, directionStr, i);
break;
}
IQRF_DEBUG_PRINTF("Failed to set direction \"%s\" on GPIO pin #%"PRId64". Wait for 100 ms to next try: %d", directionStr, pin, i);
SLEEP(100);
}

if (direction == IQRF_GPIO_DIRECTION_OUT) {
error = iqrf_gpio_set_value(pin, initialValue);
if (error) {
return error;
}
}

return IQRF_GPIO_ERROR_OK;
#endif
}

iqrf_gpio_error_t iqrf_gpio_init_input(int64_t pin) {
return iqrf_gpio_init(pin, IQRF_GPIO_DIRECTION_IN, false);
}

iqrf_gpio_error_t iqrf_gpio_init_output(int64_t pin, bool initialValue) {
return iqrf_gpio_init(pin, IQRF_GPIO_DIRECTION_OUT, initialValue);
}
Loading

0 comments on commit 9fdf1a2

Please sign in to comment.