gpio: chardev interface / multiple gpio support for sysfs
Signed-off-by: Mihai Stefanescu <mihai.t.gh.stefanescu@gmail.com> Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
@@ -104,6 +104,15 @@ typedef enum {
|
||||
MRAA_GPIO_PUSH_PULL = 1, /**< Push Pull Configuration */
|
||||
} mraa_gpio_out_driver_mode_t;
|
||||
|
||||
typedef long long unsigned int mraa_timestamp_t;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
mraa_timestamp_t timestamp;
|
||||
} mraa_gpio_event;
|
||||
|
||||
typedef mraa_gpio_event* mraa_gpio_events_t;
|
||||
|
||||
/**
|
||||
* Initialise gpio_context, based on board number
|
||||
*
|
||||
@@ -112,7 +121,15 @@ typedef enum {
|
||||
*/
|
||||
mraa_gpio_context mraa_gpio_init(int pin);
|
||||
|
||||
mraa_gpio_context mraa_gpio_init_multiple(int pins[], int num_pins);
|
||||
/**
|
||||
* Initialise gpio_context, based on board number, for multiple pins (can be one).
|
||||
*
|
||||
* @param pins Pin array read from the board
|
||||
* @param num_pins Number of pins - must be the same as the pins array length provided
|
||||
* as the first argument.
|
||||
* @returns gpio context or NULL
|
||||
*/
|
||||
mraa_gpio_context mraa_gpio_init_multi(int pins[], int num_pins);
|
||||
|
||||
/**
|
||||
* Initialise gpio context without any mapping to a pin
|
||||
@@ -131,13 +148,11 @@ mraa_gpio_context mraa_gpio_init_raw(int gpiopin);
|
||||
*/
|
||||
mraa_result_t mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode);
|
||||
|
||||
mraa_result_t mraa_gpio_edge_mode_multiple(mraa_gpio_context dev, mraa_gpio_edge_t mode);
|
||||
|
||||
/**
|
||||
* Set an interrupt on pin
|
||||
* Set an interrupt on pin(s).
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param edge The edge mode to set the gpio into
|
||||
* @param edge The edge mode to set the gpio(s) into
|
||||
* @param fptr Function pointer to function to be called when interrupt is
|
||||
* triggered
|
||||
* @param args Arguments passed to the interrupt handler (fptr)
|
||||
@@ -145,11 +160,19 @@ mraa_result_t mraa_gpio_edge_mode_multiple(mraa_gpio_context dev, mraa_gpio_edge
|
||||
*/
|
||||
mraa_result_t mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t edge, void (*fptr)(void*), void* args);
|
||||
|
||||
mraa_result_t mraa_gpio_isr_multiple(mraa_gpio_context dev, mraa_gpio_edge_t edge, void (*fptr)(void*), void* args);
|
||||
/**
|
||||
* Get an array of structures describing triggered events.
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @return Array of structures containing pairs of pin id's and the associated timestamp.
|
||||
* An event with negative id value indicates that no event was triggered for the respective pin.
|
||||
* The array length is that of the number of pins provided in mraa_gpio_init_multi().
|
||||
*/
|
||||
mraa_gpio_events_t mraa_gpio_get_events(mraa_gpio_context dev);
|
||||
|
||||
/**
|
||||
* Stop the current interrupt watcher on this Gpio, and set the Gpio edge mode
|
||||
* to MRAA_GPIO_EDGE_NONE
|
||||
* to MRAA_GPIO_EDGE_NONE(only for sysfs interface).
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @return Result of operation
|
||||
@@ -157,37 +180,36 @@ mraa_result_t mraa_gpio_isr_multiple(mraa_gpio_context dev, mraa_gpio_edge_t edg
|
||||
mraa_result_t mraa_gpio_isr_exit(mraa_gpio_context dev);
|
||||
|
||||
/**
|
||||
* Set Gpio Output Mode,
|
||||
* Set Gpio(s) Output Mode,
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param mode The Gpio Output Mode
|
||||
* @param mode The Gpio(s) Output Mode
|
||||
* @return Result of operation
|
||||
*/
|
||||
mraa_result_t mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode);
|
||||
|
||||
/**
|
||||
* Set Gpio direction
|
||||
* Set Gpio(s) direction
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param dir The direction of the Gpio
|
||||
* @param dir The direction of the Gpio(s)
|
||||
* @return Result of operation
|
||||
*/
|
||||
mraa_result_t mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir);
|
||||
|
||||
mraa_result_t mraa_gpio_dir_multiple(mraa_gpio_context dev, mraa_gpio_dir_t dir);
|
||||
|
||||
/**
|
||||
* Read Gpio direction
|
||||
* Read Gpio(s) direction
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param dir The address where to store the Gpio direction
|
||||
* @param dir The address where to store the Gpio(s) direction
|
||||
* @return Result of operation
|
||||
*/
|
||||
mraa_result_t mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t *dir);
|
||||
|
||||
/**
|
||||
* Close the Gpio context
|
||||
* - Will free the memory for the context and unexport the Gpio
|
||||
* - Will free the memory for the context and unexport the Gpio - sysfs interface.
|
||||
* - Will free up the memory used by context and close related file descriptors - chardev interface.
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @return Result of operation
|
||||
@@ -203,10 +225,15 @@ mraa_result_t mraa_gpio_close(mraa_gpio_context dev);
|
||||
*/
|
||||
int mraa_gpio_read(mraa_gpio_context dev);
|
||||
|
||||
/* Values array is provided by user. Must be the same size as the array passed in init.
|
||||
* It will be overwritten with the read results.
|
||||
/**
|
||||
* Read the Gpio(s) value. The user must provide an integer array with a length equal to the
|
||||
* number of pins provided to mraa_gpio_init_multi() function.
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param output_values The array provided by the user. Existing values will be overwritten with the newly read ones.
|
||||
* @return Result of operation
|
||||
*/
|
||||
mraa_result_t mraa_gpio_read_multiple(mraa_gpio_context dev, int output_values[]);
|
||||
mraa_result_t mraa_gpio_read_multi(mraa_gpio_context dev, int output_values[]);
|
||||
|
||||
/**
|
||||
* Write to the Gpio Value.
|
||||
@@ -217,7 +244,16 @@ mraa_result_t mraa_gpio_read_multiple(mraa_gpio_context dev, int output_values[]
|
||||
*/
|
||||
mraa_result_t mraa_gpio_write(mraa_gpio_context dev, int value);
|
||||
|
||||
mraa_result_t mraa_gpio_write_multiple(mraa_gpio_context dev, int input_values[]);
|
||||
/**
|
||||
* Write to the Gpio(s) Value. The user must provide an integer array with a length equal to the
|
||||
* number of pins provided to mraa_gpio_init_multi() function.
|
||||
*
|
||||
* @param dev The Gpio context
|
||||
* @param output_values The array provided by the user. It must contain the values intended to be written
|
||||
* to the gpio pins, in the same order as the init function.
|
||||
* @return Result of operation
|
||||
*/
|
||||
mraa_result_t mraa_gpio_write_multi(mraa_gpio_context dev, int input_values[]);
|
||||
|
||||
/**
|
||||
* Change ownership of the context.
|
||||
|
||||
103
examples/gpio_multiple_rw.c
Normal file
103
examples/gpio_multiple_rw.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* This currently works only on Intel Joule Platform. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mraa/gpio.h"
|
||||
|
||||
int running = 0;
|
||||
|
||||
void
|
||||
sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT) {
|
||||
printf("Closing down nicely\n");
|
||||
running = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
mraa_result_t r = MRAA_SUCCESS;
|
||||
/* These are Joule's onboard LED's. */
|
||||
int default_joule_leds[] = {100, 101, 102, 103};
|
||||
int *gpio_pins;
|
||||
int num_pins;
|
||||
int *input_values, *output_values;
|
||||
|
||||
printf("Provide int arg(s) if you want to toggle gpio pins other than Joule's onboard LED's\n");
|
||||
|
||||
if (argc < 2) {
|
||||
gpio_pins = default_joule_leds;
|
||||
num_pins = 4;
|
||||
} else {
|
||||
num_pins = argc - 1;
|
||||
gpio_pins = malloc(num_pins * sizeof(int));
|
||||
|
||||
for (int i = 0; i < num_pins; ++i) {
|
||||
gpio_pins[i] = strtol(argv[i+1], NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate input and output values arrays. */
|
||||
input_values = malloc(num_pins * sizeof(int));
|
||||
output_values = malloc(num_pins * sizeof(int));
|
||||
|
||||
mraa_init();
|
||||
fprintf(stdout, "MRAA Version: %s\nStarting program...\n", mraa_get_version());
|
||||
|
||||
mraa_gpio_context gpio = mraa_gpio_init_multi(gpio_pins, num_pins);
|
||||
if (gpio == NULL) {
|
||||
fprintf(stderr, "Error during gpio initialization\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = mraa_gpio_dir(gpio, MRAA_GPIO_OUT);
|
||||
if (r != MRAA_SUCCESS) {
|
||||
mraa_result_print(r);
|
||||
}
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
/* Set input values first. */
|
||||
memset(input_values, 0, num_pins * sizeof(int));
|
||||
|
||||
while (running == 0) {
|
||||
r = mraa_gpio_write_multi(gpio, input_values);
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (r != MRAA_SUCCESS) {
|
||||
mraa_result_print(r);
|
||||
} else {
|
||||
r = mraa_gpio_read_multi(gpio, output_values);
|
||||
if (r != MRAA_SUCCESS) {
|
||||
mraa_result_print(r);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_pins; ++i) {
|
||||
input_values[i] = (input_values[i] + 1) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
memset(input_values, 0, num_pins * sizeof(int));
|
||||
mraa_gpio_write_multi(gpio, input_values);
|
||||
|
||||
r = mraa_gpio_close(gpio);
|
||||
if (r != MRAA_SUCCESS) {
|
||||
mraa_result_print(r);
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
if (argc >= 2) {
|
||||
free(gpio_pins);
|
||||
}
|
||||
free(input_values);
|
||||
free(output_values);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -29,6 +29,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mraa_internal.h"
|
||||
#include "linux/gpio.h"
|
||||
|
||||
typedef struct {
|
||||
int chip_fd;
|
||||
@@ -38,6 +39,8 @@ typedef struct {
|
||||
typedef struct gpioline_info mraa_gpiod_line_info;
|
||||
|
||||
void _mraa_free_gpio_groups(mraa_gpio_context dev);
|
||||
void _mraa_close_gpio_event_handles(mraa_gpio_context dev);
|
||||
void _mraa_close_gpio_desc(mraa_gpio_context dev);
|
||||
int _mraa_gpiod_ioctl(int fd, unsigned long gpio_request, void* data);
|
||||
|
||||
mraa_gpiod_chip_info* mraa_get_chip_info_by_path(const char* path);
|
||||
@@ -45,6 +48,7 @@ mraa_gpiod_chip_info* mraa_get_chip_info_by_name(const char* name);
|
||||
mraa_gpiod_chip_info* mraa_get_chip_info_by_label(const char* label);
|
||||
mraa_gpiod_chip_info* mraa_get_chip_info_by_number(unsigned number);
|
||||
|
||||
mraa_gpiod_line_info* mraa_get_line_info_from_descriptor(int chip_fd, unsigned line_number);
|
||||
mraa_gpiod_line_info* mraa_get_line_info_by_chip_number(unsigned chip_number, unsigned line_number);
|
||||
mraa_gpiod_line_info* mraa_get_line_info_by_chip_name(const char* chip_name, unsigned line_number);
|
||||
mraa_gpiod_line_info* mraa_get_line_info_by_chip_label(const char* chip_label, unsigned line_number);
|
||||
@@ -52,8 +56,14 @@ mraa_gpiod_line_info* mraa_get_line_info_by_chip_label(const char* chip_label, u
|
||||
int mraa_get_lines_handle(int chip_fd, unsigned line_offsets[], unsigned num_lines, unsigned flags, unsigned default_value);
|
||||
int mraa_set_line_values(int line_handle, unsigned int num_lines, unsigned char input_values[]);
|
||||
int mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char output_values[]);
|
||||
int mraa_get_number_of_gpio_chips();
|
||||
|
||||
mraa_boolean_t mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo);
|
||||
mraa_boolean_t mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo);
|
||||
mraa_boolean_t mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo);
|
||||
mraa_boolean_t mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo);
|
||||
mraa_boolean_t mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo);
|
||||
|
||||
int mraa_get_number_of_gpio_chips();
|
||||
|
||||
/* Multiple gpio support. */
|
||||
typedef struct _gpio_group* mraa_gpiod_group_t;
|
||||
|
||||
@@ -155,18 +155,12 @@ struct _gpio {
|
||||
AGpio *bgpio;
|
||||
#endif
|
||||
|
||||
/* TODO: The below members should be integrated in gpio_group struct. */
|
||||
int dev_fd;
|
||||
int gpiod_handle;
|
||||
unsigned int gpio_chip;
|
||||
unsigned int gpio_line;
|
||||
|
||||
/* Multiple gpio support. These members are treated separately for now until multiple gpio support is accepted. */
|
||||
unsigned int num_chips;
|
||||
struct _gpio_group *gpio_group;
|
||||
/* Pin index passed by the user to gpio_group structures. */
|
||||
unsigned int num_chips;
|
||||
int *pin_to_gpio_table;
|
||||
unsigned int num_pins;
|
||||
mraa_gpio_events_t events;
|
||||
int *provided_pins;
|
||||
|
||||
struct _gpio *next;
|
||||
};
|
||||
|
||||
919
src/gpio/gpio.c
919
src/gpio/gpio.c
File diff suppressed because it is too large
Load Diff
@@ -50,38 +50,74 @@
|
||||
void
|
||||
_mraa_free_gpio_groups(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_group = dev->gpio_group;
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for (int i = 0; i < dev->num_chips; ++i) {
|
||||
if (gpio_group[i].is_required) {
|
||||
free(gpio_group[i].gpio_lines);
|
||||
free(gpio_group[i].rw_values);
|
||||
free(gpio_group[i].gpio_group_to_pins_table);
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
free(gpio_iter->gpio_lines);
|
||||
free(gpio_iter->rw_values);
|
||||
free(gpio_iter->gpio_group_to_pins_table);
|
||||
|
||||
if (gpio_group[i].gpiod_handle != -1) {
|
||||
close(gpio_group[i].gpiod_handle);
|
||||
if (gpio_iter->gpiod_handle != -1) {
|
||||
close(gpio_iter->gpiod_handle);
|
||||
}
|
||||
|
||||
if (gpio_group[i].event_handles != NULL) {
|
||||
for (int j = 0; j < gpio_group[i].num_gpio_lines; ++j) {
|
||||
close(gpio_group[i].event_handles[j]);
|
||||
if (gpio_iter->event_handles != NULL) {
|
||||
for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) {
|
||||
close(gpio_iter->event_handles[j]);
|
||||
}
|
||||
|
||||
free(gpio_group[i].event_handles);
|
||||
free(gpio_iter->event_handles);
|
||||
}
|
||||
|
||||
close(gpio_group[i].dev_fd);
|
||||
}
|
||||
close(gpio_iter->dev_fd);
|
||||
}
|
||||
|
||||
free(gpio_group);
|
||||
free(dev->gpio_group);
|
||||
|
||||
/* Also delete the pin to gpio chip mapping. */
|
||||
free(dev->pin_to_gpio_table);
|
||||
|
||||
/* User provided array saved internally. */
|
||||
free(dev->provided_pins);
|
||||
|
||||
/* Finally, delete event array. */
|
||||
free(dev->events);
|
||||
}
|
||||
|
||||
void
|
||||
_mraa_close_gpio_event_handles(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
if (gpio_iter->event_handles != NULL) {
|
||||
for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) {
|
||||
close(gpio_iter->event_handles[j]);
|
||||
}
|
||||
|
||||
free(gpio_iter->event_handles);
|
||||
|
||||
/* In the end, _mraa_free_gpio_groups will be called. */
|
||||
gpio_iter->event_handles = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_mraa_close_gpio_desc(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
if (gpio_iter->gpiod_handle != -1) {
|
||||
close(gpio_iter->gpiod_handle);
|
||||
gpio_iter->gpiod_handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_mraa__mraa_gpiod_ioctl(int fd, unsigned long gpio_request, void* data)
|
||||
_mraa_gpiod_ioctl(int fd, unsigned long gpio_request, void* data)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -319,6 +355,37 @@ mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char outp
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_IS_OUT);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_IS_OUT);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_ACTIVE_LOW);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_OPEN_DRAIN);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOHANDLE_REQUEST_OPEN_SOURCE);
|
||||
}
|
||||
|
||||
int
|
||||
mraa_get_number_of_gpio_chips()
|
||||
{
|
||||
@@ -343,4 +410,3 @@ mraa_get_number_of_gpio_chips()
|
||||
/* Assume opendir() error. */
|
||||
return num_chips;
|
||||
}
|
||||
|
||||
|
||||
39
src/mraa.c
39
src/mraa.c
@@ -57,6 +57,7 @@
|
||||
#include "firmata/firmata_mraa.h"
|
||||
#include "grovepi/grovepi.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio/gpio_chardev.h"
|
||||
#include "version.h"
|
||||
#include "i2c.h"
|
||||
#include "pwm.h"
|
||||
@@ -100,43 +101,7 @@ mraa_set_log_level(int level)
|
||||
|
||||
mraa_boolean_t mraa_is_kernel_chardev_interface_compatible()
|
||||
{
|
||||
struct utsname buf;
|
||||
int status;
|
||||
|
||||
status = uname(&buf);
|
||||
|
||||
if (status) {
|
||||
syslog(LOG_ERR, "uname() error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int major, minor;
|
||||
char *token;
|
||||
|
||||
token = strtok(buf.release, ".");
|
||||
if (token == NULL) {
|
||||
syslog(LOG_ERR, "Could not find kernel version major number");
|
||||
return 0;
|
||||
}
|
||||
status = mraa_atoi(token, &major);
|
||||
if (status) {
|
||||
syslog(LOG_ERR, "mraa_atoi() error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
token = strtok(NULL, ".");
|
||||
if (token == NULL) {
|
||||
syslog(LOG_ERR, "Could not find kernel version minor number");
|
||||
return 0;
|
||||
}
|
||||
status = mraa_atoi(token, &minor);
|
||||
if (status) {
|
||||
syslog(LOG_ERR, "mraa_atoi() error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (major < 4 || minor < 8) {
|
||||
syslog(LOG_ERR, "Kernel version %i.%i not supported for chardev interface. Need version 4.8 or newer!", major, minor);
|
||||
if (mraa_get_number_of_gpio_chips() <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user