mirror of
https://github.com/xtacocorex/CHIP_IO
synced 2025-07-20 12:53:22 +00:00
Fixed a bunch of error handling
This commit is contained in:
@ -145,7 +145,7 @@ int softpwm_set_duty_cycle(const char *key, float duty) {;
|
|||||||
void *softpwm_thread_toggle(void *key)
|
void *softpwm_thread_toggle(void *key)
|
||||||
{
|
{
|
||||||
struct softpwm *pwm;
|
struct softpwm *pwm;
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
struct timespec tim_on;
|
struct timespec tim_on;
|
||||||
struct timespec tim_off;
|
struct timespec tim_off;
|
||||||
unsigned int sec;
|
unsigned int sec;
|
||||||
@ -237,7 +237,7 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
|
|||||||
struct softpwm *new_pwm, *pwm;
|
struct softpwm *new_pwm, *pwm;
|
||||||
pthread_t new_thread;
|
pthread_t new_thread;
|
||||||
pthread_mutex_t *new_params_lock;
|
pthread_mutex_t *new_params_lock;
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
get_gpio_number(key, &gpio);
|
get_gpio_number(key, &gpio);
|
||||||
@ -296,7 +296,7 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
|
|||||||
int softpwm_disable(const char *key)
|
int softpwm_disable(const char *key)
|
||||||
{
|
{
|
||||||
struct softpwm *pwm, *temp, *prev_pwm = NULL;
|
struct softpwm *pwm, *temp, *prev_pwm = NULL;
|
||||||
unsigned int gpio = 0;
|
int gpio = 0;
|
||||||
|
|
||||||
// remove from list
|
// remove from list
|
||||||
pwm = exported_pwms;
|
pwm = exported_pwms;
|
||||||
|
260
source/common.c
260
source/common.c
@ -42,6 +42,7 @@ SOFTWARE.
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -49,24 +50,25 @@ SOFTWARE.
|
|||||||
int setup_error = 0;
|
int setup_error = 0;
|
||||||
int module_setup = 0;
|
int module_setup = 0;
|
||||||
|
|
||||||
|
|
||||||
// I have no idea if this table is correct, we shall see - Robert Wolterman
|
// I have no idea if this table is correct, we shall see - Robert Wolterman
|
||||||
pins_t pins_info[] = {
|
pins_t pins_info[] = {
|
||||||
{ "GND", "U13_1", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U13_1", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "CHG-IN", "U13_2", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "CHG-IN", "U13_2", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "VCC-5V", "U13_3", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "VCC-5V", "U13_3", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U13_4", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U13_4", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "VCC-3V3", "U13_5", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "VCC-3V3", "U13_5", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "TS", "U13_6", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "TS", "U13_6", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "VCC-1V8", "U13_7", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "VCC-1V8", "U13_7", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "BAT", "U13_8", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "BAT", "U13_8", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "TWI1-SDA", "U13_9", 48, BASE_METHOD_AS_IS, -1, -1},
|
{ "TWI1-SDA", "U13_9", 48, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "PWRON", "U13_10", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "PWRON", "U13_10", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "TWI1-SCK", "U13_11", 47, BASE_METHOD_AS_IS, -1, -1},
|
{ "TWI1-SCK", "U13_11", 47, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U13_12", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U13_12", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "X1", "U13_13", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "X1", "U13_13", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "X2", "U13_14", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "X2", "U13_14", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "Y1", "U13_15", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "Y1", "U13_15", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "Y2", "U13_16", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "Y2", "U13_16", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "LCD-D2", "U13_17", 98, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-D2", "U13_17", 98, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "PWM0", "U13_18", 34, BASE_METHOD_AS_IS, 0, -1},
|
{ "PWM0", "U13_18", 34, BASE_METHOD_AS_IS, 0, -1},
|
||||||
{ "LCD-D4", "U13_19", 100, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-D4", "U13_19", 100, BASE_METHOD_AS_IS, -1, -1},
|
||||||
@ -89,20 +91,20 @@ pins_t pins_info[] = {
|
|||||||
{ "LCD-D23", "U13_36", 119, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-D23", "U13_36", 119, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "LCD-VSYNC", "U13_37", 123, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-VSYNC", "U13_37", 123, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "LCD-HSYNC", "U13_38", 122, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-HSYNC", "U13_38", 122, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U13_39", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U13_39", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "LCD-DE", "U13_40", 121, BASE_METHOD_AS_IS, -1, -1},
|
{ "LCD-DE", "U13_40", 121, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U14_1", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U14_1", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "VCC-5V", "U14_2", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "VCC-5V", "U14_2", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "UART1-TX", "U14_3", 195, BASE_METHOD_AS_IS, -1, -1},
|
{ "UART1-TX", "U14_3", 195, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "HPL", "U14_4", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "HPL", "U14_4", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "UART1-RX", "U14_5", 196, BASE_METHOD_AS_IS, -1, -1},
|
{ "UART1-RX", "U14_5", 196, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "HPCOM", "U14_6", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "HPCOM", "U14_6", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "FEL", "U14_7", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "FEL", "U14_7", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "HPR", "U14_8", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "HPR", "U14_8", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "VCC-3V3", "U14_9", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "VCC-3V3", "U14_9", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "MICM", "U14_10", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "MICM", "U14_10", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "LRADC", "U14_11", 0, BASE_METHOD_AS_IS, -1, 0},
|
{ "LRADC", "U14_11", -1, BASE_METHOD_AS_IS, -1, 0},
|
||||||
{ "MICIN1", "U14_12", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "MICIN1", "U14_12", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "XIO-P0", "U14_13", 0, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P0", "U14_13", 0, BASE_METHOD_XIO, -1, -1},
|
||||||
{ "XIO-P1", "U14_14", 1, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P1", "U14_14", 1, BASE_METHOD_XIO, -1, -1},
|
||||||
{ "XIO-P2", "U14_15", 2, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P2", "U14_15", 2, BASE_METHOD_XIO, -1, -1},
|
||||||
@ -111,8 +113,8 @@ pins_t pins_info[] = {
|
|||||||
{ "XIO-P5", "U14_18", 5, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P5", "U14_18", 5, BASE_METHOD_XIO, -1, -1},
|
||||||
{ "XIO-P6", "U14_19", 6, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P6", "U14_19", 6, BASE_METHOD_XIO, -1, -1},
|
||||||
{ "XIO-P7", "U14_20", 7, BASE_METHOD_XIO, -1, -1},
|
{ "XIO-P7", "U14_20", 7, BASE_METHOD_XIO, -1, -1},
|
||||||
{ "GND", "U14_21", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U14_21", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U14_22", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U14_22", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "AP-EINT1", "U14_23", 193, BASE_METHOD_AS_IS, -1, -1},
|
{ "AP-EINT1", "U14_23", 193, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "AP-EINT3", "U14_24", 35, BASE_METHOD_AS_IS, -1, -1},
|
{ "AP-EINT3", "U14_24", 35, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "TWI2-SDA", "U14_25", 50, BASE_METHOD_AS_IS, -1, -1},
|
{ "TWI2-SDA", "U14_25", 50, BASE_METHOD_AS_IS, -1, -1},
|
||||||
@ -129,9 +131,9 @@ pins_t pins_info[] = {
|
|||||||
{ "CSID5", "U14_36", 137, BASE_METHOD_AS_IS, -1, -1},
|
{ "CSID5", "U14_36", 137, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "CSID6", "U14_37", 138, BASE_METHOD_AS_IS, -1, -1},
|
{ "CSID6", "U14_37", 138, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "CSID7", "U14_38", 139, BASE_METHOD_AS_IS, -1, -1},
|
{ "CSID7", "U14_38", 139, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U14_39", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U14_39", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ "GND", "U14_40", 0, BASE_METHOD_AS_IS, -1, -1},
|
{ "GND", "U14_40", -1, BASE_METHOD_AS_IS, -1, -1},
|
||||||
{ NULL, NULL, 0, 0, -1, -1}
|
{ NULL, NULL, -1, 0, -1, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -144,14 +146,14 @@ pins_t pins_info[] = {
|
|||||||
// http://stackoverflow.com/questions/612097/how-can-i-get-the-list-of-files-in-a-directory-using-c-or-c
|
// http://stackoverflow.com/questions/612097/how-can-i-get-the-list-of-files-in-a-directory-using-c-or-c
|
||||||
#define GPIO_PATH "/sys/class/gpio"
|
#define GPIO_PATH "/sys/class/gpio"
|
||||||
#define EXPANDER "pcf8574a\n"
|
#define EXPANDER "pcf8574a\n"
|
||||||
int num_get_xio_base = 0; /* for self-test purposes */
|
|
||||||
|
/* returns -1 for error */
|
||||||
int get_xio_base(void)
|
int get_xio_base(void)
|
||||||
{
|
{
|
||||||
char label_file[FILENAME_BUFFER_SIZE];
|
char label_file[FILENAME_BUFFER_SIZE];
|
||||||
FILE *label_fp;
|
FILE *label_fp;
|
||||||
char base_file[FILENAME_BUFFER_SIZE];
|
char base_file[FILENAME_BUFFER_SIZE];
|
||||||
FILE *base_fp;
|
FILE *base_fp;
|
||||||
char input_line[80];
|
|
||||||
// Makes use of static variable xio_base_address to maintain state between
|
// Makes use of static variable xio_base_address to maintain state between
|
||||||
// calls. First time this is called, xio_base_address is -1, so the actual
|
// calls. First time this is called, xio_base_address is -1, so the actual
|
||||||
// base address is calculated and stored in xio_base_address. Subsequent
|
// base address is calculated and stored in xio_base_address. Subsequent
|
||||||
@ -162,33 +164,55 @@ int get_xio_base(void)
|
|||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
|
|
||||||
if (xio_base_address == -1 && (dir = opendir (GPIO_PATH)) != NULL) {
|
if (xio_base_address != -1)
|
||||||
|
return xio_base_address;
|
||||||
|
|
||||||
|
dir = opendir (GPIO_PATH);
|
||||||
|
if (dir == NULL) {
|
||||||
|
char err[256];
|
||||||
|
snprintf(err, sizeof(err), "get_xio_base: could not open '%s' (%s)", GPIO_PATH, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (xio_base_address == -1 && (ent = readdir (dir)) != NULL) {
|
while (xio_base_address == -1 && (ent = readdir (dir)) != NULL) {
|
||||||
lstat(ent->d_name,&sbuf);
|
lstat(ent->d_name,&sbuf);
|
||||||
if (S_ISDIR(sbuf.st_mode)) {
|
if (S_ISDIR(sbuf.st_mode)) {
|
||||||
if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) {
|
if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) {
|
||||||
continue; /* skip "." and ".." entries */
|
continue; /* skip "." and ".." entries */
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file);
|
snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file);
|
||||||
label_fp = fopen(label_file, "r");
|
label_fp = fopen(label_file, "r");
|
||||||
if (label_fp != NULL) {
|
if (label_fp != NULL) {
|
||||||
char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line); ASSRT(s);
|
char input_line[80]; input_line[0] = '\0';
|
||||||
|
char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line);
|
||||||
fclose(label_fp);
|
fclose(label_fp);
|
||||||
if (strcmp(input_line, EXPANDER) == 0) {
|
if (s != NULL && strcmp(input_line, EXPANDER) == 0) {
|
||||||
/* Found the expander, get the contents of base */
|
/* Found the expander, get the contents of base */
|
||||||
snprintf(base_file, sizeof(base_file), "%s/%s/base", GPIO_PATH, ent->d_name); BUF2SMALL(base_file);
|
snprintf(base_file, sizeof(base_file), "%s/%s/base", GPIO_PATH, ent->d_name); BUF2SMALL(base_file);
|
||||||
base_fp = fopen(base_file, "r"); ASSRT(base_fp != NULL);
|
base_fp = fopen(base_file, "r");
|
||||||
s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line); ASSRT(s);
|
if (base_fp == NULL) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "get_xio_base: could not open '%s' (%s)", base_file, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
break; /* error, exit loop */
|
||||||
|
}
|
||||||
|
s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line);
|
||||||
fclose(base_fp);
|
fclose(base_fp);
|
||||||
|
if (s == NULL) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "get_xio_base: could not read '%s' (%s)", base_file, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
break; /* error, exit loop */
|
||||||
|
}
|
||||||
/* Remember the value in the static local. */
|
/* Remember the value in the static local. */
|
||||||
xio_base_address = atoi(input_line); ASSRT(xio_base_address > 0);
|
xio_base_address = atoi(input_line);
|
||||||
num_get_xio_base++; /* for self-test purposes */
|
|
||||||
}
|
}
|
||||||
} /* if label file is open */
|
} /* if label file is open */
|
||||||
} /* if isdir */
|
} /* if isdir */
|
||||||
} /* while */
|
} /* while */
|
||||||
closedir (dir);
|
closedir (dir);
|
||||||
}
|
|
||||||
|
|
||||||
return xio_base_address;
|
return xio_base_address;
|
||||||
} /* get_xio_base */
|
} /* get_xio_base */
|
||||||
@ -197,6 +221,7 @@ int get_xio_base(void)
|
|||||||
int gpio_number(pins_t *pin)
|
int gpio_number(pins_t *pin)
|
||||||
{
|
{
|
||||||
int gpio_num = -1;
|
int gpio_num = -1;
|
||||||
|
int xio_base;
|
||||||
|
|
||||||
switch (pin->base_method) {
|
switch (pin->base_method) {
|
||||||
case BASE_METHOD_AS_IS:
|
case BASE_METHOD_AS_IS:
|
||||||
@ -204,11 +229,16 @@ int gpio_number(pins_t *pin)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BASE_METHOD_XIO:
|
case BASE_METHOD_XIO:
|
||||||
gpio_num = pin->gpio + get_xio_base();
|
xio_base = get_xio_base();
|
||||||
|
if (xio_base <= 0) {
|
||||||
|
char err[80]; snprintf(err, sizeof(err), "gpio_number: %d found for %s", xio_base, pin->name);
|
||||||
|
add_error_msg(err);
|
||||||
|
break; /* error, exit switch */
|
||||||
|
}
|
||||||
|
gpio_num = pin->gpio + xio_base;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSRT(gpio_num != -1);
|
|
||||||
return gpio_num;
|
return gpio_num;
|
||||||
} /* gpio_number */
|
} /* gpio_number */
|
||||||
|
|
||||||
@ -221,7 +251,7 @@ int lookup_gpio_by_key(const char *key)
|
|||||||
return gpio_number(p);
|
return gpio_number(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lookup_gpio_by_name(const char *name)
|
int lookup_gpio_by_name(const char *name)
|
||||||
@ -232,7 +262,7 @@ int lookup_gpio_by_name(const char *name)
|
|||||||
return gpio_number(p);
|
return gpio_number(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lookup_ain_by_key(const char *key)
|
int lookup_ain_by_key(const char *key)
|
||||||
@ -325,15 +355,18 @@ int get_pwm_key_by_name(const char *name, char *key)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_gpio_number(const char *key, unsigned int *gpio)
|
int get_gpio_number(const char *key, int *gpio)
|
||||||
{
|
{
|
||||||
|
int status = 0; /* assume success */
|
||||||
*gpio = lookup_gpio_by_key(key);
|
*gpio = lookup_gpio_by_key(key);
|
||||||
|
|
||||||
if (!*gpio) {
|
if (*gpio <= 0) {
|
||||||
*gpio = lookup_gpio_by_name(key);
|
*gpio = lookup_gpio_by_name(key);
|
||||||
|
if (*gpio <= 0) {
|
||||||
|
status = -1; /* error */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_key(const char *input, char *key)
|
int get_key(const char *input, char *key)
|
||||||
@ -421,73 +454,136 @@ int get_spi_bus_path_number(unsigned int spi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct dyn_int_array {
|
// We do not know at compile time how many GPIOs there are, so it is not safe
|
||||||
int num_elements;
|
// to declare per-GPIO arrays with a static size. The "dyn_int_array_*"
|
||||||
int *array;
|
// functions implement a dynamic integer array which grows as needed at run
|
||||||
};
|
// time. Users of a dynamic array do not access the array directly, but by
|
||||||
|
// access methods.
|
||||||
|
//
|
||||||
|
// To use, declare a dyn_int_array_t pointer initialized to NULL:
|
||||||
|
// dyn_int_array_t *my_per_gpio_array = NULL;
|
||||||
|
// If declared as a local to a function, consider making it "static":
|
||||||
|
// static dyn_int_array_t *my_per_gpio_array = NULL;
|
||||||
|
// The access methods must be passed a pointer to this pointer.
|
||||||
|
// Then when reading and writing to array elements, it is usually important
|
||||||
|
// to supply a "default value". This is so that as the array grows, the
|
||||||
|
// as-yet unused elements can be initialzied to a desired value.
|
||||||
|
// my_index = 100;
|
||||||
|
// dyn_int_array_set(&my_per_gpio_array, my_index, my_value, -1);
|
||||||
|
// This initializes elements 0-99 to -1, and element 100 to my_value. For
|
||||||
|
// efficiency purposes, it grows the array to half again larger than it needs
|
||||||
|
// to. Thus, elements 101-149 will be initialized to -1.
|
||||||
|
//
|
||||||
|
// If an element past the end of the array is read, the array is once again
|
||||||
|
// grown, with initialization:
|
||||||
|
// my_index = 500;
|
||||||
|
// int val = dyn_int_array_get(&my_per_gpio_array, my_index, -1);
|
||||||
|
// This grows the array to 749 (half again larger than 500) and initializes all
|
||||||
|
// the new elements to -1, including element 500, which is then returned.
|
||||||
|
|
||||||
void *dyn_int_array_create(int initial_num_elements, int initial_val)
|
/* internal function; only called by access methods. */
|
||||||
|
dyn_int_array_t *dyn_int_array_create(int initial_num_elements, int initial_val)
|
||||||
{
|
{
|
||||||
struct dyn_int_array *new_array = (struct dyn_int_array *)malloc(sizeof(struct dyn_int_array));
|
dyn_int_array_t *new_array = (dyn_int_array_t *)malloc(sizeof(dyn_int_array_t));
|
||||||
ASSRT(new_array != NULL);
|
ASSRT(new_array != NULL); /* out of memory */
|
||||||
|
|
||||||
new_array->num_elements = initial_num_elements;
|
new_array->num_elements = initial_num_elements;
|
||||||
new_array->array = (int *)malloc(initial_num_elements * sizeof(int));
|
new_array->content = (int *)malloc(initial_num_elements * sizeof(int));
|
||||||
ASSRT(new_array->array != NULL);
|
ASSRT(new_array->content != NULL); /* out of memory */
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < initial_num_elements; i++)
|
for (i = 0; i < initial_num_elements; i++)
|
||||||
new_array->array[i] = initial_val;
|
new_array->content[i] = initial_val;
|
||||||
|
|
||||||
return (void *)new_array;
|
return new_array;
|
||||||
} /* dyn_int_array_create */
|
} /* dyn_int_array_create */
|
||||||
|
|
||||||
|
|
||||||
void dyn_int_array_set(void **in_array, int i, int val, int initial_val)
|
void dyn_int_array_set(dyn_int_array_t **in_array, int i, int val, int initial_val)
|
||||||
{
|
{
|
||||||
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array);
|
dyn_int_array_t *array = *in_array;
|
||||||
if (array == NULL)
|
if (array == NULL) { /* if array hasn't been created yet */
|
||||||
array = dyn_int_array_create(i * 3 / 2, initial_val);
|
array = dyn_int_array_create((i+1) * 3 / 2, initial_val);
|
||||||
|
*in_array = array;
|
||||||
|
}
|
||||||
|
|
||||||
if (i >= array->num_elements) {
|
if (i >= array->num_elements) {
|
||||||
int new_num_elements = i * 3 / 2; /* half-again larger than current request */
|
int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */
|
||||||
array->array = realloc(array->array, new_num_elements * sizeof(int));
|
array->content = realloc(array->content, new_num_elements * sizeof(int));
|
||||||
ASSRT(array->array != NULL);
|
ASSRT(array->content != NULL); /* out of memory */
|
||||||
// Zero out the newly allocated elements.
|
// Zero out the newly allocated elements.
|
||||||
while (array->num_elements < new_num_elements) {
|
while (array->num_elements < new_num_elements) {
|
||||||
array->array[array->num_elements] = initial_val;
|
array->content[array->num_elements] = initial_val;
|
||||||
array->num_elements ++;
|
array->num_elements ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
array->array[i] = val;
|
array->content[i] = val;
|
||||||
*in_array = (void *)array;
|
|
||||||
} /* dyn_int_array_set */
|
} /* dyn_int_array_set */
|
||||||
|
|
||||||
|
|
||||||
int dyn_int_array_get(void **in_array, int i, int initial_val)
|
int dyn_int_array_get(dyn_int_array_t **in_array, int i, int initial_val)
|
||||||
{
|
{
|
||||||
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array);
|
dyn_int_array_t *array = *in_array;
|
||||||
if (array == NULL)
|
if (array == NULL) { /* if array hasn't been created yet */
|
||||||
array = dyn_int_array_create(i * 3 / 2, initial_val);
|
array = dyn_int_array_create((i+1) * 3 / 2, initial_val);
|
||||||
|
*in_array = array;
|
||||||
|
}
|
||||||
|
|
||||||
if (i >= array->num_elements) {
|
if (i >= array->num_elements) {
|
||||||
int new_num_elements = i * 3 / 2; /* half-again larger than current request */
|
int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */
|
||||||
array->array = realloc(array->array, new_num_elements * sizeof(int));
|
array->content = realloc(array->content, new_num_elements * sizeof(int));
|
||||||
ASSRT(array->array != NULL);
|
ASSRT(array->content != NULL); /* out of memory */
|
||||||
// Zero out the newly allocated elements.
|
// Zero out the newly allocated elements.
|
||||||
while (array->num_elements < new_num_elements) {
|
while (array->num_elements < new_num_elements) {
|
||||||
array->array[array->num_elements] = initial_val;
|
array->content[array->num_elements] = initial_val;
|
||||||
array->num_elements ++;
|
array->num_elements ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array->array[i];
|
return array->content[i];
|
||||||
*in_array = (void *)array;
|
|
||||||
} /* dyn_int_array_get */
|
} /* dyn_int_array_get */
|
||||||
|
|
||||||
|
|
||||||
void dyn_int_array_delete(void **in_array)
|
void dyn_int_array_delete(dyn_int_array_t **in_array)
|
||||||
{
|
{
|
||||||
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array);
|
dyn_int_array_t *array = *in_array;
|
||||||
free(array->array);
|
free(array->content);
|
||||||
free(array);
|
free(array);
|
||||||
} /* dyn_int_array_delete */
|
} /* dyn_int_array_delete */
|
||||||
|
|
||||||
|
|
||||||
|
char error_msg_buff[1024]; /* written to when an error must be returned */
|
||||||
|
|
||||||
|
void clear_error_msg(void)
|
||||||
|
{
|
||||||
|
error_msg_buff[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *get_error_msg(void)
|
||||||
|
{
|
||||||
|
return error_msg_buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add_error_msg(char *msg)
|
||||||
|
{
|
||||||
|
int buff_len = strnlen(error_msg_buff, sizeof(error_msg_buff)); ASSRT(buff_len < sizeof(error_msg_buff));
|
||||||
|
int remaining = sizeof(error_msg_buff) - buff_len - 1; /* leave room for final null */
|
||||||
|
|
||||||
|
if (buff_len > 0 && remaining > 0) { /* include newline between messages */
|
||||||
|
error_msg_buff[buff_len] = '\n';
|
||||||
|
buff_len ++;
|
||||||
|
remaining --;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *start = &error_msg_buff[buff_len]; /* points at null in the buffer */
|
||||||
|
int msg_len = strlen(msg);
|
||||||
|
if (msg_len >= remaining)
|
||||||
|
msg_len = remaining; /* don't overflow buffer; truncate message */
|
||||||
|
if (msg_len > 0)
|
||||||
|
memcpy(start, msg, msg_len);
|
||||||
|
|
||||||
|
start[msg_len] = '\0';
|
||||||
|
}
|
||||||
|
@ -69,6 +69,14 @@ typedef struct pins_t {
|
|||||||
int ain;
|
int ain;
|
||||||
} pins_t;
|
} pins_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct dyn_int_array_s {
|
||||||
|
int num_elements;
|
||||||
|
int *content;
|
||||||
|
};
|
||||||
|
typedef struct dyn_int_array_s dyn_int_array_t;
|
||||||
|
|
||||||
|
|
||||||
#define FILENAME_BUFFER_SIZE 128
|
#define FILENAME_BUFFER_SIZE 128
|
||||||
|
|
||||||
int setup_error;
|
int setup_error;
|
||||||
@ -84,12 +92,15 @@ int copy_key_by_key(const char *input_key, char *key);
|
|||||||
int copy_pwm_key_by_key(const char *input_key, char *key);
|
int copy_pwm_key_by_key(const char *input_key, char *key);
|
||||||
int get_key_by_name(const char *name, char *key);
|
int get_key_by_name(const char *name, char *key);
|
||||||
int get_pwm_key_by_name(const char *name, char *key);
|
int get_pwm_key_by_name(const char *name, char *key);
|
||||||
int get_gpio_number(const char *key, unsigned int *gpio);
|
int get_gpio_number(const char *key, int *gpio);
|
||||||
int get_key(const char *input, char *key);
|
int get_key(const char *input, char *key);
|
||||||
int get_pwm_key(const char *input, char *key);
|
int get_pwm_key(const char *input, char *key);
|
||||||
int get_adc_ain(const char *key, unsigned int *ain);
|
int get_adc_ain(const char *key, unsigned int *ain);
|
||||||
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len);
|
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len);
|
||||||
int get_spi_bus_path_number(unsigned int spi);
|
int get_spi_bus_path_number(unsigned int spi);
|
||||||
void dyn_int_array_set(void **in_array, int i, int val, int initial_val);
|
void dyn_int_array_set(dyn_int_array_t **in_array, int i, int val, int initial_val);
|
||||||
int dyn_int_array_get(void **in_array, int i, int initial_val);
|
int dyn_int_array_get(dyn_int_array_t **in_array, int i, int initial_val);
|
||||||
void dyn_int_array_delete(void **in_array);
|
void dyn_int_array_delete(dyn_int_array_t **in_array);
|
||||||
|
void clear_error_msg(void);
|
||||||
|
char *get_error_msg(void);
|
||||||
|
void add_error_msg(char *msg);
|
||||||
|
@ -42,6 +42,7 @@ SOFTWARE.
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "event_gpio.h"
|
#include "event_gpio.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@ -52,7 +53,7 @@ const char *stredge[4] = {"none", "rising", "falling", "both"};
|
|||||||
struct fdx
|
struct fdx
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
int initial;
|
int initial;
|
||||||
unsigned int is_evented;
|
unsigned int is_evented;
|
||||||
struct fdx *next;
|
struct fdx *next;
|
||||||
@ -62,8 +63,8 @@ struct fdx *fd_list = NULL;
|
|||||||
// event callbacks
|
// event callbacks
|
||||||
struct callback
|
struct callback
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
void (*func)(unsigned int gpio);
|
void (*func)(int gpio);
|
||||||
struct callback *next;
|
struct callback *next;
|
||||||
};
|
};
|
||||||
struct callback *callbacks = NULL;
|
struct callback *callbacks = NULL;
|
||||||
@ -71,38 +72,47 @@ struct callback *callbacks = NULL;
|
|||||||
// gpio exports
|
// gpio exports
|
||||||
struct gpio_exp
|
struct gpio_exp
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
struct gpio_exp *next;
|
struct gpio_exp *next;
|
||||||
};
|
};
|
||||||
struct gpio_exp *exported_gpios = NULL;
|
struct gpio_exp *exported_gpios = NULL;
|
||||||
|
|
||||||
pthread_t threads;
|
pthread_t threads;
|
||||||
void *event_occurred = NULL;
|
dyn_int_array_t *event_occurred = NULL;
|
||||||
int thread_running = 0;
|
int thread_running = 0;
|
||||||
int epfd = -1;
|
int epfd = -1;
|
||||||
|
|
||||||
int gpio_export(unsigned int gpio)
|
|
||||||
|
int gpio_export(int gpio)
|
||||||
{
|
{
|
||||||
int fd, len;
|
int fd, len, e_no;
|
||||||
char str_gpio[16];
|
char filename[MAX_FILENAME];
|
||||||
|
char str_gpio[80];
|
||||||
struct gpio_exp *new_gpio, *g;
|
struct gpio_exp *new_gpio, *g;
|
||||||
|
|
||||||
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/export"); BUF2SMALL(filename);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||||
{
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_export: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
|
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
|
||||||
ssize_t s = write(fd, str_gpio, len);
|
ssize_t s = write(fd, str_gpio, len); e_no = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
if (s != len)
|
if (s != len)
|
||||||
{
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_export: could not write '%s' to %s (%s)", str_gpio, filename, strerror(e_no));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to list
|
// add to list
|
||||||
new_gpio = malloc(sizeof(struct gpio_exp));
|
new_gpio = malloc(sizeof(struct gpio_exp)); ASSRT(new_gpio != NULL);
|
||||||
if (new_gpio == 0)
|
|
||||||
return -1; // out of memory
|
|
||||||
|
|
||||||
new_gpio->gpio = gpio;
|
new_gpio->gpio = gpio;
|
||||||
new_gpio->next = NULL;
|
new_gpio->next = NULL;
|
||||||
@ -118,10 +128,12 @@ int gpio_export(unsigned int gpio)
|
|||||||
g = g->next;
|
g = g->next;
|
||||||
g->next = new_gpio;
|
g->next = new_gpio;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_value_fd(unsigned int gpio)
|
return 0;
|
||||||
|
} /* gpio_export */
|
||||||
|
|
||||||
|
|
||||||
|
void close_value_fd(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
struct fdx *temp;
|
struct fdx *temp;
|
||||||
@ -144,9 +156,10 @@ void close_value_fd(unsigned int gpio)
|
|||||||
f = f->next;
|
f = f->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} /* close_value_fd */
|
||||||
|
|
||||||
int fd_lookup(unsigned int gpio)
|
|
||||||
|
int fd_lookup(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
while (f != NULL)
|
while (f != NULL)
|
||||||
@ -155,16 +168,16 @@ int fd_lookup(unsigned int gpio)
|
|||||||
return f->fd;
|
return f->fd;
|
||||||
f = f->next;
|
f = f->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_fd_list(unsigned int gpio, int fd)
|
|
||||||
|
int add_fd_list(int gpio, int fd)
|
||||||
{
|
{
|
||||||
struct fdx *new_fd;
|
struct fdx *new_fd;
|
||||||
|
|
||||||
new_fd = malloc(sizeof(struct fdx));
|
new_fd = malloc(sizeof(struct fdx)); ASSRT(new_fd != NULL);
|
||||||
if (new_fd == 0)
|
|
||||||
return -1; // out of memory
|
|
||||||
|
|
||||||
new_fd->fd = fd;
|
new_fd->fd = fd;
|
||||||
new_fd->gpio = gpio;
|
new_fd->gpio = gpio;
|
||||||
@ -176,10 +189,11 @@ int add_fd_list(unsigned int gpio, int fd)
|
|||||||
new_fd->next = fd_list;
|
new_fd->next = fd_list;
|
||||||
}
|
}
|
||||||
fd_list = new_fd;
|
fd_list = new_fd;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int open_value_file(unsigned int gpio)
|
int open_value_file(int gpio)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char filename[MAX_FILENAME];
|
char filename[MAX_FILENAME];
|
||||||
@ -188,26 +202,44 @@ int open_value_file(unsigned int gpio)
|
|||||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
|
||||||
|
|
||||||
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
|
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "open_value_file: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
add_fd_list(gpio, fd);
|
add_fd_list(gpio, fd);
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gpio_unexport(unsigned int gpio)
|
return fd;
|
||||||
|
} /* open_value_file */
|
||||||
|
|
||||||
|
|
||||||
|
int gpio_unexport(int gpio)
|
||||||
{
|
{
|
||||||
int fd, len;
|
int fd, len, e_no;
|
||||||
|
char filename[MAX_FILENAME];
|
||||||
char str_gpio[16];
|
char str_gpio[16];
|
||||||
struct gpio_exp *g, *temp, *prev_g = NULL;
|
struct gpio_exp *g, *temp, *prev_g = NULL;
|
||||||
|
|
||||||
close_value_fd(gpio);
|
close_value_fd(gpio);
|
||||||
|
|
||||||
if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/unexport"); BUF2SMALL(filename);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_unexport: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
|
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
|
||||||
ssize_t s = write(fd, str_gpio, len); ASSRT(s == len);
|
ssize_t s = write(fd, str_gpio, len); e_no = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
if (s != len) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_unexport: could not write '%s' (%s)", filename, strerror(e_no));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// remove from list
|
// remove from list
|
||||||
g = exported_gpios;
|
g = exported_gpios;
|
||||||
@ -227,61 +259,100 @@ int gpio_unexport(unsigned int gpio)
|
|||||||
g = g->next;
|
g = g->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
|
int gpio_set_direction(int gpio, unsigned int in_flag)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd, e_no;
|
||||||
char filename[MAX_FILENAME];
|
char filename[MAX_FILENAME]; filename[0] = '\0';
|
||||||
char direction[16] = { 0 };
|
|
||||||
|
|
||||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
|
||||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_direction: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char direction[16];
|
||||||
if (in_flag) {
|
if (in_flag) {
|
||||||
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
|
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
|
||||||
} else {
|
} else {
|
||||||
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
|
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
|
||||||
}
|
}
|
||||||
ssize_t s = write(fd, direction, strlen(direction)); ASSRT(s == strlen(direction));
|
ssize_t s = write(fd, direction, strlen(direction)); e_no = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
if (s != strlen(direction)) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_direction: could not write '%s' (%s)", filename, strerror(e_no));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_get_direction(unsigned int gpio, unsigned int *value)
|
int gpio_get_direction(int gpio, unsigned int *value)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd, e_no;
|
||||||
char direction[4] = { 0 };
|
|
||||||
char filename[MAX_FILENAME];
|
char filename[MAX_FILENAME];
|
||||||
|
|
||||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
|
||||||
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
|
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_direction: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
if (lseek(fd, 0, SEEK_SET) < 0) {
|
||||||
ssize_t s = read(fd, &direction, sizeof(direction) - 1); ASSRT(s > 0);
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_direction: could not seek GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(direction, "out") == 0) {
|
char direction[4] = { 0 }; /* make sure read is null-terminated */
|
||||||
|
ssize_t s = read(fd, &direction, sizeof(direction) - 1); e_no = errno;
|
||||||
|
close(fd);
|
||||||
|
if (s < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_direction: could not read '%s' (%s)", filename, strerror(e_no));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(direction, "out") == 0)
|
||||||
*value = OUTPUT;
|
*value = OUTPUT;
|
||||||
} else {
|
else if (strcmp(direction, "in") == 0)
|
||||||
*value = INPUT;
|
*value = INPUT;
|
||||||
|
else {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_direction: unexpected '%s' found in %s", direction, filename);
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} /* gpio_set_direction */
|
||||||
|
|
||||||
int gpio_set_value(unsigned int gpio, unsigned int value)
|
|
||||||
|
int gpio_set_value(int gpio, unsigned int value)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd, e_no;
|
||||||
char filename[MAX_FILENAME];
|
char filename[MAX_FILENAME];
|
||||||
char vstr[16];
|
char vstr[16];
|
||||||
|
|
||||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
|
||||||
|
|
||||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_value: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
strncpy(vstr, "1", ARRAY_SIZE(vstr) - 1);
|
strncpy(vstr, "1", ARRAY_SIZE(vstr) - 1);
|
||||||
@ -289,53 +360,89 @@ int gpio_set_value(unsigned int gpio, unsigned int value)
|
|||||||
strncpy(vstr, "0", ARRAY_SIZE(vstr) - 1);
|
strncpy(vstr, "0", ARRAY_SIZE(vstr) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t s = write(fd, vstr, strlen(vstr));
|
ssize_t s = write(fd, vstr, strlen(vstr)); e_no = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (s != strlen(vstr))
|
if (s != strlen(vstr)) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_value: could not write '%s' to %s (%s)", vstr, filename, strerror(e_no));
|
||||||
|
add_error_msg(err);
|
||||||
return -2;
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_get_value(unsigned int gpio, unsigned int *value)
|
int gpio_get_value(int gpio, unsigned int *value)
|
||||||
{
|
{
|
||||||
int fd = fd_lookup(gpio);
|
int fd = fd_lookup(gpio);
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
if (!fd)
|
if (!fd)
|
||||||
{
|
{
|
||||||
if ((fd = open_value_file(gpio)) == -1)
|
if ((fd = open_value_file(gpio)) == -1) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_value: could not open GPIO %d value file", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lseek(fd, 0, SEEK_SET) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_value: could not seek GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ssize_t s = read(fd, &ch, sizeof(ch));
|
||||||
|
if (s < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_value: could not read GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
if (ch == '1') {
|
||||||
ssize_t s = read(fd, &ch, sizeof(ch)); ASSRT(s > 0);
|
|
||||||
|
|
||||||
if (ch != '0') {
|
|
||||||
*value = 1;
|
*value = 1;
|
||||||
} else {
|
} else if (ch == '0') {
|
||||||
*value = 0;
|
*value = 0;
|
||||||
|
} else {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_get_value: unrecognized read GPIO %d (%c)", gpio, ch);
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_set_edge(unsigned int gpio, unsigned int edge)
|
int gpio_set_edge(int gpio, unsigned int edge)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char filename[MAX_FILENAME];
|
char filename[MAX_FILENAME];
|
||||||
|
|
||||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); BUF2SMALL(filename);
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); BUF2SMALL(filename);
|
||||||
|
|
||||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_edge: could not open '%s' (%s)", filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t s = write(fd, stredge[edge], strlen(stredge[edge]) + 1); ASSRT(s == strlen(stredge[edge]) + 1);
|
ssize_t s = write(fd, stredge[edge], strlen(stredge[edge]) + 1);
|
||||||
|
if (s < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "gpio_set_edge: could not write '%s' to %s (%s)", stredge[edge], filename, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int gpio_lookup(int fd)
|
int gpio_lookup(int fd)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
while (f != NULL)
|
while (f != NULL)
|
||||||
@ -344,7 +451,8 @@ unsigned int gpio_lookup(int fd)
|
|||||||
return f->gpio;
|
return f->gpio;
|
||||||
f = f->next;
|
f = f->next;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exports_cleanup(void)
|
void exports_cleanup(void)
|
||||||
@ -354,14 +462,12 @@ void exports_cleanup(void)
|
|||||||
gpio_unexport(exported_gpios->gpio);
|
gpio_unexport(exported_gpios->gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
|
int add_edge_callback(int gpio, void (*func)(int gpio))
|
||||||
{
|
{
|
||||||
struct callback *cb = callbacks;
|
struct callback *cb = callbacks;
|
||||||
struct callback *new_cb;
|
struct callback *new_cb;
|
||||||
|
|
||||||
new_cb = malloc(sizeof(struct callback));
|
new_cb = malloc(sizeof(struct callback)); ASSRT(new_cb != NULL);
|
||||||
if (new_cb == 0)
|
|
||||||
return -1; // out of memory
|
|
||||||
|
|
||||||
new_cb->gpio = gpio;
|
new_cb->gpio = gpio;
|
||||||
new_cb->func = func;
|
new_cb->func = func;
|
||||||
@ -379,7 +485,7 @@ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_callbacks(unsigned int gpio)
|
void run_callbacks(int gpio)
|
||||||
{
|
{
|
||||||
struct callback *cb = callbacks;
|
struct callback *cb = callbacks;
|
||||||
while (cb != NULL)
|
while (cb != NULL)
|
||||||
@ -390,7 +496,7 @@ void run_callbacks(unsigned int gpio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_callbacks(unsigned int gpio)
|
void remove_callbacks(int gpio)
|
||||||
{
|
{
|
||||||
struct callback *cb = callbacks;
|
struct callback *cb = callbacks;
|
||||||
struct callback *temp;
|
struct callback *temp;
|
||||||
@ -414,7 +520,7 @@ void remove_callbacks(unsigned int gpio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_initial_false(unsigned int gpio)
|
void set_initial_false(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
|
|
||||||
@ -426,7 +532,7 @@ void set_initial_false(unsigned int gpio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_initial(unsigned int gpio)
|
int gpio_initial(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
|
|
||||||
@ -443,7 +549,7 @@ void *poll_thread(void *threadarg)
|
|||||||
{
|
{
|
||||||
struct epoll_event events;
|
struct epoll_event events;
|
||||||
char buf;
|
char buf;
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
thread_running = 1;
|
thread_running = 1;
|
||||||
@ -475,7 +581,7 @@ void *poll_thread(void *threadarg)
|
|||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_is_evented(unsigned int gpio)
|
int gpio_is_evented(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
while (f != NULL)
|
while (f != NULL)
|
||||||
@ -487,7 +593,7 @@ int gpio_is_evented(unsigned int gpio)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_event_add(unsigned int gpio)
|
int gpio_event_add(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
while (f != NULL)
|
while (f != NULL)
|
||||||
@ -505,7 +611,7 @@ int gpio_event_add(unsigned int gpio)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_event_remove(unsigned int gpio)
|
int gpio_event_remove(int gpio)
|
||||||
{
|
{
|
||||||
struct fdx *f = fd_list;
|
struct fdx *f = fd_list;
|
||||||
while (f != NULL)
|
while (f != NULL)
|
||||||
@ -521,7 +627,7 @@ int gpio_event_remove(unsigned int gpio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add_edge_detect assumes the caller has ensured the GPIO is already exported.
|
// add_edge_detect assumes the caller has ensured the GPIO is already exported.
|
||||||
int add_edge_detect(unsigned int gpio, unsigned int edge)
|
int add_edge_detect(int gpio, unsigned int edge)
|
||||||
// return values:
|
// return values:
|
||||||
// 0 - Success
|
// 0 - Success
|
||||||
// 1 - Edge detection already added
|
// 1 - Edge detection already added
|
||||||
@ -537,18 +643,34 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// export /sys/class/gpio interface
|
// export /sys/class/gpio interface
|
||||||
gpio_set_direction(gpio, 0); // 0=input
|
if (gpio_set_direction(gpio, 0) < 0) {
|
||||||
gpio_set_edge(gpio, edge);
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not set direction for GPIO %d", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (gpio_set_edge(gpio, edge) < 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not set edge for GPIO %d", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fd)
|
if (!fd)
|
||||||
{
|
{
|
||||||
if ((fd = open_value_file(gpio)) == -1) {
|
if ((fd = open_value_file(gpio)) == -1) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not open GPIO %d value file", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create epfd if not already open
|
// create epfd if not already open
|
||||||
if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) {
|
if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not epoll_create GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,6 +678,9 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
|
|||||||
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||||
ev.data.fd = fd;
|
ev.data.fd = fd;
|
||||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not epoll_ctl GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,14 +688,18 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
|
|||||||
if (!thread_running)
|
if (!thread_running)
|
||||||
{
|
{
|
||||||
if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) {
|
if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "add_edge_detect: could not pthread_create GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} /* add_edge_detect */
|
||||||
|
|
||||||
void remove_edge_detect(unsigned int gpio)
|
|
||||||
|
void remove_edge_detect(int gpio)
|
||||||
{
|
{
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
int fd = fd_lookup(gpio);
|
int fd = fd_lookup(gpio);
|
||||||
@ -591,7 +720,8 @@ void remove_edge_detect(unsigned int gpio)
|
|||||||
dyn_int_array_set(&event_occurred, gpio, 0, 0);
|
dyn_int_array_set(&event_occurred, gpio, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int event_detected(unsigned int gpio)
|
|
||||||
|
int event_detected(int gpio)
|
||||||
{
|
{
|
||||||
if (dyn_int_array_get(&event_occurred, gpio, 0)) {
|
if (dyn_int_array_get(&event_occurred, gpio, 0)) {
|
||||||
dyn_int_array_set(&event_occurred, gpio, 0, 0);
|
dyn_int_array_set(&event_occurred, gpio, 0, 0);
|
||||||
@ -608,7 +738,8 @@ void event_cleanup(void)
|
|||||||
exports_cleanup();
|
exports_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
|
// blocking_wait_for_edge assumes the caller has ensured the GPIO is already exported.
|
||||||
|
int blocking_wait_for_edge(int gpio, unsigned int edge)
|
||||||
// standalone from all the event functions above
|
// standalone from all the event functions above
|
||||||
{
|
{
|
||||||
int fd = fd_lookup(gpio);
|
int fd = fd_lookup(gpio);
|
||||||
@ -616,51 +747,79 @@ int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
|
|||||||
struct epoll_event events, ev;
|
struct epoll_event events, ev;
|
||||||
char buf;
|
char buf;
|
||||||
|
|
||||||
if ((epfd = epoll_create(1)) == -1)
|
if ((epfd = epoll_create(1)) == -1) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not epoll_create GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// check to see if this gpio has been added already, if not, mark as added
|
// check to see if this gpio has been added already, if not, mark as added
|
||||||
if (gpio_event_add(gpio) != 0)
|
if (gpio_event_add(gpio) != 0) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not add event for GPIO %d", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
return 2;
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
// export /sys/class/gpio interface
|
// export /sys/class/gpio interface
|
||||||
gpio_export(gpio); // ignore errors
|
|
||||||
gpio_set_direction(gpio, 0); // 0=input
|
gpio_set_direction(gpio, 0); // 0=input
|
||||||
gpio_set_edge(gpio, edge);
|
gpio_set_edge(gpio, edge);
|
||||||
|
|
||||||
if (!fd)
|
if (!fd)
|
||||||
{
|
{
|
||||||
if ((fd = open_value_file(gpio)) == -1)
|
if ((fd = open_value_file(gpio)) == -1) {
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not open GPIO %d value file", gpio);
|
||||||
|
add_error_msg(err);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add to epoll fd
|
// add to epoll fd
|
||||||
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||||
ev.data.fd = fd;
|
ev.data.fd = fd;
|
||||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||||
{
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not epoll_ctl GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
gpio_event_remove(gpio);
|
gpio_event_remove(gpio);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// epoll for event
|
// epoll for event
|
||||||
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
|
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
|
||||||
|
{
|
||||||
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
||||||
{
|
{
|
||||||
gpio_event_remove(gpio);
|
gpio_event_remove(gpio);
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
lseek(events.data.fd, 0, SEEK_SET);
|
if (lseek(events.data.fd, 0, SEEK_SET) < 0)
|
||||||
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not seek GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
if (read(events.data.fd, &buf, sizeof(buf)) != 1)
|
if (read(events.data.fd, &buf, sizeof(buf)) != 1)
|
||||||
{
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not read GPIO %d (%s)", gpio, strerror(errno));
|
||||||
|
add_error_msg(err);
|
||||||
gpio_event_remove(gpio);
|
gpio_event_remove(gpio);
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
if (events.data.fd != fd)
|
if (events.data.fd != fd)
|
||||||
{
|
{
|
||||||
|
char err[80];
|
||||||
|
snprintf(err, sizeof(err), "blocking_wait_for_edge: events.data.fd (%d) not equal to fd (%d) for GPIO %d", events.data.fd, fd, gpio);
|
||||||
|
add_error_msg(err);
|
||||||
gpio_event_remove(gpio);
|
gpio_event_remove(gpio);
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
|
@ -54,21 +54,21 @@ SOFTWARE.
|
|||||||
#define PUD_DOWN 1
|
#define PUD_DOWN 1
|
||||||
#define PUD_UP 2
|
#define PUD_UP 2
|
||||||
|
|
||||||
int gpio_export(unsigned int gpio);
|
int gpio_export(int gpio);
|
||||||
int gpio_unexport(unsigned int gpio);
|
int gpio_unexport(int gpio);
|
||||||
void exports_cleanup(void);
|
void exports_cleanup(void);
|
||||||
int gpio_set_direction(unsigned int gpio, unsigned int in_flag);
|
int gpio_set_direction(int gpio, unsigned int in_flag);
|
||||||
int gpio_get_direction(unsigned int gpio, unsigned int *value);
|
int gpio_get_direction(int gpio, unsigned int *value);
|
||||||
int gpio_set_value(unsigned int gpio, unsigned int value);
|
int gpio_set_value(int gpio, unsigned int value);
|
||||||
int gpio_get_value(unsigned int gpio, unsigned int *value);
|
int gpio_get_value(int gpio, unsigned int *value);
|
||||||
|
|
||||||
int add_edge_detect(unsigned int gpio, unsigned int edge);
|
int add_edge_detect(int gpio, unsigned int edge);
|
||||||
void remove_edge_detect(unsigned int gpio);
|
void remove_edge_detect(int gpio);
|
||||||
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio));
|
int add_edge_callback(int gpio, void (*func)(int gpio));
|
||||||
int event_detected(unsigned int gpio);
|
int event_detected(int gpio);
|
||||||
int gpio_event_add(unsigned int gpio);
|
int gpio_event_add(int gpio);
|
||||||
int gpio_event_remove(unsigned int gpio);
|
int gpio_event_remove(int gpio);
|
||||||
int gpio_is_evented(unsigned int gpio);
|
int gpio_is_evented(int gpio);
|
||||||
int event_initialise(void);
|
int event_initialise(void);
|
||||||
void event_cleanup(void);
|
void event_cleanup(void);
|
||||||
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge);
|
int blocking_wait_for_edge(int gpio, unsigned int edge);
|
||||||
|
217
source/py_gpio.c
217
source/py_gpio.c
@ -45,12 +45,12 @@ SOFTWARE.
|
|||||||
static int gpio_warnings = 1;
|
static int gpio_warnings = 1;
|
||||||
|
|
||||||
int max_gpio = -1;
|
int max_gpio = -1;
|
||||||
void *gpio_direction = NULL;
|
dyn_int_array_t *gpio_direction = NULL;
|
||||||
|
|
||||||
struct py_callback
|
struct py_callback
|
||||||
{
|
{
|
||||||
char channel[32];
|
char channel[32];
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
PyObject *py_cb;
|
PyObject *py_cb;
|
||||||
unsigned long long lastcall;
|
unsigned long long lastcall;
|
||||||
unsigned int bouncetime;
|
unsigned int bouncetime;
|
||||||
@ -74,6 +74,8 @@ static void remember_gpio_direction(int gpio, int direction)
|
|||||||
// python function cleanup()
|
// python function cleanup()
|
||||||
static PyObject *py_cleanup(PyObject *self, PyObject *args)
|
static PyObject *py_cleanup(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
// clean up any exports
|
// clean up any exports
|
||||||
event_cleanup();
|
event_cleanup();
|
||||||
|
|
||||||
@ -83,13 +85,15 @@ static PyObject *py_cleanup(PyObject *self, PyObject *args)
|
|||||||
// python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None)
|
// python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None)
|
||||||
static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs)
|
static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
int direction;
|
int direction;
|
||||||
int pud = PUD_OFF;
|
int pud = PUD_OFF;
|
||||||
int initial = 0;
|
int initial = 0;
|
||||||
static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL};
|
static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL};
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial))
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -113,39 +117,54 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio) < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid value for channel");
|
char err[2000];
|
||||||
|
snprintf(err, sizeof(err), "Invalid channel %s. (%s)", channel, get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_ValueError, err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = gpio_export(gpio);
|
if (gpio_export(gpio) < 0) {
|
||||||
if (result < 0) {
|
char err[2000];
|
||||||
PyErr_SetString(PyExc_ValueError, "Channel in use (already exported)");
|
snprintf(err, sizeof(err), "Error setting up channel %s, maybe already exported? (%s)", channel, get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (gpio_set_direction(gpio, direction) < 0) {
|
||||||
|
char err[2000];
|
||||||
|
snprintf(err, sizeof(err), "Error setting direction %d on channel %s. (%s)", direction, channel, get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
gpio_set_direction(gpio, direction);
|
|
||||||
// For some reason, the following code doesn't work for XIOs. Skip.
|
|
||||||
if (direction == OUTPUT) {
|
if (direction == OUTPUT) {
|
||||||
gpio_set_value(gpio, initial);
|
if (gpio_set_value(gpio, initial) < 0) {
|
||||||
|
char err[2000];
|
||||||
|
snprintf(err, sizeof(err), "Error setting initial value %d on channel %s. (%s)", initial, channel, get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remember_gpio_direction(gpio, direction);
|
remember_gpio_direction(gpio, direction);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
} /* py_setup_channel */
|
||||||
|
|
||||||
|
|
||||||
// python function output(channel, value)
|
// python function output(channel, value)
|
||||||
static PyObject *py_output_gpio(PyObject *self, PyObject *args)
|
static PyObject *py_output_gpio(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
int value;
|
int value;
|
||||||
char *channel;
|
char *channel;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "si", &channel, &value))
|
if (!PyArg_ParseTuple(args, "si", &channel, &value))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,26 +176,31 @@ static PyObject *py_output_gpio(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
int result = gpio_set_value(gpio, value);
|
int result = gpio_set_value(gpio, value);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Could not write to channel");
|
char err[2000];
|
||||||
|
snprintf(err, sizeof(err), "Could no write %d on channel %s. (%s)", value, channel, get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
} /* py_output_gpio */
|
||||||
|
|
||||||
|
|
||||||
// python function value = input(channel)
|
// python function value = input(channel)
|
||||||
static PyObject *py_input_gpio(PyObject *self, PyObject *args)
|
static PyObject *py_input_gpio(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
PyObject *py_value;
|
PyObject *py_value;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +218,7 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args)
|
|||||||
return py_value;
|
return py_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_py_callbacks(unsigned int gpio)
|
static void run_py_callbacks(int gpio)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
PyGILState_STATE gstate;
|
PyGILState_STATE gstate;
|
||||||
@ -202,6 +226,8 @@ static void run_py_callbacks(unsigned int gpio)
|
|||||||
struct timeval tv_timenow;
|
struct timeval tv_timenow;
|
||||||
unsigned long long timenow;
|
unsigned long long timenow;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
while (cb != NULL)
|
while (cb != NULL)
|
||||||
{
|
{
|
||||||
if (cb->gpio == gpio)
|
if (cb->gpio == gpio)
|
||||||
@ -231,11 +257,13 @@ static void run_py_callbacks(unsigned int gpio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_py_callback(char *channel, unsigned int gpio, unsigned int bouncetime, PyObject *cb_func)
|
static int add_py_callback(char *channel, int gpio, unsigned int bouncetime, PyObject *cb_func)
|
||||||
{
|
{
|
||||||
struct py_callback *new_py_cb;
|
struct py_callback *new_py_cb;
|
||||||
struct py_callback *cb = py_callbacks;
|
struct py_callback *cb = py_callbacks;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
// add callback to py_callbacks list
|
// add callback to py_callbacks list
|
||||||
new_py_cb = malloc(sizeof(struct py_callback));
|
new_py_cb = malloc(sizeof(struct py_callback));
|
||||||
if (new_py_cb == 0)
|
if (new_py_cb == 0)
|
||||||
@ -266,12 +294,14 @@ static int add_py_callback(char *channel, unsigned int gpio, unsigned int bounce
|
|||||||
// python function add_event_callback(gpio, callback, bouncetime=0)
|
// python function add_event_callback(gpio, callback, bouncetime=0)
|
||||||
static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs)
|
static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
unsigned int bouncetime = 0;
|
unsigned int bouncetime = 0;
|
||||||
PyObject *cb_func;
|
PyObject *cb_func;
|
||||||
char *kwlist[] = {"gpio", "callback", "bouncetime", NULL};
|
char *kwlist[] = {"gpio", "callback", "bouncetime", NULL};
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime))
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -282,7 +312,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +320,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
|
|||||||
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
||||||
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
||||||
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Callbacks currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
PyErr_SetString(PyExc_ValueError, "Callbacks currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,13 +345,15 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
|
|||||||
// python function add_event_detect(gpio, edge, callback=None, bouncetime=0
|
// python function add_event_detect(gpio, edge, callback=None, bouncetime=0
|
||||||
static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs)
|
static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
int edge, result;
|
int edge, result;
|
||||||
unsigned int bouncetime = 0;
|
unsigned int bouncetime = 0;
|
||||||
PyObject *cb_func = NULL;
|
PyObject *cb_func = NULL;
|
||||||
char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL};
|
char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL};
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime))
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -332,7 +364,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,14 +372,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
|
|||||||
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
||||||
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
||||||
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check channel is set up as an input
|
|
||||||
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +383,13 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check channel is set up as an input
|
||||||
|
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread
|
if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread
|
||||||
{
|
{
|
||||||
if (result == 1)
|
if (result == 1)
|
||||||
@ -380,17 +412,19 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
|
|||||||
// python function remove_event_detect(gpio)
|
// python function remove_event_detect(gpio)
|
||||||
static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
struct py_callback *cb = py_callbacks;
|
struct py_callback *cb = py_callbacks;
|
||||||
struct py_callback *temp;
|
struct py_callback *temp;
|
||||||
struct py_callback *prev = NULL;
|
struct py_callback *prev = NULL;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +432,7 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
|||||||
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
||||||
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
||||||
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,14 +463,16 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
|||||||
// python function value = event_detected(channel)
|
// python function value = event_detected(channel)
|
||||||
static PyObject *py_event_detected(PyObject *self, PyObject *args)
|
static PyObject *py_event_detected(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
char *channel;
|
char *channel;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,16 +485,18 @@ static PyObject *py_event_detected(PyObject *self, PyObject *args)
|
|||||||
// python function py_wait_for_edge(gpio, edge)
|
// python function py_wait_for_edge(gpio, edge)
|
||||||
static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
int edge, result;
|
int edge, result;
|
||||||
char *channel;
|
char *channel;
|
||||||
char error[81];
|
char error[81];
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "si", &channel, &edge))
|
if (!PyArg_ParseTuple(args, "si", &channel, &edge))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,14 +504,7 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
|||||||
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
if (gpio != lookup_gpio_by_name("AP-EINT3")
|
||||||
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
&& gpio != lookup_gpio_by_name("AP-EINT1")
|
||||||
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check channel is setup as an input
|
|
||||||
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,6 +515,13 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check channel is setup as an input
|
||||||
|
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS // disable GIL
|
Py_BEGIN_ALLOW_THREADS // disable GIL
|
||||||
result = blocking_wait_for_edge(gpio, edge);
|
result = blocking_wait_for_edge(gpio, edge);
|
||||||
Py_END_ALLOW_THREADS // enable GIL
|
Py_END_ALLOW_THREADS // enable GIL
|
||||||
@ -506,17 +544,18 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
|||||||
// python function value = gpio_function(gpio)
|
// python function value = gpio_function(gpio)
|
||||||
static PyObject *py_gpio_function(PyObject *self, PyObject *args)
|
static PyObject *py_gpio_function(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned int gpio;
|
int gpio;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
PyObject *func;
|
PyObject *func;
|
||||||
char *channel;
|
char *channel;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (get_gpio_number(channel, &gpio)) {
|
if (get_gpio_number(channel, &gpio)) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
|
PyErr_SetString(PyExc_ValueError, "Invalid channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,6 +573,8 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args)
|
|||||||
// python function setwarnings(state)
|
// python function setwarnings(state)
|
||||||
static PyObject *py_setwarnings(PyObject *self, PyObject *args)
|
static PyObject *py_setwarnings(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &gpio_warnings))
|
if (!PyArg_ParseTuple(args, "i", &gpio_warnings))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -552,56 +593,62 @@ static PyObject *py_gpio_base(PyObject *self, PyObject *args)
|
|||||||
unsigned int value;
|
unsigned int value;
|
||||||
PyObject *py_value;
|
PyObject *py_value;
|
||||||
|
|
||||||
value = get_xio_base();
|
clear_error_msg();
|
||||||
|
|
||||||
|
value = get_xio_base();
|
||||||
|
if (value <= 0) {
|
||||||
|
char err[1024];
|
||||||
|
snprintf(err, sizeof(err), "Could not get XIO base ('%s')", get_error_msg());
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
py_value = Py_BuildValue("i", value);
|
py_value = Py_BuildValue("i", value);
|
||||||
|
|
||||||
return py_value;
|
return py_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal unit tests
|
// Internal unit tests
|
||||||
extern int num_get_xio_base;
|
|
||||||
extern pins_t pins_info[];
|
extern pins_t pins_info[];
|
||||||
static PyObject *py_selftest(PyObject *self, PyObject *args)
|
static PyObject *py_selftest(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
int input;
|
int input;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &input))
|
if (!PyArg_ParseTuple(args, "i", &input))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
printf("Testing get_xio_base\n");
|
printf("Testing get_xio_base\n");
|
||||||
ASSRT(num_get_xio_base == 0);
|
int first_base = get_xio_base(); ASSRT(first_base > 0);
|
||||||
int base = get_xio_base(); ASSRT(base > 0 && base < 1024);
|
int second_base = get_xio_base(); ASSRT(second_base == first_base);
|
||||||
ASSRT(num_get_xio_base == 1);
|
printf("base=%d\n", first_base);
|
||||||
int second_base = get_xio_base(); ASSRT(second_base == base);
|
|
||||||
ASSRT(num_get_xio_base == 1); /* make sure it didn't do the full calc a second time. */
|
|
||||||
printf("base=%d\n", base);
|
|
||||||
|
|
||||||
printf("Testing lookup_gpio_by_key\n");
|
printf("Testing lookup_gpio_by_key\n");
|
||||||
ASSRT(0 == lookup_gpio_by_key("U13_1"));
|
ASSRT(-1 == lookup_gpio_by_key("U13_1"));
|
||||||
ASSRT(48 == lookup_gpio_by_key("U13_9"));
|
ASSRT(48 == lookup_gpio_by_key("U13_9"));
|
||||||
ASSRT(47 == lookup_gpio_by_key("U13_11"));
|
ASSRT(47 == lookup_gpio_by_key("U13_11"));
|
||||||
ASSRT(base == lookup_gpio_by_key("U14_13"));
|
ASSRT(first_base == lookup_gpio_by_key("U14_13"));
|
||||||
ASSRT((base+1) == lookup_gpio_by_key("U14_14"));
|
ASSRT((first_base+1) == lookup_gpio_by_key("U14_14"));
|
||||||
ASSRT((base+6) == lookup_gpio_by_key("U14_19"));
|
ASSRT((first_base+6) == lookup_gpio_by_key("U14_19"));
|
||||||
ASSRT((base+7) == lookup_gpio_by_key("U14_20"));
|
ASSRT((first_base+7) == lookup_gpio_by_key("U14_20"));
|
||||||
ASSRT(193 == lookup_gpio_by_key("U14_23"));
|
ASSRT(193 == lookup_gpio_by_key("U14_23"));
|
||||||
ASSRT(139 == lookup_gpio_by_key("U14_38"));
|
ASSRT(139 == lookup_gpio_by_key("U14_38"));
|
||||||
ASSRT(0 == lookup_gpio_by_key("U14_40"));
|
ASSRT(-1 == lookup_gpio_by_key("U14_40"));
|
||||||
ASSRT(0 == lookup_gpio_by_key("NOTFOUND"));
|
ASSRT(-1 == lookup_gpio_by_key("NOTFOUND"));
|
||||||
ASSRT(0 == lookup_gpio_by_key("U14_"));
|
ASSRT(-1 == lookup_gpio_by_key("U14_"));
|
||||||
ASSRT(0 == lookup_gpio_by_key("U14_4000"));
|
ASSRT(-1 == lookup_gpio_by_key("U14_4000"));
|
||||||
|
|
||||||
printf("Testing lookup_gpio_by_name\n");
|
printf("Testing lookup_gpio_by_name\n");
|
||||||
ASSRT(0 == lookup_gpio_by_name("GND"));
|
ASSRT(-1 == lookup_gpio_by_name("GND"));
|
||||||
ASSRT(48 == lookup_gpio_by_name("TWI1-SDA"));
|
ASSRT(48 == lookup_gpio_by_name("TWI1-SDA"));
|
||||||
ASSRT(47 == lookup_gpio_by_name("TWI1-SCK"));
|
ASSRT(47 == lookup_gpio_by_name("TWI1-SCK"));
|
||||||
ASSRT(base == lookup_gpio_by_name("XIO-P0"));
|
ASSRT(first_base == lookup_gpio_by_name("XIO-P0"));
|
||||||
ASSRT((base+6) == lookup_gpio_by_name("XIO-P6"));
|
ASSRT((first_base+6) == lookup_gpio_by_name("XIO-P6"));
|
||||||
ASSRT((base+7) == lookup_gpio_by_name("XIO-P7"));
|
ASSRT((first_base+7) == lookup_gpio_by_name("XIO-P7"));
|
||||||
ASSRT(139 == lookup_gpio_by_name("CSID7"));
|
ASSRT(139 == lookup_gpio_by_name("CSID7"));
|
||||||
ASSRT(0 == lookup_gpio_by_name("NOTFOUND"));
|
ASSRT(-1 == lookup_gpio_by_name("NOTFOUND"));
|
||||||
ASSRT(0 == lookup_gpio_by_name("CSID"));
|
ASSRT(-1 == lookup_gpio_by_name("CSID"));
|
||||||
ASSRT(0 == lookup_gpio_by_name("CSID777"));
|
ASSRT(-1 == lookup_gpio_by_name("CSID777"));
|
||||||
|
|
||||||
printf("Testing lookup_ain_by_key\n");
|
printf("Testing lookup_ain_by_key\n");
|
||||||
ASSRT(-1 == lookup_ain_by_key("U14_1"));
|
ASSRT(-1 == lookup_ain_by_key("U14_1"));
|
||||||
@ -661,6 +708,26 @@ static PyObject *py_selftest(PyObject *self, PyObject *args)
|
|||||||
ASSRT(2 == get_spi_bus_path_number(0)); /* doesn't really work on CHIP */
|
ASSRT(2 == get_spi_bus_path_number(0)); /* doesn't really work on CHIP */
|
||||||
ASSRT(2 == get_spi_bus_path_number(1)); /* doesn't really work on CHIP */
|
ASSRT(2 == get_spi_bus_path_number(1)); /* doesn't really work on CHIP */
|
||||||
|
|
||||||
|
printf("Testing error message buffer\n");
|
||||||
|
clear_error_msg();
|
||||||
|
ASSRT(0 == strlen(get_error_msg()));
|
||||||
|
char *s100 = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
add_error_msg(s100); ASSRT(100 == strlen(get_error_msg()));
|
||||||
|
// Subsequent messages added include a newline separator.
|
||||||
|
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(403 == strlen(get_error_msg()));
|
||||||
|
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(706 == strlen(get_error_msg()));
|
||||||
|
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(1009 == strlen(get_error_msg()));
|
||||||
|
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(1023 == strlen(get_error_msg()));
|
||||||
|
|
||||||
|
printf("Testing dynamic integer array\n");
|
||||||
|
dyn_int_array_t *my_array = NULL;
|
||||||
|
ASSRT(-2 == dyn_int_array_get(&my_array, 29, -2)); ASSRT(my_array->num_elements == 45);
|
||||||
|
dyn_int_array_set(&my_array, 44, 3, -2); ASSRT(my_array->num_elements == 45);
|
||||||
|
ASSRT(3 == dyn_int_array_get(&my_array, 44, -2)); ASSRT(my_array->num_elements == 45);
|
||||||
|
dyn_int_array_set(&my_array, 45, 6, -2); ASSRT(my_array->num_elements == 69);
|
||||||
|
ASSRT(6 == dyn_int_array_get(&my_array, 45, -2)); ASSRT(my_array->num_elements == 69);
|
||||||
|
dyn_int_array_delete(&my_array);
|
||||||
|
|
||||||
int value = input;
|
int value = input;
|
||||||
|
|
||||||
PyObject *py_value = Py_BuildValue("i", value);
|
PyObject *py_value = Py_BuildValue("i", value);
|
||||||
@ -704,6 +771,8 @@ PyMODINIT_FUNC initGPIO(void)
|
|||||||
{
|
{
|
||||||
PyObject *module = NULL;
|
PyObject *module = NULL;
|
||||||
|
|
||||||
|
clear_error_msg();
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION > 2
|
#if PY_MAJOR_VERSION > 2
|
||||||
if ((module = PyModule_Create(&rpigpiomodule)) == NULL)
|
if ((module = PyModule_Create(&rpigpiomodule)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
96
test/.ropeproject/config.py
Normal file
96
test/.ropeproject/config.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# The default ``config.py``
|
||||||
|
|
||||||
|
|
||||||
|
def set_prefs(prefs):
|
||||||
|
"""This function is called before opening the project"""
|
||||||
|
|
||||||
|
# Specify which files and folders to ignore in the project.
|
||||||
|
# Changes to ignored resources are not added to the history and
|
||||||
|
# VCSs. Also they are not returned in `Project.get_files()`.
|
||||||
|
# Note that ``?`` and ``*`` match all characters but slashes.
|
||||||
|
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
|
||||||
|
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
|
||||||
|
# '.svn': matches 'pkg/.svn' and all of its children
|
||||||
|
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
|
||||||
|
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
|
||||||
|
prefs['ignored_resources'] = [
|
||||||
|
'*.pyc', '*~', '.ropeproject', '.hg', '.svn', '_svn', '.git',
|
||||||
|
'.tox', '.env', 'node_modules', 'bower_components']
|
||||||
|
|
||||||
|
# Specifies which files should be considered python files. It is
|
||||||
|
# useful when you have scripts inside your project. Only files
|
||||||
|
# ending with ``.py`` are considered to be python files by
|
||||||
|
# default.
|
||||||
|
#prefs['python_files'] = ['*.py']
|
||||||
|
|
||||||
|
# Custom source folders: By default rope searches the project
|
||||||
|
# for finding source folders (folders that should be searched
|
||||||
|
# for finding modules). You can add paths to that list. Note
|
||||||
|
# that rope guesses project source folders correctly most of the
|
||||||
|
# time; use this if you have any problems.
|
||||||
|
# The folders should be relative to project root and use '/' for
|
||||||
|
# separating folders regardless of the platform rope is running on.
|
||||||
|
# 'src/my_source_folder' for instance.
|
||||||
|
#prefs.add('source_folders', 'src')
|
||||||
|
|
||||||
|
# You can extend python path for looking up modules
|
||||||
|
#prefs.add('python_path', '~/python/')
|
||||||
|
|
||||||
|
# Should rope save object information or not.
|
||||||
|
prefs['save_objectdb'] = True
|
||||||
|
prefs['compress_objectdb'] = False
|
||||||
|
|
||||||
|
# If `True`, rope analyzes each module when it is being saved.
|
||||||
|
prefs['automatic_soa'] = True
|
||||||
|
# The depth of calls to follow in static object analysis
|
||||||
|
prefs['soa_followed_calls'] = 0
|
||||||
|
|
||||||
|
# If `False` when running modules or unit tests "dynamic object
|
||||||
|
# analysis" is turned off. This makes them much faster.
|
||||||
|
prefs['perform_doa'] = True
|
||||||
|
|
||||||
|
# Rope can check the validity of its object DB when running.
|
||||||
|
prefs['validate_objectdb'] = True
|
||||||
|
|
||||||
|
# How many undos to hold?
|
||||||
|
prefs['max_history_items'] = 32
|
||||||
|
|
||||||
|
# Shows whether to save history across sessions.
|
||||||
|
prefs['save_history'] = True
|
||||||
|
prefs['compress_history'] = False
|
||||||
|
|
||||||
|
# Set the number spaces used for indenting. According to
|
||||||
|
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
|
||||||
|
# unit-tests use 4 spaces it is more reliable, too.
|
||||||
|
prefs['indent_size'] = 4
|
||||||
|
|
||||||
|
# Builtin and c-extension modules that are allowed to be imported
|
||||||
|
# and inspected by rope.
|
||||||
|
prefs['extension_modules'] = []
|
||||||
|
|
||||||
|
# Add all standard c-extensions to extension_modules list.
|
||||||
|
prefs['import_dynload_stdmods'] = True
|
||||||
|
|
||||||
|
# If `True` modules with syntax errors are considered to be empty.
|
||||||
|
# The default value is `False`; When `False` syntax errors raise
|
||||||
|
# `rope.base.exceptions.ModuleSyntaxError` exception.
|
||||||
|
prefs['ignore_syntax_errors'] = False
|
||||||
|
|
||||||
|
# If `True`, rope ignores unresolvable imports. Otherwise, they
|
||||||
|
# appear in the importing namespace.
|
||||||
|
prefs['ignore_bad_imports'] = False
|
||||||
|
|
||||||
|
# If `True`, rope will transform a comma list of imports into
|
||||||
|
# multiple separate import statements when organizing
|
||||||
|
# imports.
|
||||||
|
prefs['split_imports'] = False
|
||||||
|
|
||||||
|
# If `True`, rope will sort imports alphabetically by module name
|
||||||
|
# instead of alphabetically by import statement, with from imports
|
||||||
|
# after normal imports.
|
||||||
|
prefs['sort_imports_alphabetically'] = False
|
||||||
|
|
||||||
|
|
||||||
|
def project_opened(project):
|
||||||
|
"""This function is called after opening the project"""
|
||||||
|
# Do whatever you like here!
|
2
test/.ropeproject/globalnames
Normal file
2
test/.ropeproject/globalnames
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<EFBFBD>}q(Utest_softpwm_setup]q(Uteardown_moduleqUTestSoftpwmSetupqeUtest_gpio_output]q(hUTestGPIOOutputqeUtest_pwm_setup]q(hUTestPwmSetupqeUtest_gpio_setup]q (hU TestSetupq
|
||||||
|
eUtest_gpio_input]q(hU
|
1
test/.ropeproject/history
Normal file
1
test/.ropeproject/history
Normal file
@ -0,0 +1 @@
|
|||||||
|
<EFBFBD>]q(]q]qe.
|
1
test/.ropeproject/objectdb
Normal file
1
test/.ropeproject/objectdb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<EFBFBD>}q.
|
@ -42,7 +42,7 @@ if (GPIO.input("XIO-P0") != GPIO.HIGH):
|
|||||||
num_errs += 1
|
num_errs += 1
|
||||||
GPIO.cleanup()
|
GPIO.cleanup()
|
||||||
|
|
||||||
GPIO.setup("XIO-P0", GPIO.IN)
|
GPIO.setup("U14_13", GPIO.IN) # XIO-P0
|
||||||
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW)
|
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW)
|
||||||
if (GPIO.input("XIO-P0") != GPIO.LOW):
|
if (GPIO.input("XIO-P0") != GPIO.LOW):
|
||||||
print "A low output on CSI0 does not lead to a low input on XIO-P0."
|
print "A low output on CSI0 does not lead to a low input on XIO-P0."
|
||||||
@ -51,7 +51,7 @@ if (GPIO.input("XIO-P0") != GPIO.LOW):
|
|||||||
GPIO.cleanup()
|
GPIO.cleanup()
|
||||||
|
|
||||||
GPIO.setup("XIO-P0", GPIO.IN)
|
GPIO.setup("XIO-P0", GPIO.IN)
|
||||||
GPIO.setup("CSID0", GPIO.OUT)
|
GPIO.setup("U14_31", GPIO.OUT) # CSID0
|
||||||
|
|
||||||
# VERIFY SIMPLE FUNCTIONALITY
|
# VERIFY SIMPLE FUNCTIONALITY
|
||||||
print "VERIFY SIMPLE FUNCTIONALITY"
|
print "VERIFY SIMPLE FUNCTIONALITY"
|
||||||
@ -66,7 +66,7 @@ assert(GPIO.input("XIO-P0") == GPIO.LOW)
|
|||||||
|
|
||||||
# ==============================================
|
# ==============================================
|
||||||
# EDGE DETECTION - AP-EINT1
|
# EDGE DETECTION - AP-EINT1
|
||||||
print "SETTING UP EDGE DETECTION ON AP-EINT1"
|
print "SETTING UP RISING EDGE DETECTION ON AP-EINT1"
|
||||||
GPIO.setup("AP-EINT1", GPIO.IN)
|
GPIO.setup("AP-EINT1", GPIO.IN)
|
||||||
print "adding event detect"
|
print "adding event detect"
|
||||||
GPIO.add_event_detect("AP-EINT1", GPIO.RISING)
|
GPIO.add_event_detect("AP-EINT1", GPIO.RISING)
|
||||||
@ -75,13 +75,12 @@ print "VERIFYING EDGE DETECT"
|
|||||||
f = open("/sys/class/gpio/gpio193/edge", "r")
|
f = open("/sys/class/gpio/gpio193/edge", "r")
|
||||||
edge = f.read()
|
edge = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
print "edge='", edge, "'"
|
|
||||||
assert(edge == "rising\n")
|
assert(edge == "rising\n")
|
||||||
GPIO.remove_event_detect("AP-EINT1")
|
GPIO.remove_event_detect("AP-EINT1")
|
||||||
|
|
||||||
# ==============================================
|
# ==============================================
|
||||||
# EDGE DETECTION - AP-EINT3
|
# EDGE DETECTION - AP-EINT3
|
||||||
print "SETTING UP EDGE DETECTION ON AP-EINT3"
|
print "SETTING UP BOTH EDGE DETECTION ON AP-EINT3"
|
||||||
GPIO.setup("AP-EINT3", GPIO.IN)
|
GPIO.setup("AP-EINT3", GPIO.IN)
|
||||||
GPIO.add_event_detect("AP-EINT3", GPIO.BOTH)
|
GPIO.add_event_detect("AP-EINT3", GPIO.BOTH)
|
||||||
|
|
||||||
@ -89,13 +88,12 @@ print "VERIFYING EDGE DETECT"
|
|||||||
f = open("/sys/class/gpio/gpio35/edge", "r")
|
f = open("/sys/class/gpio/gpio35/edge", "r")
|
||||||
edge = f.read()
|
edge = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
print "EDGE: %s" % edge
|
|
||||||
assert(edge == "both\n")
|
assert(edge == "both\n")
|
||||||
GPIO.remove_event_detect("AP-EINT3")
|
GPIO.remove_event_detect("AP-EINT3")
|
||||||
|
|
||||||
# ==============================================
|
# ==============================================
|
||||||
# EDGE DETECTION - EXPANDED GPIO
|
# EDGE DETECTION - EXPANDED GPIO
|
||||||
print "SETTING UP EDGE DETECTION ON XIO-P0"
|
print "SETTING UP FALLING EDGE DETECTION ON XIO-P0"
|
||||||
GPIO.add_event_detect("XIO-P0", GPIO.FALLING, myfuncallback)
|
GPIO.add_event_detect("XIO-P0", GPIO.FALLING, myfuncallback)
|
||||||
|
|
||||||
print "VERIFYING EDGE DETECT"
|
print "VERIFYING EDGE DETECT"
|
||||||
@ -104,7 +102,6 @@ gfile = "/sys/class/gpio/gpio%d/edge" % base
|
|||||||
f = open(gfile, "r")
|
f = open(gfile, "r")
|
||||||
edge = f.read()
|
edge = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
print "EDGE: %s" % edge
|
|
||||||
assert(edge == "falling\n")
|
assert(edge == "falling\n")
|
||||||
|
|
||||||
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
|
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
|
||||||
@ -134,14 +131,60 @@ GPIO.setup("CSID1", GPIO.IN)
|
|||||||
try:
|
try:
|
||||||
GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback)
|
GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback)
|
||||||
print "Oops, it did not throw an exception! BUG!!!"
|
print "Oops, it did not throw an exception! BUG!!!"
|
||||||
except:
|
num_errors += 1
|
||||||
|
except ValueError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
except RuntimeError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
|
||||||
|
print "TESTING ERRORS THROWN WHEN SETTING UP AN ALREADY EXPORTED GPIO"
|
||||||
|
try:
|
||||||
|
GPIO.output("XIO-P0", GPIO.LOW)
|
||||||
|
print "Oops, it did not throw an exception! BUG!!!"
|
||||||
|
num_errors += 1
|
||||||
|
except ValueError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
except RuntimeError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
pass
|
pass
|
||||||
|
|
||||||
print "TESTING ERRORS THROWN WHEN WRITING TO A GPIO WITH NO DIRECTION"
|
print "TESTING ERRORS THROWN WHEN WRITING TO A GPIO WITH NO DIRECTION"
|
||||||
try:
|
try:
|
||||||
GPIO.output("CSID1", GPIO.LOW)
|
GPIO.output("CSID1", GPIO.LOW)
|
||||||
print "Oops, it did not throw an exception! BUG!!!"
|
print "Oops, it did not throw an exception! BUG!!!"
|
||||||
except:
|
num_errors += 1
|
||||||
|
except ValueError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
except RuntimeError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
|
||||||
|
print "TESTING ERRORS THROWN FOR ILLEGAL GPIO"
|
||||||
|
try:
|
||||||
|
GPIO.setup("NOTUSED", GPIO.IN)
|
||||||
|
print "Oops, it did not throw an exception! BUG!!!"
|
||||||
|
num_errors += 1
|
||||||
|
except ValueError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
except RuntimeError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
|
||||||
|
print "TESTING ERRORS THROWN FOR NON-GPIO"
|
||||||
|
try:
|
||||||
|
GPIO.setup("FEL", GPIO.IN)
|
||||||
|
print "Oops, it did not throw an exception! BUG!!!"
|
||||||
|
num_errors += 1
|
||||||
|
except ValueError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
|
pass
|
||||||
|
except RuntimeError, ex:
|
||||||
|
print "error msg=", ex.args[0]
|
||||||
pass
|
pass
|
||||||
|
|
||||||
print "CLEANUP"
|
print "CLEANUP"
|
||||||
|
Reference in New Issue
Block a user