mirror of
https://github.com/xtacocorex/CHIP_IO
synced 2025-07-20 04:43:21 +00:00
Initial commit, working GPIO for all available CHIP GPIO pins, have not tested edge detection and callbacks
This commit is contained in:
309
source/common.c
Normal file
309
source/common.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include "common.h"
|
||||
|
||||
int setup_error = 0;
|
||||
int module_setup = 0;
|
||||
|
||||
typedef struct pins_t {
|
||||
const char *name;
|
||||
const char *key;
|
||||
int gpio;
|
||||
int pwm_mux_mode;
|
||||
int ain;
|
||||
} pins_t;
|
||||
|
||||
// I have no idea if this table is correct, we shall see - Robert Wolterman
|
||||
pins_t table[] = {
|
||||
{ "GND", "U13_1", 0, -1, -1},
|
||||
{ "CHG-IN", "U13_2", 0, -1, -1},
|
||||
{ "VCC-5V", "U13_3", 0, -1, -1},
|
||||
{ "GND", "U13_4", 0, -1, -1},
|
||||
{ "VCC-3V3", "U13_5", 0, -1, -1},
|
||||
{ "TS", "U13_6", 0, -1, -1},
|
||||
{ "VCC-1V8", "U13_7", 0, -1, -1},
|
||||
{ "BAT", "U13_8", 0, -1, -1},
|
||||
{ "TWI1-SDA", "U13_9", 48, -1, -1},
|
||||
{ "PWRON", "U13_10", 0, -1, -1},
|
||||
{ "TWI1-SCK", "U13_11", 47, -1, -1},
|
||||
{ "GND", "U13_12", 0, -1, -1},
|
||||
{ "X1", "U13_13", 0, -1, -1},
|
||||
{ "X2", "U13_14", 0, -1, -1},
|
||||
{ "Y1", "U13_15", 0, -1, -1},
|
||||
{ "Y2", "U13_16", 0, -1, -1},
|
||||
{ "LCD-D2", "U13_17", 98, -1, -1},
|
||||
{ "PWM0", "U13_18", 34, -1, -1},
|
||||
{ "LCD-D4", "U13_19", 100, -1, -1},
|
||||
{ "LCD-D3", "U13_20", 99, -1, -1},
|
||||
{ "LCD-D6", "U13_21", 102, -1, -1},
|
||||
{ "LCD-D5", "U13_22", 101, -1, -1},
|
||||
{ "LCD-D10", "U13_23", 106, -1, -1},
|
||||
{ "LCD-D7", "U13_24", 103, -1, -1},
|
||||
{ "LCD-D12", "U13_25", 108, -1, -1},
|
||||
{ "LCD-D11", "U13_26", 107, -1, -1},
|
||||
{ "LCD-D14", "U13_27", 110, -1, -1},
|
||||
{ "LCD-D13", "U13_28", 109, -1, -1},
|
||||
{ "LCD-D18", "U13_29", 114, -1, -1},
|
||||
{ "LCD-D15", "U13_30", 111, -1, -1},
|
||||
{ "LCD-D20", "U13_31", 116, -1, -1},
|
||||
{ "LCD-D19", "U13_32", 115, -1, -1},
|
||||
{ "LCD-D22", "U13_33", 118, -1, -1},
|
||||
{ "LCD-D21", "U13_34", 117, -1, -1},
|
||||
{ "LCD-CLK", "U13_35", 120, -1, -1},
|
||||
{ "LCD-D23", "U13_36", 119, -1, -1},
|
||||
{ "LCD-VSYNC", "U13_37", 123, -1, -1},
|
||||
{ "LCD-HSYNC", "U13_38", 122, -1, -1},
|
||||
{ "GND", "U13_39", 0, -1, -1},
|
||||
{ "LCD-DE", "U13_40", 121, -1, -1},
|
||||
{ "GND", "U14_1", 0, -1, -1},
|
||||
{ "VCC-5V", "U14_2", 0, -1, -1},
|
||||
{ "UART1-TX", "U14_3", 195, -1, -1},
|
||||
{ "HPL", "U14_4", 0, -1, -1},
|
||||
{ "UART1-RX", "U14_5", 196, -1, -1},
|
||||
{ "HPCOM", "U14_6", 0, -1, -1},
|
||||
{ "FEL", "U14_7", 0, -1, -1},
|
||||
{ "HPR", "U14_8", 0, -1, -1},
|
||||
{ "VCC-3V3", "U14_9", 0, -1, -1},
|
||||
{ "MICM", "U14_10", 0, -1, -1},
|
||||
{ "LRADC", "U14_11", 0, -1, -1},
|
||||
{ "MICIN1", "U14_12", 0, -1, -1},
|
||||
{ "XIO-P0", "U14_13", 408, -1, -1},
|
||||
{ "XIO-P1", "U14_14", 409, -1, -1},
|
||||
{ "XIO-P2", "U14_15", 410, -1, -1},
|
||||
{ "XIO-P3", "U14_16", 411, -1, -1},
|
||||
{ "XIO-P4", "U14_17", 412, -1, -1},
|
||||
{ "XIO-P5", "U14_18", 413, -1, -1},
|
||||
{ "XIO-P6", "U14_19", 414, -1, -1},
|
||||
{ "XIO-P7", "U14_20", 415, -1, -1},
|
||||
{ "GND", "U14_21", 0, -1, -1},
|
||||
{ "GND", "U14_22", 0, -1, -1},
|
||||
{ "AP-EINT1", "U14_23", 193, -1, -1},
|
||||
{ "AP-EINT3", "U14_24", 35, -1, -1},
|
||||
{ "TWI2-SDA", "U14_25", 50, -1, -1},
|
||||
{ "TWI2-SCK", "U14_26", 49, -1, -1},
|
||||
{ "CSIPCK", "U14_27", 128, -1, -1},
|
||||
{ "CSICK", "U14_28", 129, 4, -1},
|
||||
{ "CSIHSYNC", "U14_29", 130, 1, -1},
|
||||
{ "CSIVSYNC", "U14_30", 131, -1, -1},
|
||||
{ "CSID0", "U14_31", 132, 1, -1},
|
||||
{ "CSID1", "U14_32", 133, -1, -1},
|
||||
{ "CSID2", "U14_33", 134, -1, 4},
|
||||
{ "CSID3", "U14_34", 135, -1, -1},
|
||||
{ "CSID4", "U14_35", 136, -1, 6},
|
||||
{ "CSID5", "U14_36", 137, -1, 5},
|
||||
{ "CSID6", "U14_37", 138, -1, 2},
|
||||
{ "CSID7", "U14_38", 139, -1, 3},
|
||||
{ "GND", "U14_39", 0, -1, 0},
|
||||
{ "GND", "U14_40", 0, -1, 1},
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
int lookup_gpio_by_key(const char *key)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->key != NULL; ++p) {
|
||||
if (strcmp(p->key, key) == 0) {
|
||||
return p->gpio;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_gpio_by_name(const char *name)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->name != NULL; ++p) {
|
||||
if (strcmp(p->name, name) == 0) {
|
||||
return p->gpio;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_ain_by_key(const char *key)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->key != NULL; ++p) {
|
||||
if (strcmp(p->key, key) == 0) {
|
||||
if (p->ain == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
return p->ain;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lookup_ain_by_name(const char *name)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->name != NULL; ++p) {
|
||||
if (strcmp(p->name, name) == 0) {
|
||||
if (p->ain == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
return p->ain;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int copy_pwm_key_by_key(const char *input_key, char *key)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->key != NULL; ++p) {
|
||||
if (strcmp(p->key, input_key) == 0) {
|
||||
//validate it's a valid pwm pin
|
||||
if (p->pwm_mux_mode == -1)
|
||||
return 0;
|
||||
|
||||
strncpy(key, p->key, 7);
|
||||
key[7] = '\0';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_pwm_key_by_name(const char *name, char *key)
|
||||
{
|
||||
pins_t *p;
|
||||
for (p = table; p->name != NULL; ++p) {
|
||||
if (strcmp(p->name, name) == 0) {
|
||||
//validate it's a valid pwm pin
|
||||
if (p->pwm_mux_mode == -1)
|
||||
return 0;
|
||||
|
||||
strncpy(key, p->key, 7);
|
||||
key[7] = '\0';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_gpio_number(const char *key, unsigned int *gpio)
|
||||
{
|
||||
*gpio = lookup_gpio_by_key(key);
|
||||
|
||||
if (!*gpio) {
|
||||
*gpio = lookup_gpio_by_name(key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_pwm_key(const char *input, char *key)
|
||||
{
|
||||
if (!copy_pwm_key_by_key(input, key)) {
|
||||
return get_pwm_key_by_name(input, key);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_adc_ain(const char *key, unsigned int *ain)
|
||||
{
|
||||
*ain = lookup_ain_by_key(key);
|
||||
|
||||
if (*ain == -1) {
|
||||
*ain = lookup_ain_by_name(key);
|
||||
|
||||
if (*ain == -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
|
||||
dp = opendir (partial_path);
|
||||
if (dp != NULL) {
|
||||
while ((ep = readdir (dp))) {
|
||||
// Enforce that the prefix must be the first part of the file
|
||||
char* found_string = strstr(ep->d_name, prefix);
|
||||
|
||||
if (found_string != NULL && (ep->d_name - found_string) == 0) {
|
||||
snprintf(full_path, full_path_len, "%s/%s", partial_path, ep->d_name);
|
||||
(void) closedir (dp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
(void) closedir (dp);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_spi_bus_path_number(unsigned int spi)
|
||||
{
|
||||
char path[50];
|
||||
|
||||
build_path("/sys/devices", "ocp", ocp_dir, sizeof(ocp_dir));
|
||||
|
||||
if (spi == 0) {
|
||||
snprintf(path, sizeof(path), "%s/48030000.spi/spi_master/spi1", ocp_dir);
|
||||
} else {
|
||||
snprintf(path, sizeof(path), "%s/481a0000.spi/spi_master/spi1", ocp_dir);
|
||||
}
|
||||
|
||||
DIR* dir = opendir(path);
|
||||
if (dir) {
|
||||
closedir(dir);
|
||||
//device is using /dev/spidev1.x
|
||||
return 1;
|
||||
} else if (ENOENT == errno) {
|
||||
//device is using /dev/spidev2.x
|
||||
return 2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
59
source/common.h
Normal file
59
source/common.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#define MODE_UNKNOWN -1
|
||||
#define BOARD 10
|
||||
#define BCM 11
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
#define FILENAME_BUFFER_SIZE 128
|
||||
|
||||
int gpio_mode;
|
||||
int gpio_direction[120];
|
||||
|
||||
char ctrl_dir[35];
|
||||
char ocp_dir[25];
|
||||
|
||||
int get_gpio_number(const char *key, unsigned int *gpio);
|
||||
int get_pwm_key(const char *input, char *key);
|
||||
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 get_spi_bus_path_number(unsigned int spi);
|
||||
int setup_error;
|
||||
int module_setup;
|
81
source/constants.c
Normal file
81
source/constants.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "constants.h"
|
||||
#include "event_gpio.h"
|
||||
#include "common.h"
|
||||
|
||||
void define_constants(PyObject *module)
|
||||
{
|
||||
high = Py_BuildValue("i", HIGH);
|
||||
PyModule_AddObject(module, "HIGH", high);
|
||||
|
||||
low = Py_BuildValue("i", LOW);
|
||||
PyModule_AddObject(module, "LOW", low);
|
||||
|
||||
output = Py_BuildValue("i", OUTPUT);
|
||||
PyModule_AddObject(module, "OUT", output);
|
||||
|
||||
input = Py_BuildValue("i", INPUT);
|
||||
PyModule_AddObject(module, "IN", input);
|
||||
|
||||
alt0 = Py_BuildValue("i", ALT0);
|
||||
PyModule_AddObject(module, "ALT0", alt0);
|
||||
|
||||
pud_off = Py_BuildValue("i", PUD_OFF);
|
||||
PyModule_AddObject(module, "PUD_OFF", pud_off);
|
||||
|
||||
pud_up = Py_BuildValue("i", PUD_UP);
|
||||
PyModule_AddObject(module, "PUD_UP", pud_up);
|
||||
|
||||
pud_down = Py_BuildValue("i", PUD_DOWN);
|
||||
PyModule_AddObject(module, "PUD_DOWN", pud_down);
|
||||
|
||||
rising_edge = Py_BuildValue("i", RISING_EDGE);
|
||||
PyModule_AddObject(module, "RISING", rising_edge);
|
||||
|
||||
falling_edge = Py_BuildValue("i", FALLING_EDGE);
|
||||
PyModule_AddObject(module, "FALLING", falling_edge);
|
||||
|
||||
both_edge = Py_BuildValue("i", BOTH_EDGE);
|
||||
PyModule_AddObject(module, "BOTH", both_edge);
|
||||
|
||||
version = Py_BuildValue("s", "0.0.4");
|
||||
PyModule_AddObject(module, "VERSION", version);
|
||||
}
|
14
source/constants.h
Normal file
14
source/constants.h
Normal file
@ -0,0 +1,14 @@
|
||||
PyObject *high;
|
||||
PyObject *low;
|
||||
PyObject *input;
|
||||
PyObject *output;
|
||||
PyObject *alt0;
|
||||
PyObject *pud_off;
|
||||
PyObject *pud_up;
|
||||
PyObject *pud_down;
|
||||
PyObject *rising_edge;
|
||||
PyObject *falling_edge;
|
||||
PyObject *both_edge;
|
||||
PyObject *version;
|
||||
|
||||
void define_constants(PyObject *module);
|
660
source/event_gpio.c
Normal file
660
source/event_gpio.c
Normal file
@ -0,0 +1,660 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "event_gpio.h"
|
||||
#include "common.h"
|
||||
|
||||
const char *stredge[4] = {"none", "rising", "falling", "both"};
|
||||
|
||||
// file descriptors
|
||||
struct fdx
|
||||
{
|
||||
int fd;
|
||||
unsigned int gpio;
|
||||
int initial;
|
||||
unsigned int is_evented;
|
||||
struct fdx *next;
|
||||
};
|
||||
struct fdx *fd_list = NULL;
|
||||
|
||||
// event callbacks
|
||||
struct callback
|
||||
{
|
||||
unsigned int gpio;
|
||||
void (*func)(unsigned int gpio);
|
||||
struct callback *next;
|
||||
};
|
||||
struct callback *callbacks = NULL;
|
||||
|
||||
// gpio exports
|
||||
struct gpio_exp
|
||||
{
|
||||
unsigned int gpio;
|
||||
struct gpio_exp *next;
|
||||
};
|
||||
struct gpio_exp *exported_gpios = NULL;
|
||||
|
||||
pthread_t threads;
|
||||
int event_occurred[430] = { 0 };
|
||||
int thread_running = 0;
|
||||
int epfd = -1;
|
||||
|
||||
int gpio_export(unsigned int gpio)
|
||||
{
|
||||
int fd, len;
|
||||
char str_gpio[10];
|
||||
struct gpio_exp *new_gpio, *g;
|
||||
|
||||
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
|
||||
write(fd, str_gpio, len);
|
||||
close(fd);
|
||||
|
||||
// add to list
|
||||
new_gpio = malloc(sizeof(struct gpio_exp));
|
||||
if (new_gpio == 0)
|
||||
return -1; // out of memory
|
||||
|
||||
new_gpio->gpio = gpio;
|
||||
new_gpio->next = NULL;
|
||||
|
||||
if (exported_gpios == NULL)
|
||||
{
|
||||
// create new list
|
||||
exported_gpios = new_gpio;
|
||||
} else {
|
||||
// add to end of existing list
|
||||
g = exported_gpios;
|
||||
while (g->next != NULL)
|
||||
g = g->next;
|
||||
g->next = new_gpio;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_value_fd(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
struct fdx *temp;
|
||||
struct fdx *prev = NULL;
|
||||
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
{
|
||||
close(f->fd);
|
||||
if (prev == NULL)
|
||||
fd_list = f->next;
|
||||
else
|
||||
prev->next = f->next;
|
||||
temp = f;
|
||||
f = f->next;
|
||||
free(temp);
|
||||
} else {
|
||||
prev = f;
|
||||
f = f->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fd_lookup(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
return f->fd;
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_fd_list(unsigned int gpio, int fd)
|
||||
{
|
||||
struct fdx *new_fd;
|
||||
|
||||
new_fd = malloc(sizeof(struct fdx));
|
||||
if (new_fd == 0)
|
||||
return -1; // out of memory
|
||||
|
||||
new_fd->fd = fd;
|
||||
new_fd->gpio = gpio;
|
||||
new_fd->initial = 1;
|
||||
new_fd->is_evented = 0;
|
||||
if (fd_list == NULL) {
|
||||
new_fd->next = NULL;
|
||||
} else {
|
||||
new_fd->next = fd_list;
|
||||
}
|
||||
fd_list = new_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_value_file(unsigned int gpio)
|
||||
{
|
||||
int fd;
|
||||
char filename[MAX_FILENAME];
|
||||
|
||||
// create file descriptor of value file
|
||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
|
||||
|
||||
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
|
||||
return -1;
|
||||
add_fd_list(gpio, fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int gpio_unexport(unsigned int gpio)
|
||||
{
|
||||
int fd, len;
|
||||
char str_gpio[10];
|
||||
struct gpio_exp *g, *temp, *prev_g = NULL;
|
||||
|
||||
close_value_fd(gpio);
|
||||
|
||||
if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
|
||||
write(fd, str_gpio, len);
|
||||
close(fd);
|
||||
|
||||
// remove from list
|
||||
g = exported_gpios;
|
||||
while (g != NULL)
|
||||
{
|
||||
if (g->gpio == gpio)
|
||||
{
|
||||
if (prev_g == NULL)
|
||||
exported_gpios = g->next;
|
||||
else
|
||||
prev_g->next = g->next;
|
||||
temp = g;
|
||||
g = g->next;
|
||||
free(temp);
|
||||
} else {
|
||||
prev_g = g;
|
||||
g = g->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
|
||||
{
|
||||
int fd;
|
||||
char filename[40];
|
||||
char direction[10] = { 0 };
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
|
||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
if (in_flag) {
|
||||
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
|
||||
} else {
|
||||
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
|
||||
}
|
||||
|
||||
write(fd, direction, strlen(direction));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_get_direction(unsigned int gpio, unsigned int *value)
|
||||
{
|
||||
int fd;
|
||||
char direction[4] = { 0 };
|
||||
char filename[40];
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
|
||||
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
|
||||
return -1;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
read(fd, &direction, sizeof(direction) - 1);
|
||||
|
||||
if (strcmp(direction, "out") == 0) {
|
||||
*value = OUTPUT;
|
||||
} else {
|
||||
*value = INPUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_set_value(unsigned int gpio, unsigned int value)
|
||||
{
|
||||
int fd;
|
||||
char filename[MAX_FILENAME];
|
||||
char vstr[10];
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
|
||||
|
||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
if (value) {
|
||||
strncpy(vstr, "1", ARRAY_SIZE(vstr) - 1);
|
||||
} else {
|
||||
strncpy(vstr, "0", ARRAY_SIZE(vstr) - 1);
|
||||
}
|
||||
|
||||
write(fd, vstr, strlen(vstr));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_get_value(unsigned int gpio, unsigned int *value)
|
||||
{
|
||||
int fd = fd_lookup(gpio);
|
||||
char ch;
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
if ((fd = open_value_file(gpio)) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
read(fd, &ch, sizeof(ch));
|
||||
|
||||
if (ch != '0') {
|
||||
*value = 1;
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_set_edge(unsigned int gpio, unsigned int edge)
|
||||
{
|
||||
int fd;
|
||||
char filename[40];
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio);
|
||||
|
||||
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
write(fd, stredge[edge], strlen(stredge[edge]) + 1);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int gpio_lookup(int fd)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->fd == fd)
|
||||
return f->gpio;
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exports_cleanup(void)
|
||||
{
|
||||
// unexport everything
|
||||
while (exported_gpios != NULL)
|
||||
gpio_unexport(exported_gpios->gpio);
|
||||
}
|
||||
|
||||
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
|
||||
{
|
||||
struct callback *cb = callbacks;
|
||||
struct callback *new_cb;
|
||||
|
||||
new_cb = malloc(sizeof(struct callback));
|
||||
if (new_cb == 0)
|
||||
return -1; // out of memory
|
||||
|
||||
new_cb->gpio = gpio;
|
||||
new_cb->func = func;
|
||||
new_cb->next = NULL;
|
||||
|
||||
if (callbacks == NULL) {
|
||||
// start new list
|
||||
callbacks = new_cb;
|
||||
} else {
|
||||
// add to end of list
|
||||
while (cb->next != NULL)
|
||||
cb = cb->next;
|
||||
cb->next = new_cb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_callbacks(unsigned int gpio)
|
||||
{
|
||||
struct callback *cb = callbacks;
|
||||
while (cb != NULL)
|
||||
{
|
||||
if (cb->gpio == gpio)
|
||||
cb->func(cb->gpio);
|
||||
cb = cb->next;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_callbacks(unsigned int gpio)
|
||||
{
|
||||
struct callback *cb = callbacks;
|
||||
struct callback *temp;
|
||||
struct callback *prev = NULL;
|
||||
|
||||
while (cb != NULL)
|
||||
{
|
||||
if (cb->gpio == gpio)
|
||||
{
|
||||
if (prev == NULL)
|
||||
callbacks = cb->next;
|
||||
else
|
||||
prev->next = cb->next;
|
||||
temp = cb;
|
||||
cb = cb->next;
|
||||
free(temp);
|
||||
} else {
|
||||
prev = cb;
|
||||
cb = cb->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_initial_false(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
f->initial = 0;
|
||||
f = f->next;
|
||||
}
|
||||
}
|
||||
|
||||
int gpio_initial(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
|
||||
while (f != NULL)
|
||||
{
|
||||
if ((f->gpio == gpio) && f->initial)
|
||||
return 1;
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *poll_thread(void *threadarg)
|
||||
{
|
||||
struct epoll_event events;
|
||||
char buf;
|
||||
unsigned int gpio;
|
||||
int n;
|
||||
|
||||
thread_running = 1;
|
||||
while (thread_running)
|
||||
{
|
||||
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
||||
{
|
||||
thread_running = 0;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if (n > 0) {
|
||||
lseek(events.data.fd, 0, SEEK_SET);
|
||||
if (read(events.data.fd, &buf, 1) != 1)
|
||||
{
|
||||
thread_running = 0;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
gpio = gpio_lookup(events.data.fd);
|
||||
if (gpio_initial(gpio)) { // ignore first epoll trigger
|
||||
set_initial_false(gpio);
|
||||
} else {
|
||||
event_occurred[gpio] = 1;
|
||||
run_callbacks(gpio);
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_running = 0;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int gpio_is_evented(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
return 1;
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_event_add(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
{
|
||||
if (f->is_evented)
|
||||
return 1;
|
||||
|
||||
f->is_evented = 1;
|
||||
return 0;
|
||||
}
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_event_remove(unsigned int gpio)
|
||||
{
|
||||
struct fdx *f = fd_list;
|
||||
while (f != NULL)
|
||||
{
|
||||
if (f->gpio == gpio)
|
||||
{
|
||||
f->is_evented = 0;
|
||||
return 0;
|
||||
}
|
||||
f = f->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_edge_detect(unsigned int gpio, unsigned int edge)
|
||||
// return values:
|
||||
// 0 - Success
|
||||
// 1 - Edge detection already added
|
||||
// 2 - Other error
|
||||
{
|
||||
int fd = fd_lookup(gpio);
|
||||
pthread_t threads;
|
||||
struct epoll_event ev;
|
||||
long t = 0;
|
||||
|
||||
// check to see if this gpio has been added already
|
||||
if (gpio_event_add(gpio) != 0)
|
||||
return 1;
|
||||
|
||||
// export /sys/class/gpio interface
|
||||
gpio_export(gpio);
|
||||
gpio_set_direction(gpio, 0); // 0=input
|
||||
gpio_set_edge(gpio, edge);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
if ((fd = open_value_file(gpio)) == -1)
|
||||
return 2;
|
||||
}
|
||||
|
||||
// create epfd if not already open
|
||||
if ((epfd == -1) && ((epfd = epoll_create(1)) == -1))
|
||||
return 2;
|
||||
|
||||
// add to epoll fd
|
||||
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||
ev.data.fd = fd;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||
return 2;
|
||||
|
||||
// start poll thread if it is not already running
|
||||
if (!thread_running)
|
||||
{
|
||||
if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0)
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void remove_edge_detect(unsigned int gpio)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int fd = fd_lookup(gpio);
|
||||
|
||||
// delete callbacks for gpio
|
||||
remove_callbacks(gpio);
|
||||
|
||||
// delete epoll of fd
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
|
||||
|
||||
// set edge to none
|
||||
gpio_set_edge(gpio, NO_EDGE);
|
||||
|
||||
// unexport gpio
|
||||
gpio_event_remove(gpio);
|
||||
|
||||
// clear detected flag
|
||||
event_occurred[gpio] = 0;
|
||||
}
|
||||
|
||||
int event_detected(unsigned int gpio)
|
||||
{
|
||||
if (event_occurred[gpio]) {
|
||||
event_occurred[gpio] = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void event_cleanup(void)
|
||||
{
|
||||
close(epfd);
|
||||
thread_running = 0;
|
||||
exports_cleanup();
|
||||
}
|
||||
|
||||
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
|
||||
// standalone from all the event functions above
|
||||
{
|
||||
int fd = fd_lookup(gpio);
|
||||
int epfd, n, i;
|
||||
struct epoll_event events, ev;
|
||||
char buf;
|
||||
|
||||
if ((epfd = epoll_create(1)) == -1)
|
||||
return 1;
|
||||
|
||||
// check to see if this gpio has been added already, if not, mark as added
|
||||
if (gpio_event_add(gpio) != 0)
|
||||
return 2;
|
||||
|
||||
// export /sys/class/gpio interface
|
||||
gpio_export(gpio);
|
||||
gpio_set_direction(gpio, 0); // 0=input
|
||||
gpio_set_edge(gpio, edge);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
if ((fd = open_value_file(gpio)) == -1)
|
||||
return 3;
|
||||
}
|
||||
|
||||
// add to epoll fd
|
||||
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||
ev.data.fd = fd;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||
{
|
||||
gpio_event_remove(gpio);
|
||||
return 4;
|
||||
}
|
||||
|
||||
// epoll for event
|
||||
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
|
||||
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
||||
{
|
||||
gpio_event_remove(gpio);
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
lseek(events.data.fd, 0, SEEK_SET);
|
||||
if (read(events.data.fd, &buf, sizeof(buf)) != 1)
|
||||
{
|
||||
gpio_event_remove(gpio);
|
||||
return 6;
|
||||
}
|
||||
if (events.data.fd != fd)
|
||||
{
|
||||
gpio_event_remove(gpio);
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_event_remove(gpio);
|
||||
close(epfd);
|
||||
return 0;
|
||||
}
|
74
source/event_gpio.h
Normal file
74
source/event_gpio.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#define NO_EDGE 0
|
||||
#define RISING_EDGE 1
|
||||
#define FALLING_EDGE 2
|
||||
#define BOTH_EDGE 3
|
||||
|
||||
#define INPUT 0
|
||||
#define OUTPUT 1
|
||||
#define ALT0 4
|
||||
|
||||
#define HIGH 1
|
||||
#define LOW 0
|
||||
|
||||
#define MAX_FILENAME 50
|
||||
|
||||
#define PUD_OFF 0
|
||||
#define PUD_DOWN 1
|
||||
#define PUD_UP 2
|
||||
|
||||
int gpio_export(unsigned int gpio);
|
||||
int gpio_unexport(unsigned int gpio);
|
||||
void exports_cleanup(void);
|
||||
int gpio_set_direction(unsigned int gpio, unsigned int in_flag);
|
||||
int gpio_get_direction(unsigned int gpio, unsigned int *value);
|
||||
int gpio_set_value(unsigned int gpio, unsigned int value);
|
||||
int gpio_get_value(unsigned int gpio, unsigned int *value);
|
||||
|
||||
int add_edge_detect(unsigned int gpio, unsigned int edge);
|
||||
void remove_edge_detect(unsigned int gpio);
|
||||
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio));
|
||||
int event_detected(unsigned int gpio);
|
||||
int gpio_event_add(unsigned int gpio);
|
||||
int gpio_event_remove(unsigned int gpio);
|
||||
int gpio_is_evented(unsigned int gpio);
|
||||
int event_initialise(void);
|
||||
void event_cleanup(void);
|
||||
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge);
|
554
source/py_gpio.c
Normal file
554
source/py_gpio.c
Normal file
@ -0,0 +1,554 @@
|
||||
/*
|
||||
Copyright (c) 2016 Robert Wolterman
|
||||
|
||||
Original BBIO Author Justin Cooper
|
||||
Modified for CHIP_IO Author Robert Wolterman
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Adafruit
|
||||
|
||||
Original RPi.GPIO Author Ben Croston
|
||||
Modified for BBIO Author Justin Cooper
|
||||
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice, all modified code adopts the original license:
|
||||
|
||||
Copyright (c) 2013 Ben Croston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "constants.h"
|
||||
#include "common.h"
|
||||
#include "event_gpio.h"
|
||||
|
||||
static int gpio_warnings = 1;
|
||||
|
||||
struct py_callback
|
||||
{
|
||||
char channel[32];
|
||||
unsigned int gpio;
|
||||
PyObject *py_cb;
|
||||
unsigned long long lastcall;
|
||||
unsigned int bouncetime;
|
||||
struct py_callback *next;
|
||||
};
|
||||
static struct py_callback *py_callbacks = NULL;
|
||||
|
||||
static int init_module(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<430; i++)
|
||||
gpio_direction[i] = -1;
|
||||
|
||||
module_setup = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// python function cleanup()
|
||||
static PyObject *py_cleanup(PyObject *self, PyObject *args)
|
||||
{
|
||||
// clean up any exports
|
||||
event_cleanup();
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None)
|
||||
static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
int direction;
|
||||
int pud = PUD_OFF;
|
||||
int initial = 0;
|
||||
static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial))
|
||||
return NULL;
|
||||
|
||||
if (!module_setup) {
|
||||
init_module();
|
||||
}
|
||||
|
||||
|
||||
if (direction != INPUT && direction != OUTPUT)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "An invalid direction was passed to setup()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (direction == OUTPUT)
|
||||
pud = PUD_OFF;
|
||||
|
||||
if (pud != PUD_OFF && pud != PUD_DOWN && pud != PUD_UP)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP or PUD_DOWN");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
gpio_export(gpio);
|
||||
gpio_set_direction(gpio, direction);
|
||||
if (gpio < 408) {
|
||||
if (direction == OUTPUT) {
|
||||
gpio_set_value(gpio, initial);
|
||||
} else {
|
||||
gpio_set_value(gpio, pud);
|
||||
}
|
||||
}
|
||||
|
||||
gpio_direction[gpio] = direction;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function output(channel, value)
|
||||
static PyObject *py_output_gpio(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
int value;
|
||||
char *channel;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "si", &channel, &value))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
if (!module_setup || gpio_direction[gpio] != OUTPUT)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been setup() as an OUTPUT");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpio_set_value(gpio, value);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function value = input(channel)
|
||||
static PyObject *py_input_gpio(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
unsigned int value;
|
||||
PyObject *py_value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
// check channel is set up as an input or output
|
||||
if (!module_setup || (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT))
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpio_get_value(gpio, &value);
|
||||
|
||||
py_value = Py_BuildValue("i", value);
|
||||
|
||||
return py_value;
|
||||
}
|
||||
|
||||
static void run_py_callbacks(unsigned int gpio)
|
||||
{
|
||||
PyObject *result;
|
||||
PyGILState_STATE gstate;
|
||||
struct py_callback *cb = py_callbacks;
|
||||
struct timeval tv_timenow;
|
||||
unsigned long long timenow;
|
||||
|
||||
while (cb != NULL)
|
||||
{
|
||||
if (cb->gpio == gpio)
|
||||
{
|
||||
gettimeofday(&tv_timenow, NULL);
|
||||
timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
|
||||
if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) {
|
||||
|
||||
// save lastcall before calling func to prevent reentrant bounce
|
||||
cb->lastcall = timenow;
|
||||
|
||||
// run callback
|
||||
gstate = PyGILState_Ensure();
|
||||
result = PyObject_CallFunction(cb->py_cb, "s", cb->channel);
|
||||
|
||||
if (result == NULL && PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
PyGILState_Release(gstate);
|
||||
}
|
||||
cb->lastcall = timenow;
|
||||
}
|
||||
cb = cb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int add_py_callback(char *channel, unsigned int gpio, unsigned int bouncetime, PyObject *cb_func)
|
||||
{
|
||||
struct py_callback *new_py_cb;
|
||||
struct py_callback *cb = py_callbacks;
|
||||
|
||||
// add callback to py_callbacks list
|
||||
new_py_cb = malloc(sizeof(struct py_callback));
|
||||
if (new_py_cb == 0)
|
||||
{
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
new_py_cb->py_cb = cb_func;
|
||||
Py_XINCREF(cb_func); // Add a reference to new callback
|
||||
memset(new_py_cb->channel, 0, sizeof(new_py_cb->channel));
|
||||
strncpy(new_py_cb->channel, channel, sizeof(new_py_cb->channel) - 1);
|
||||
new_py_cb->gpio = gpio;
|
||||
new_py_cb->lastcall = 0;
|
||||
new_py_cb->bouncetime = bouncetime;
|
||||
new_py_cb->next = NULL;
|
||||
if (py_callbacks == NULL) {
|
||||
py_callbacks = new_py_cb;
|
||||
} else {
|
||||
// add to end of list
|
||||
while (cb->next != NULL)
|
||||
cb = cb->next;
|
||||
cb->next = new_py_cb;
|
||||
}
|
||||
add_edge_callback(gpio, run_py_callbacks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// python function add_event_callback(gpio, callback, bouncetime=0)
|
||||
static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
unsigned int bouncetime = 0;
|
||||
PyObject *cb_func;
|
||||
char *kwlist[] = {"gpio", "callback", "bouncetime", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime))
|
||||
return NULL;
|
||||
|
||||
if (!PyCallable_Check(cb_func))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
// check channel is set up as an input
|
||||
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!gpio_is_evented(gpio))
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function add_event_detect(gpio, edge, callback=None, bouncetime=0
|
||||
static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
int edge, result;
|
||||
unsigned int bouncetime = 0;
|
||||
PyObject *cb_func = NULL;
|
||||
char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime))
|
||||
return NULL;
|
||||
|
||||
if (cb_func != NULL && !PyCallable_Check(cb_func))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
// check channel is set up as an input
|
||||
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// is edge valid value
|
||||
if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread
|
||||
{
|
||||
if (result == 1)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Edge detection already enabled for this GPIO channel");
|
||||
return NULL;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cb_func != NULL)
|
||||
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function remove_event_detect(gpio)
|
||||
static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
struct py_callback *cb = py_callbacks;
|
||||
struct py_callback *temp;
|
||||
struct py_callback *prev = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
// remove all python callbacks for gpio
|
||||
while (cb != NULL)
|
||||
{
|
||||
if (cb->gpio == gpio)
|
||||
{
|
||||
Py_XDECREF(cb->py_cb);
|
||||
if (prev == NULL)
|
||||
py_callbacks = cb->next;
|
||||
else
|
||||
prev->next = cb->next;
|
||||
temp = cb;
|
||||
cb = cb->next;
|
||||
free(temp);
|
||||
} else {
|
||||
prev = cb;
|
||||
cb = cb->next;
|
||||
}
|
||||
}
|
||||
|
||||
remove_edge_detect(gpio);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function value = event_detected(channel)
|
||||
static PyObject *py_event_detected(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
char *channel;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
if (event_detected(gpio))
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
// python function py_wait_for_edge(gpio, edge)
|
||||
static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
int edge, result;
|
||||
char *channel;
|
||||
char error[30];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "si", &channel, &edge))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
// check channel is setup as an input
|
||||
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// is edge a valid value?
|
||||
if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS // disable GIL
|
||||
result = blocking_wait_for_edge(gpio, edge);
|
||||
Py_END_ALLOW_THREADS // enable GIL
|
||||
|
||||
if (result == 0) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
} else if (result == 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Edge detection events already enabled for this GPIO channel");
|
||||
return NULL;
|
||||
} else {
|
||||
sprintf(error, "Error #%d waiting for edge", result);
|
||||
PyErr_SetString(PyExc_RuntimeError, error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// python function value = gpio_function(gpio)
|
||||
static PyObject *py_gpio_function(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int gpio;
|
||||
unsigned int value;
|
||||
PyObject *func;
|
||||
char *channel;
|
||||
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||
return NULL;
|
||||
|
||||
if (get_gpio_number(channel, &gpio))
|
||||
return NULL;
|
||||
|
||||
if (setup_error)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpio_get_direction(gpio, &value);
|
||||
func = Py_BuildValue("i", value);
|
||||
return func;
|
||||
}
|
||||
|
||||
// python function setwarnings(state)
|
||||
static PyObject *py_setwarnings(PyObject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "i", &gpio_warnings))
|
||||
return NULL;
|
||||
|
||||
if (setup_error)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static const char moduledocstring[] = "GPIO functionality of a CHIP using Python";
|
||||
|
||||
PyMethodDef gpio_methods[] = {
|
||||
{"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up the GPIO channel, direction and (optional) pull/up down control\nchannel - Either: RPi board pin number (not BCM GPIO 00..nn number). Pins start from 1\n or : BCM GPIO number\ndirection - INPUT or OUTPUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel"},
|
||||
{"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"},
|
||||
{"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel\ngpio - gpio channel\nvalue - 0/1 or False/True or LOW/HIGH"},
|
||||
{"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False\ngpio - gpio channel"},
|
||||
{"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[callback] - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"},
|
||||
{"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\ngpio - gpio channel"},
|
||||
{"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occured on a given GPIO. You need to enable edge detection using add_event_detect() first.\ngpio - gpio channel"},
|
||||
{"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\ngpio - gpio channel\ncallback - a callback function\n[bouncetime] - Switch bounce timeout in ms"},
|
||||
{"wait_for_edge", py_wait_for_edge, METH_VARARGS, "Wait for an edge.\ngpio - gpio channel\nedge - RISING, FALLING or BOTH"},
|
||||
{"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, ALT0)\ngpio - gpio channel"},
|
||||
{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
static struct PyModuleDef rpigpiomodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"GPIO", // name of module
|
||||
moduledocstring, // module documentation, may be NULL
|
||||
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
|
||||
gpio_methods
|
||||
};
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
PyMODINIT_FUNC PyInit_GPIO(void)
|
||||
#else
|
||||
PyMODINIT_FUNC initGPIO(void)
|
||||
#endif
|
||||
{
|
||||
PyObject *module = NULL;
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
if ((module = PyModule_Create(&rpigpiomodule)) == NULL)
|
||||
return NULL;
|
||||
#else
|
||||
if ((module = Py_InitModule3("GPIO", gpio_methods, moduledocstring)) == NULL)
|
||||
return;
|
||||
#endif
|
||||
|
||||
define_constants(module);
|
||||
|
||||
if (!PyEval_ThreadsInitialized())
|
||||
PyEval_InitThreads();
|
||||
|
||||
if (Py_AtExit(event_cleanup) != 0)
|
||||
{
|
||||
setup_error = 1;
|
||||
event_cleanup();
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
return NULL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
return module;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
36
source/setup.py
Normal file
36
source/setup.py
Normal file
@ -0,0 +1,36 @@
|
||||
try:
|
||||
from overlays import builder
|
||||
builder.compile()
|
||||
builder.copy()
|
||||
except:
|
||||
pass
|
||||
|
||||
import distribute_setup
|
||||
distribute_setup.use_setuptools()
|
||||
from setuptools import setup, Extension, find_packages
|
||||
|
||||
classifiers = ['Development Status :: 3 - Alpha',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Intended Audience :: Developers',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Topic :: Software Development',
|
||||
'Topic :: Home Automation',
|
||||
'Topic :: System :: Hardware']
|
||||
|
||||
setup(name = 'CHIP_IO',
|
||||
version = '0.0.4',
|
||||
author = 'Robert Wolterman',
|
||||
author_email = 'robert.wolterman@gmail.com',
|
||||
description = 'A module to control CHIP IO channels',
|
||||
long_description = open('README.md').read() + open('CHANGELOG.rst').read(),
|
||||
license = 'MIT',
|
||||
keywords = 'CHIP NextThingCo IO GPIO PWM ADC',
|
||||
url = 'https://github.com/xtacocorex/CHIP_IO/',
|
||||
classifiers = classifiers,
|
||||
packages = find_packages(),
|
||||
ext_modules = [Extension('CHIP_IO.GPIO', ['source/py_gpio.c', 'source/event_gpio.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])]) #,
|
||||
# Extension('CHIP_IO.PWM', ['source/py_pwm.c', 'source/c_pwm.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||
# Extension('CHIP_IO.ADC', ['source/py_adc.c', 'source/c_adc.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||
# Extension('CHIP_IO.SPI', ['source/spimodule.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])])
|
Reference in New Issue
Block a user