From b24de4a22a6f98c7bac3afa915e0a1b2246c6404 Mon Sep 17 00:00:00 2001
From: Semjon Kerner <semjon.kerner@fu-berlin.de>
Date: Thu, 20 Sep 2018 13:00:57 +0200
Subject: [PATCH] drivers/srf04: initial driver implementation

---
 drivers/Makefile.dep                 |   6 ++
 drivers/Makefile.include             |   4 +
 drivers/include/srf04.h              | 110 +++++++++++++++++++++++++++
 drivers/srf04/Makefile               |   1 +
 drivers/srf04/include/srf04_params.h |  62 +++++++++++++++
 drivers/srf04/srf04.c                |  95 +++++++++++++++++++++++
 6 files changed, 278 insertions(+)
 create mode 100644 drivers/include/srf04.h
 create mode 100644 drivers/srf04/Makefile
 create mode 100644 drivers/srf04/include/srf04_params.h
 create mode 100644 drivers/srf04/srf04.c

diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index cf30a71667..e5a0c9991d 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -405,6 +405,12 @@ ifneq (,$(filter srf02,$(USEMODULE)))
   USEMODULE += xtimer
 endif
 
+ifneq (,$(filter srf04,$(USEMODULE)))
+  USEMODULE += xtimer
+  FEATURES_REQUIRED += periph_gpio
+  FEATURES_REQUIRED += periph_gpio_irq
+endif
+
 ifneq (,$(filter srf08,$(USEMODULE)))
   FEATURES_REQUIRED += periph_i2c
   USEMODULE += xtimer
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index 11cc60b374..83c994ef37 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -222,6 +222,10 @@ ifneq (,$(filter soft_spi,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/soft_spi/include
 endif
 
+ifneq (,$(filter srf04,$(USEMODULE)))
+  USEMODULE_INCLUDES += $(RIOTBASE)/drivers/srf04/include
+endif
+
 ifneq (,$(filter sx127x,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include
 endif
diff --git a/drivers/include/srf04.h b/drivers/include/srf04.h
new file mode 100644
index 0000000000..3856b34f0f
--- /dev/null
+++ b/drivers/include/srf04.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Freie Universität Berlin
+ *
+ * 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_srf04 srf04 ultra sonic range finder
+ * @ingroup     drivers_sensors
+ * @brief       Device driver for the srf04 ultra sonic range finder
+ * @{
+ *
+ * @file
+ * @brief       Device driver for the srf04 ultra sonic range finder
+ *
+ * @author      Semjon Kerner <semjon.kerner@fu-berlin.de>
+ */
+
+#ifndef SRF04_H
+#define SRF04_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "periph/gpio.h"
+#include "xtimer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Status and error return codes
+ */
+enum {
+    SRF04_OK            =  0,   /**< exit without error */
+    SRF04_ERR_INVALID   = -1,   /**< error no valid measurement available*/
+    SRF04_ERR_MEASURING = -2,   /**< error sensor is measuring*/
+    SRF04_ERR_GPIO      = -3,   /**< error initializing gpio*/
+};
+
+/**
+ * @brief   GPIO pins for srf04 device
+ */
+typedef struct {
+    gpio_t trigger;     /**< GPIO Port the trigger pin is connected to */
+    gpio_t echo;        /**< GPIO Port the echo pin is connected to */
+} srf04_params_t;
+
+/**
+ * @brief   Device descriptor for srf04 sensor
+ */
+typedef struct {
+    srf04_params_t p;   /**< GPIO Ports of device */
+    int distance;       /**< raw time of flight distance */
+    uint32_t time;      /**< timestamp of trigger or echo */
+} srf04_t;
+
+/**
+ * @brief   Initialize gpio and interrupt
+ *
+ * @param[out] dev      device descriptor of sensor to initialize
+ * @param[in] params    init param struct holding gpio trigger and echo pins
+ *
+ * @return              SRF04_OK on success
+ * @return              SRF04_GPIO on gpio init failure
+ */
+int srf04_init(srf04_t *dev, const srf04_params_t *params);
+
+/**
+ * @brief   Triggers measurement
+ *
+ * @param[in]  dev      device descriptor of sensor
+ */
+void srf04_trigger(const srf04_t *dev);
+
+/**
+ * @brief   Returns time of flight in ms
+ *
+ * @note    should not be invoked within 50 ms after triggering
+ *
+ * @param[in]  dev      device descriptor of sensor
+ *
+ * @return              time of flight in ms
+ * @return              SRF04_MEASURING if measurement is in progress
+ * @return              SRF04_INVALID if no valid measurement is available
+ */
+int srf04_read(const srf04_t* dev);
+
+/**
+ * @brief   Convenience function triggers a measurement and returns distance
+ *
+ * @note    This function will return after 50 ms once new data is available
+ *
+ * @param[in]  dev      device descriptor of sensor
+ *
+ * @return              time of flight in mm
+ * @return              SRF04_MEASURING if measurement is in progress
+ * @return              SRF04_INVALID if no valid measurement is available
+ */
+int srf04_get_distance(const srf04_t* dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SRF04_H */
+/** @} */
diff --git a/drivers/srf04/Makefile b/drivers/srf04/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/drivers/srf04/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/srf04/include/srf04_params.h b/drivers/srf04/include/srf04_params.h
new file mode 100644
index 0000000000..fddcfd046d
--- /dev/null
+++ b/drivers/srf04/include/srf04_params.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 Freie Universität Berlin
+ *
+ * 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_srf04
+ *
+ * @{
+ * @file
+ * @brief       Default configuration for srf04 devices
+ *
+ * @author      Semjon Kerner <semjon.kerner@fu-berlin.de>
+ */
+
+#ifndef SRF04_PARAMS_H
+#define SRF04_PARAMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "board.h"
+#include "srf04.h"
+
+/**
+ * @name   Default configuration parameters for SRF04 device
+ * @{
+ */
+#ifndef SRF04_PARAM_TRIGGER
+#define SRF04_PARAM_TRIGGER     GPIO_PIN(0,13)
+#endif
+#ifndef SRF04_PARAM_ECHO
+#define SRF04_PARAM_ECHO        GPIO_PIN(0,14)
+#endif
+
+#ifndef SRF04_PARAMS
+#define SRF04_PARAMS                            \
+    {   .trigger        = SRF04_PARAM_TRIGGER,  \
+        .echo           = SRF04_PARAM_ECHO,     \
+    }
+#endif
+/** @} */
+
+/**
+ * @brief   SRF04 configuration
+ */
+static const srf04_params_t srf04_params[] = {
+    SRF04_PARAMS
+};
+
+#define SRF04_NUMOF     (sizeof(srf04_params) / sizeof(srf04_params[0]))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SRF04_PARAMS_H */
+/** @} */
diff --git a/drivers/srf04/srf04.c b/drivers/srf04/srf04.c
new file mode 100644
index 0000000000..d828ed7d85
--- /dev/null
+++ b/drivers/srf04/srf04.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 Freie Universität Berlin
+ *
+ * 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_srf04
+ * @{
+ *
+ * @file
+ * @brief       driver for srf04 ultra sonic range finder
+ *
+ * @author      Semjon Kerner <semjon.kerner@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include "srf04.h"
+#include "srf04_params.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#define SRF04_DISTANCE  (584U)
+#define SRF04_SAMPLE_PERIOD (50U * US_PER_MS)
+
+static void _cb(void *arg)
+{
+    uint32_t t = xtimer_now_usec();
+
+    srf04_t* dev = (srf04_t*)arg;
+    if (dev->distance > SRF04_ERR_MEASURING) {
+        dev->distance = SRF04_ERR_MEASURING;
+        dev->time = t;
+    } else {
+        gpio_irq_disable(dev->p.echo);
+        dev->distance = (t - dev->time);
+    }
+}
+
+int srf04_init(srf04_t* dev, const srf04_params_t *params)
+{
+    dev->p = *params;
+
+    dev->distance = SRF04_ERR_INVALID;
+    dev->time = 0;
+
+    if (gpio_init(dev->p.trigger, GPIO_OUT) != 0) {
+        DEBUG("[srf04] Error: could not initialize GPIO trigger pin\n");
+        return SRF04_ERR_GPIO;
+    }
+
+    if (gpio_init_int(dev->p.echo, GPIO_IN, GPIO_BOTH, _cb, (void*)dev) != 0) {
+        DEBUG("[srf04] Error: could not initialize GPIO echo pin\n");
+        return SRF04_ERR_GPIO;
+    }
+
+    gpio_irq_disable(dev->p.echo);
+
+    return SRF04_OK;
+}
+
+void srf04_trigger(const srf04_t* dev)
+{
+    if (dev->distance == SRF04_ERR_MEASURING) {
+        return;
+    }
+
+    gpio_irq_enable(dev->p.echo);
+
+    gpio_set(dev->p.trigger);
+    xtimer_usleep(10);
+    gpio_clear(dev->p.trigger);
+}
+
+int srf04_read(const srf04_t* dev)
+{
+    return dev->distance;
+}
+
+int srf04_get_distance(const srf04_t* dev)
+{
+    /* trigger new reading */
+    srf04_trigger(dev);
+    /* give the sensor the required time for sampling */
+    xtimer_usleep(SRF04_SAMPLE_PERIOD);
+    /* get the result */
+    if (dev->distance >= SRF04_OK) {
+        return ((dev->distance * 100) / SRF04_DISTANCE);
+    }
+    return dev->distance;
+}
-- 
GitLab