diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 1ea870607..4301aaf62 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -120,6 +120,11 @@ ifneq (,$(filter hdc1000,$(USEMODULE))) FEATURES_REQUIRED += periph_i2c endif +ifneq (,$(filter pulse_counter,$(USEMODULE))) + USEMODULE += xtimer + FEATURES_REQUIRED += periph_gpio +endif + ifneq (,$(filter hih6130,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/drivers/Makefile.include b/drivers/Makefile.include index ff5dac66b..f14c98401 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -58,6 +58,9 @@ endif ifneq (,$(filter my9221,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/my9221/include endif +ifneq (,$(filter pulse_counter,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pulse_counter/include +endif ifneq (,$(filter ina220,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina220/include endif diff --git a/drivers/include/pulse_counter.h b/drivers/include/pulse_counter.h new file mode 100644 index 000000000..e81c876b3 --- /dev/null +++ b/drivers/include/pulse_counter.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017 UC Berkeley + * + * 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. + */ + +/** + * @defgroup drivers_pulse_counter extra sensor + * @ingroup drivers_sensors + * + * The connection between the MCU and the PULSE_COUNTER is based on the + * GPIO-interface. + * + * @{ + * + * @file + * @brief Driver for the PULSE_COUNTER extra sensor + * + * @author Hyung-Sin Kim + */ + +#ifndef PULSE_COUNTER_H +#define PULSE_COUNTER_H + +#include +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Parameters needed for device initialization + */ +typedef struct { + gpio_t gpio; /**< GPIO pin that sensor is connected to */ + gpio_flank_t gpio_flank; /**< GPIO flank option */ +} pulse_counter_params_t; + +/** + * @brief Device descriptor for a PULSE_COUNTER device + */ +typedef struct { + int16_t pulse_count; /**< pulse counter */ +} pulse_counter_t; + +/** + * @brief Initialize an PULSE_COUNTER device + * + * @param[out] dev device descriptor + * @param[in] params configuration parameters + * + * @return 0 on success + * @return -1 on error + */ +int pulse_counter_init(pulse_counter_t *dev, const pulse_counter_params_t *params); + +/** + * @brief Read and reset PULSE_COUNTER value + * + * @param[in] dev device descriptor of sensor + * + * @return Accumulated pulse counts + */ +int16_t pulse_counter_read_with_reset(const void *dev); + +/** + * @brief Read PULSE_COUNTER value + * + * @param[in] dev device descriptor of sensor + * + * @return Accumulated pulse counts + */ +int16_t pulse_counter_read_without_reset(const void *dev); + +/** + * @brief Reset PULSE_COUNTER value + * + * @param[in] dev device descriptor of sensor + */ +void pulse_counter_reset(const void *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* PULSE_COUNTER_H */ +/** @} */ diff --git a/drivers/include/saul.h b/drivers/include/saul.h index b9badb05b..832f4f385 100644 --- a/drivers/include/saul.h +++ b/drivers/include/saul.h @@ -92,6 +92,7 @@ enum { SAUL_SENSE_ANALOG = 0x8a, /**< sensor: raw analog value */ SAUL_SENSE_UV = 0x8b, /**< sensor: UV index */ SAUL_SENSE_OBJTEMP = 0x8c, /**< sensor: object temperature */ + SAUL_SENSE_COUNT = 0x8d, /**< sensor: pulse counter */ SAUL_CLASS_ANY = 0xff /**< any device - wildcard */ /* extend this list as needed... */ }; diff --git a/drivers/pulse_counter/Makefile b/drivers/pulse_counter/Makefile new file mode 100644 index 000000000..48422e909 --- /dev/null +++ b/drivers/pulse_counter/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/pulse_counter/include/pulse_counter_params.h b/drivers/pulse_counter/include/pulse_counter_params.h new file mode 100644 index 000000000..72ad853b6 --- /dev/null +++ b/drivers/pulse_counter/include/pulse_counter_params.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 UC Berkeley + * + * 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 drivers_pulse_counter + * + * @{ + * @file + * @brief Default configuration for PULSE_COUNTER devices + * + * @author Hyung-Sin Kim + */ + +#ifndef PULSE_COUNTER_PARAMS_H +#define PULSE_COUNTER_PARAMS_H + +#include "board.h" +#include "pulse_counter.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PULSE_COUNTER_GPIO +#define PULSE_COUNTER_GPIO GPIO_PIN(0,18) +#endif + +#ifndef PULSE_COUNTER_GPIO_FLANK +#define PULSE_COUNTER_GPIO_FLANK GPIO_FALLING +#endif + +#ifndef PULSE_COUNTER_PARAMS +#define PULSE_COUNTER_PARAMS { .gpio = PULSE_COUNTER_GPIO, \ + .gpio_flank = PULSE_COUNTER_GPIO_FLANK } +#endif + +#ifndef PULSE_COUNTER_SAUL_INFO +#define PULSE_COUNTER_SAUL_INFO { .name = "pulse counter" } +#endif + +/** + * @brief PULSE_COUNTER configuration + */ +static const pulse_counter_params_t pulse_counter_params[] = +{ + PULSE_COUNTER_PARAMS, +}; + +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t pulse_counter_saul_info[] = +{ + PULSE_COUNTER_SAUL_INFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* PULSE_COUNTER_PARAMS_H */ +/** @} */ diff --git a/drivers/pulse_counter/pulse_counter.c b/drivers/pulse_counter/pulse_counter.c new file mode 100644 index 000000000..ea5ca8c64 --- /dev/null +++ b/drivers/pulse_counter/pulse_counter.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 UC Berkeley + * + * 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 drivers_pulse_counter + * @{ + * + * @file + * @brief Driver for the PULSE COUNTER. + * + * @author Hyung-Sin Kim + * + * @} + */ + +#include + +#include "pulse_counter_params.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Accumulate pulse count */ +static void pulse_counter_trigger(void *arg) +{ + pulse_counter_t *dev = (pulse_counter_t *)arg; + + /* Use atomic operations to avoid messing with IRQ flags */ + __atomic_fetch_add(&(dev->pulse_count), 1, __ATOMIC_SEQ_CST); +} + +/* Initialize pulse counter */ +int pulse_counter_init(pulse_counter_t *dev, const pulse_counter_params_t *params) +{ + if (gpio_init_int(params->gpio, GPIO_IN_PU, params->gpio_flank, pulse_counter_trigger, dev)) { + return -1; + } + + dev->pulse_count = 0; + return 0; +} + +/* Return the accumulated pulse counts and reset the count to zero */ +int16_t pulse_counter_read_with_reset(const void *dev) +{ + int16_t pulse_count_output = 0; + int16_t reset_value = 0; + + /* Use atomic operations to avoid messing with IRQ flags */ + __atomic_exchange(&(((pulse_counter_t *)dev)->pulse_count), &reset_value, &pulse_count_output, __ATOMIC_SEQ_CST); + return pulse_count_output; +} + +/* Return the accumulated pulse counts */ +int16_t pulse_counter_read_without_reset(const void *dev) +{ + return ((pulse_counter_t *)dev)->pulse_count; +} + +/* Reset the pulse count value to zero */ +void pulse_counter_reset(const void *dev) +{ + ((pulse_counter_t *)dev)->pulse_count = 0; +} diff --git a/drivers/pulse_counter/pulse_counter_saul.c b/drivers/pulse_counter/pulse_counter_saul.c new file mode 100644 index 000000000..9b04b3a7b --- /dev/null +++ b/drivers/pulse_counter/pulse_counter_saul.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 UC Berkeley + * + * 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 drivers_pulse_counter + * @{ + * + * @file + * @brief PULSE_COUNTER adaption to the RIOT actuator/sensor interface + * + * @author Hyung-Sin Kim + * + * @} + */ + +#include + +#include "saul.h" +#include "pulse_counter.h" + +static int read_pulse_counter(const void *dev, phydat_t *res) +{ + res->val[0] = pulse_counter_read_with_reset(dev); + res->unit = UNIT_NONE; + res->scale = 0; + return 1; +} + +static int write_pulse_counter(const void *dev, phydat_t *data) +{ + pulse_counter_reset(dev); + (void) data; + return 1; +} + +const saul_driver_t pulse_counter_saul_driver = { + .read = read_pulse_counter, + .write = write_pulse_counter, + .type = SAUL_SENSE_COUNT, +}; diff --git a/drivers/saul/saul_str.c b/drivers/saul/saul_str.c index 0a1006439..500a7f7ac 100644 --- a/drivers/saul/saul_str.c +++ b/drivers/saul/saul_str.c @@ -48,6 +48,7 @@ const char *saul_class_to_str(const uint8_t class_id) case SAUL_SENSE_PRESS: return "SENSE_PRESS"; case SAUL_SENSE_ANALOG: return "SENSE_ANALOG"; case SAUL_SENSE_OBJTEMP:return "SENSE_OBJTEMP"; + case SAUL_SENSE_COUNT: return "SENSE_PULSE_COUNT"; case SAUL_CLASS_ANY: return "CLASS_ANY"; default: return "CLASS_UNKNOWN"; }