diff --git a/boards/native/Makefile.features b/boards/native/Makefile.features index 4ad14738b855..c33d1a8c48ac 100644 --- a/boards/native/Makefile.features +++ b/boards/native/Makefile.features @@ -1,3 +1,4 @@ FEATURES_PROVIDED += transceiver periph_cpuid config cpp FEATURES_PROVIDED += periph_random FEATURES_PROVIDED += periph_rtc +FEATURES_PROVIDED += periph_gpio diff --git a/cpu/native/include/periph_conf.h b/cpu/native/include/periph_conf.h index a4655e110bdb..1b4233f9da66 100644 --- a/cpu/native/include/periph_conf.h +++ b/cpu/native/include/periph_conf.h @@ -34,6 +34,154 @@ #define RTC_NUMOF (1) /** @} */ +#ifdef MODULE_NATIVE_GPIO_VIRTUAL /* virtual */ +#define GPIO_0_EN (1) +#define GPIO_1_EN (1) +#define GPIO_2_EN (1) +#define GPIO_3_EN (1) +#define GPIO_4_EN (1) +#define GPIO_5_EN (1) +#define GPIO_6_EN (1) +#define GPIO_7_EN (1) +#define GPIO_8_EN (1) +#define GPIO_9_EN (1) +#define GPIO_10_EN (1) +#define GPIO_11_EN (1) +#define GPIO_12_EN (1) +#define GPIO_13_EN (1) +#define GPIO_14_EN (1) +#define GPIO_15_EN (1) +#define GPIO_16_EN (1) +#define GPIO_17_EN (1) +#define GPIO_18_EN (1) +#define GPIO_19_EN (1) +#define GPIO_20_EN (1) +#define GPIO_21_EN (1) +#define GPIO_22_EN (1) +#define GPIO_23_EN (1) +#define GPIO_24_EN (1) +#define GPIO_25_EN (1) +#define GPIO_26_EN (1) +#define GPIO_27_EN (1) +#define GPIO_28_EN (1) +#define GPIO_29_EN (1) +#define GPIO_30_EN (1) +#define GPIO_31_EN (1) +#define GPIO_NUMOF (32) + +#elif defined MODULE_NATIVE_GPIO_SYSFS /* sysfs */ + +#ifdef NATIVE_GPIO_NUMOF +# if NATIVE_GPIO_NUMOF > 32 +# define GPIO_NUMOF 32 +# else +# define GPIO_NUMOF NATIVE_GPIO_NUMOF +# endif +#else +# define GPIO_NUMOF 0 +#endif + +#if GPIO_NUMOF > 0 +# define GPIO_0_EN (1) +#endif +#if GPIO_NUMOF > 1 +# define GPIO_1_EN (1) +#endif +#if GPIO_NUMOF > 2 +# define GPIO_2_EN (1) +#endif +#if GPIO_NUMOF > 3 +# define GPIO_3_EN (1) +#endif +#if GPIO_NUMOF > 4 +# define GPIO_4_EN (1) +#endif +#if GPIO_NUMOF > 5 +# define GPIO_5_EN (1) +#endif +#if GPIO_NUMOF > 6 +# define GPIO_6_EN (1) +#endif +#if GPIO_NUMOF > 7 +# define GPIO_7_EN (1) +#endif +#if GPIO_NUMOF > 8 +# define GPIO_8_EN (1) +#endif +#if GPIO_NUMOF > 9 +# define GPIO_9_EN (1) +#endif +#if GPIO_NUMOF > 10 +# define GPIO_10_EN (1) +#endif +#if GPIO_NUMOF > 11 +# define GPIO_11_EN (1) +#endif +#if GPIO_NUMOF > 12 +# define GPIO_12_EN (1) +#endif +#if GPIO_NUMOF > 13 +# define GPIO_13_EN (1) +#endif +#if GPIO_NUMOF > 14 +# define GPIO_14_EN (1) +#endif +#if GPIO_NUMOF > 15 +# define GPIO_15_EN (1) +#endif +#if GPIO_NUMOF > 16 +# define GPIO_16_EN (1) +#endif +#if GPIO_NUMOF > 17 +# define GPIO_17_EN (1) +#endif +#if GPIO_NUMOF > 18 +# define GPIO_18_EN (1) +#endif +#if GPIO_NUMOF > 19 +# define GPIO_19_EN (1) +#endif +#if GPIO_NUMOF > 20 +# define GPIO_20_EN (1) +#endif +#if GPIO_NUMOF > 21 +# define GPIO_21_EN (1) +#endif +#if GPIO_NUMOF > 22 +# define GPIO_22_EN (1) +#endif +#if GPIO_NUMOF > 23 +# define GPIO_23_EN (1) +#endif +#if GPIO_NUMOF > 24 +# define GPIO_24_EN (1) +#endif +#if GPIO_NUMOF > 25 +# define GPIO_25_EN (1) +#endif +#if GPIO_NUMOF > 26 +# define GPIO_26_EN (1) +#endif +#if GPIO_NUMOF > 27 +# define GPIO_27_EN (1) +#endif +#if GPIO_NUMOF > 28 +# define GPIO_28_EN (1) +#endif +#if GPIO_NUMOF > 29 +# define GPIO_29_EN (1) +#endif +#if GPIO_NUMOF > 30 +# define GPIO_30_EN (1) +#endif +#if GPIO_NUMOF > 31 +# define GPIO_31_EN (1) +#endif + +#else /* no GPIO device */ +#define GPIO_NUMOF (0) +#endif + #ifdef __cplusplus } #endif diff --git a/cpu/native/periph/Makefile b/cpu/native/periph/Makefile index 48422e909a47..5453ea9fc058 100644 --- a/cpu/native/periph/Makefile +++ b/cpu/native/periph/Makefile @@ -1 +1,7 @@ +ifneq (,$(filter native_gpio_virtual,$(USEMODULE))) + DIRS += gpio/virtual +endif +ifneq (,$(filter native_gpio_sysfs,$(USEMODULE))) + DIRS += gpio/sysfs +endif include $(RIOTBASE)/Makefile.base diff --git a/cpu/native/periph/gpio/sysfs/Makefile b/cpu/native/periph/gpio/sysfs/Makefile new file mode 100644 index 000000000000..fcc1c5da8ecb --- /dev/null +++ b/cpu/native/periph/gpio/sysfs/Makefile @@ -0,0 +1,5 @@ +MODULE = native_gpio_sysfs + +include $(RIOTBASE)/Makefile.base + +INCLUDES = $(NATIVEINCLUDES) diff --git a/cpu/native/periph/gpio/sysfs/gpio.c b/cpu/native/periph/gpio/sysfs/gpio.c new file mode 100644 index 000000000000..e65f3c6910c0 --- /dev/null +++ b/cpu/native/periph/gpio/sysfs/gpio.c @@ -0,0 +1,323 @@ +/** + * Native CPU Linux sysfs GPIO interface driver + * + * Copyright (C) 2014 Ludwig Ortmann + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * @ingroup native_cpu + * @{ + * @file + * @author Ludwig Ortmann + */ + +#include +#include +#include +#include +#include + +#include "native_internal.h" + +#include "periph/gpio.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/******************************************************************************** + * internal API declaration + *******************************************************************************/ + +#define GPIO_SYSFS_PATH "/sys/class/gpio" + +typedef enum { + _NATIVE_GPIO_CONF_NONE, + _NATIVE_GPIO_CONF_IN, + _NATIVE_GPIO_CONF_OUT, + _NATIVE_GPIO_CONF_INT, +} _native_gpio_conf_t; + +typedef struct { + _native_gpio_conf_t conf; + int pin_state; + int int_enabled; + gpio_pp_t pp; + gpio_flank_t flank; + gpio_cb_t cb; + void *cb_arg; +} _native_gpio_state_t; + +/* + * all return >= 0 on success, -1 otherwise + */ +static int sysfs_gpio_conf(gpio_t dev, _native_gpio_conf_t conf); +static int sysfs_gpio_read(gpio_t dev); +static int sysfs_gpio_write(gpio_t dev, int value); + +_native_gpio_state_t gpio_device_state[GPIO_NUMOF]; + +/******************************************************************************** + * public API implementation + *******************************************************************************/ + +int gpio_init_out(gpio_t dev, gpio_pp_t pullup) +{ + int ret = sysfs_gpio_conf(dev, _NATIVE_GPIO_CONF_OUT); + if (ret != 0) { + warnx("gpio_init_out(%i)", dev); + return -1; + } + + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_OUT; + return ret; +} + +int gpio_init_in(gpio_t dev, gpio_pp_t pullup) +{ + int ret = sysfs_gpio_conf(dev, _NATIVE_GPIO_CONF_IN); + if (ret != 0) { + warnx("gpio_init_in(%i)", dev); + return -1; + } + + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_IN; + return ret; +} + +int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg) +{ + int ret = sysfs_gpio_conf(dev, _NATIVE_GPIO_CONF_INT); + if (ret != 0) { + warnx("gpio_init_int(%i)", dev); + return -1; + } + + /* TODO: configure interrupt + pollfds */ + + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].flank = flank; + gpio_device_state[dev].cb = cb; + gpio_device_state[dev].cb_arg = arg; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_INT; + gpio_irq_enable(dev); + return ret; +} + +void gpio_irq_enable(gpio_t dev) +{ + /* TODO: implement */ + gpio_device_state[dev].int_enabled = 1; +} + +void gpio_irq_disable(gpio_t dev) +{ + /* TODO: implement */ + gpio_device_state[dev].int_enabled = 0; +} + +int gpio_read(gpio_t dev) +{ + int ret = sysfs_gpio_read(dev); + if (ret == -1) { + warnx("gpio_read(%i): error reading", dev); + return -1; + } + + gpio_device_state[dev].pin_state = ret; + + return gpio_device_state[dev].pin_state; +} + +void gpio_set(gpio_t dev) +{ + int ret = sysfs_gpio_write(dev, 1); + if (ret == -1) { + warnx("gpio_set(%i): error writing", dev); + return; + } + + printf("Native GPIO device %i is now HIGH\n", dev); + gpio_device_state[dev].pin_state = 1; +} + +void gpio_clear(gpio_t dev) +{ + int ret = sysfs_gpio_write(dev, 0); + if (ret == -1) { + warnx("gpio_clear(%i): error writing", dev); + return; + } + + printf("Native GPIO device %i is now LOW\n", dev); + gpio_device_state[dev].pin_state = 0; +} + +void gpio_toggle(gpio_t dev) +{ + int ret = sysfs_gpio_write(dev, !gpio_device_state[dev].pin_state); + if (ret == -1) { + warnx("gpio_toggle(%i): error writing", dev); + return; + } + + gpio_device_state[dev].pin_state = !gpio_device_state[dev].pin_state; + printf("Native GPIO device %i is now %s\n", dev, + (gpio_device_state[dev].pin_state == 0) ? "LOW" : "HIGH"); +} + +void gpio_write(gpio_t dev, int value) +{ + int ret = sysfs_gpio_write(dev, value); + if (ret == -1) { + warnx("gpio_write(%i): error writing", dev); + return; + } + + gpio_device_state[dev].pin_state = (value == 0) ? 0 : 1; + printf("Native GPIO device %i is now %s\n", dev, + (gpio_device_state[dev].pin_state == 0) ? "LOW" : "HIGH"); +} + + +/******************************************************************************** + * internal API implementation + *******************************************************************************/ + +static int sysfs_gpio_conf(gpio_t dev, _native_gpio_conf_t conf) +{ + char gpio_path_name[255]; + + int len = snprintf(gpio_path_name, sizeof(gpio_path_name), GPIO_SYSFS_PATH "/gpio%hi/direction", dev); + if (len < 0) { + warnx("sysfs_gpio_conf(%i): snprintf: fail", dev); + return -1; + } + + _native_syscall_enter(); + int fd = real_open(gpio_path_name, O_WRONLY); + if (fd < 0) { + warn("sysfs_gpio_conf(%i)", dev); + _native_syscall_leave(); + return -1; + } + + int ret = 0; + switch (conf) { + case (_NATIVE_GPIO_CONF_IN): + ret = real_write(fd, "in", 3); + if (ret == -1) { + warn("sysfs_gpio_conf(%i, _NATIVE_GPIO_CONF_IN)", dev); + } + else { + ret = 0; + } + break; + case (_NATIVE_GPIO_CONF_OUT): + ret = real_write(fd, "out", 4); + if (ret == -1) { + warn("sysfs_gpio_conf(%i, _NATIVE_GPIO_CONF_OUT)", dev); + } + else { + ret = 0; + } + break; + default: + warnx("sysfs_gpio_conf(%i, %i): configuration mode not implemented", dev, conf); + ret = -1; + break; + } + real_close(fd); + _native_syscall_leave(); + return ret; +} + +static int sysfs_gpio_read(gpio_t dev) +{ + char gpio_path_name[255]; + + int len = snprintf(gpio_path_name, sizeof(gpio_path_name), GPIO_SYSFS_PATH "/gpio%hi/value", dev); + if (len < 0) { + warnx("sysfs_gpio_read(%i): snprintf: fail", dev); + return -1; + } + + _native_syscall_enter(); + int fd = real_open(gpio_path_name, O_RDONLY); + if (fd < 0) { + warn("sysfs_gpio_read(%i)", dev); + _native_syscall_leave(); + return -1; + } + + char val; + int ret = real_read(fd, &val, 1); + if (ret == -1) { + warn("sysfs_gpio_read(%i)", dev); + } + else { + switch (val) { + case ('0'): + ret = 0; + break; + case ('1'): + ret = 1; + break; + default: + warnx("sysfs_gpio_read(%i): internal error", dev); + ret = -1; + } + } + + if (real_close(fd) == -1) { + warn("sysfs_gpio_read"); + } + + _native_syscall_leave(); + + return ret; +} + +static int sysfs_gpio_write(gpio_t dev, int value) +{ + char gpio_path_name[255]; + + int len = snprintf(gpio_path_name, sizeof(gpio_path_name), GPIO_SYSFS_PATH "/gpio%hi/value", dev); + if (len < 0) { + warnx("sysfs_gpio_write(%i): snprintf: fail", dev); + return -1; + } + + _native_syscall_enter(); + int fd = real_open(gpio_path_name, O_WRONLY); + if (fd < 0) { + warn("sysfs_gpio_write(%i)", dev); + _native_syscall_leave(); + return -1; + } + + int ret = real_write(fd, (value == 0) ? "0" : "1", 2); + switch (ret) { + case -1: + warn("sysfs_gpio_write(%i)", dev); + break; + case 2: + ret = 0; + break; + default: + warnx("sysfs_gpio_write(%i): short write", dev); + ret = -1; + break; + } + + if (real_close(fd) == -1) { + warn("sysfs_gpio_write"); + } + + _native_syscall_leave(); + + return ret; +} diff --git a/cpu/native/periph/gpio/virtual/Makefile b/cpu/native/periph/gpio/virtual/Makefile new file mode 100644 index 000000000000..9d9466228b13 --- /dev/null +++ b/cpu/native/periph/gpio/virtual/Makefile @@ -0,0 +1,5 @@ +MODULE = native_gpio_virtual + +include $(RIOTBASE)/Makefile.base + +INCLUDES = $(NATIVEINCLUDES) diff --git a/cpu/native/periph/gpio/virtual/gpio.c b/cpu/native/periph/gpio/virtual/gpio.c new file mode 100644 index 000000000000..e041a23dfd39 --- /dev/null +++ b/cpu/native/periph/gpio/virtual/gpio.c @@ -0,0 +1,106 @@ +/** + * Native virtual GPIO interface + * + * Copyright (C) 2014 Ludwig Ortmann + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * @ingroup native_cpu + * @{ + * @file + * @author Ludwig Ortmann + */ + +#include + +#include "periph/gpio.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +typedef enum { + _NATIVE_GPIO_CONF_NONE, + _NATIVE_GPIO_CONF_IN, + _NATIVE_GPIO_CONF_OUT, + _NATIVE_GPIO_CONF_INT, +} _native_gpio_conf_t; + +typedef struct { + _native_gpio_conf_t conf; + int pin_state; + int int_enabled; + gpio_pp_t pp; + gpio_flank_t flank; + gpio_cb_t cb; + void *cb_arg; +} _native_gpio_state_t; + +_native_gpio_state_t gpio_device_state[GPIO_NUMOF]; + +int gpio_init_out(gpio_t dev, gpio_pp_t pullup) +{ + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_OUT; + return 0; +} + +int gpio_init_in(gpio_t dev, gpio_pp_t pullup) +{ + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_IN; + return 0; +} + +int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg) +{ + gpio_device_state[dev].pp = pullup; + gpio_device_state[dev].flank = flank; + gpio_device_state[dev].cb = cb; + gpio_device_state[dev].cb_arg = arg; + gpio_device_state[dev].conf = _NATIVE_GPIO_CONF_INT; + gpio_irq_enable(dev); + return 0; +} + +void gpio_irq_enable(gpio_t dev) +{ + gpio_device_state[dev].int_enabled = 1; +} + +void gpio_irq_disable(gpio_t dev) +{ + gpio_device_state[dev].int_enabled = 0; +} + +int gpio_read(gpio_t dev) +{ + return gpio_device_state[dev].pin_state; +} + +void gpio_set(gpio_t dev) +{ + printf("Native GPIO device %i is now HIGH\n", dev); + gpio_device_state[dev].pin_state = 1; +} + +void gpio_clear(gpio_t dev) +{ + printf("Native GPIO device %i is now LOW\n", dev); + gpio_device_state[dev].pin_state = 0; +} + +void gpio_toggle(gpio_t dev) +{ + gpio_device_state[dev].pin_state = !gpio_device_state[dev].pin_state; + printf("Native GPIO device %i is now %s\n", dev, + (gpio_device_state[dev].pin_state == 0) ? "LOW" : "HIGH"); +} + +void gpio_write(gpio_t dev, int value) +{ + gpio_device_state[dev].pin_state = (value == 0) ? 0 : 1; + printf("Native GPIO device %i is now %s\n", dev, + (gpio_device_state[dev].pin_state == 0) ? "LOW" : "HIGH"); +} diff --git a/tests/driver_pir/Makefile b/tests/driver_pir/Makefile index 3e3411af22bb..40ed98985a18 100644 --- a/tests/driver_pir/Makefile +++ b/tests/driver_pir/Makefile @@ -10,6 +10,10 @@ endif ifneq (,$(filter arduino-due,$(BOARD))) export PIR_GPIO ?= GPIO_10 endif +ifneq (,$(filter native,$(BOARD))) + export PIR_GPIO ?= GPIO_0 + USEMODULE += native_gpio_virtual +endif USEMODULE += pir USEMODULE += vtimer diff --git a/tests/driver_pir/main.c b/tests/driver_pir/main.c index 0d80931ebfb9..c784805c017c 100644 --- a/tests/driver_pir/main.c +++ b/tests/driver_pir/main.c @@ -33,6 +33,8 @@ pir_t dev; void* pir_handler(void *arg) { + (void) arg; /* unused */ + msg_t msg_q[1]; msg_init_queue(msg_q, 1); diff --git a/tests/periph_gpio/Makefile b/tests/periph_gpio/Makefile index 983113639937..c1834aebbd5e 100644 --- a/tests/periph_gpio/Makefile +++ b/tests/periph_gpio/Makefile @@ -3,6 +3,13 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_gpio +ifneq (,$(filter native,$(BOARD))) + USEMODULE += native_gpio_virtual + # comment out above and uncomment below to use the sysfs interface instead + #CFLAGS += -DNATIVE_GPIO_NUMOF=4 + #USEMODULE += native_gpio_sysfs +endif + DISABLE_MODULE += auto_init include $(RIOTBASE)/Makefile.include