From 0390561e06ece892aff8526c91f75e3603b2422a Mon Sep 17 00:00:00 2001
From: Hauke Petersen <hauke.petersen@fu-berlin.de>
Date: Wed, 18 Nov 2015 16:07:02 +0100
Subject: [PATCH] drivers: added S(ensor) A(ctuator) U(ber) L(ayer)

---
 Makefile.pseudomodules        |   2 +
 drivers/include/saul.h        | 157 ++++++++++++++++++++++++++++++++++
 drivers/include/saul/periph.h |  42 +++++++++
 drivers/saul/Makefile         |   7 ++
 drivers/saul/gpio_saul.c      |  49 +++++++++++
 drivers/saul/saul_str.c       |  52 +++++++++++
 6 files changed, 309 insertions(+)
 create mode 100644 drivers/include/saul.h
 create mode 100644 drivers/include/saul/periph.h
 create mode 100644 drivers/saul/Makefile
 create mode 100644 drivers/saul/gpio_saul.c
 create mode 100644 drivers/saul/saul_str.c

diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules
index 7567b1a783..ee9c6d12d8 100644
--- a/Makefile.pseudomodules
+++ b/Makefile.pseudomodules
@@ -19,6 +19,8 @@ PSEUDOMODULES += newlib
 PSEUDOMODULES += pktqueue
 PSEUDOMODULES += schedstatistics
 PSEUDOMODULES += netif
+PSEUDOMODULES += saul_default
+PSEUDOMODULES += saul_gpio
 
 # include variants of the AT86RF2xx drivers as pseudo modules
 PSEUDOMODULES += at86rf23%
diff --git a/drivers/include/saul.h b/drivers/include/saul.h
new file mode 100644
index 0000000000..f6a9dcc47a
--- /dev/null
+++ b/drivers/include/saul.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 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_saul [S]ensor [A]ctuator [U]ber [L]ayer
+ * @ingroup     drivers
+ * @brief       Generic sensor/actuator abstraction layer for RIOT
+ *
+ * SAUL is a generic actuator/sensor interface in RIOT. Its purpose is to
+ * enable unified interaction with a wide range of sensors and actuators through
+ * a set of defined access functions and a common data structure.
+ *
+ * Each device driver implementing this interface has to expose a set of
+ * predefined functions and it has to register itself to the central SAUL
+ * registry. From here devices can be found, listed, and accessed.
+ *
+ * Each device has further to expose a name and its type. This information can
+ * be used for automated searching and matching of devices (e.g. connect light
+ * sensor automatically with the color of an RGB LED...).
+ *
+ * The SAUL module enables further the automated initialization of preconfigured
+ * actuators/sensor via auto_init and the access to all available devices via
+ * one unified shell command.
+ *
+ * @todo        So far, the interface only supports simple read and set
+ *              operations. It probably needs to be extended to handling events,
+ *              thresholds, and so on.
+ *
+ * @{
+ *
+ * @file
+ * @brief       Definition of the generic [S]ensor [A]ctuator [U]ber [L]ayer
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ */
+
+#ifndef SAUL_H
+#define SAUL_H
+
+#include <stdint.h>
+
+#include "phydat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Definition of device classes
+ *
+ * This list contains a collections of available device classes. Each device
+ * must be part of one, but can be part of multiple of these classes. When
+ * belonging to more than one class, a device must however expose one driver
+ * for each class it belongs to, and it has to register each driver with a
+ * separate entry at the SAUL registry.
+ *
+ * Classes are identified by 8-bit unsigned integers.
+ *
+ * For searching and filtering purposes, the device classes are further split
+ * into two top-level classes: sensors and actuators. For identification, all
+ * actuator classes start with 0b01xxxxxx, all sensor classes start with
+ * 0b10xxxxxx.
+ *
+ * This list is not exhaustive, extend to your needs!
+ */
+enum {
+    SAUL_CLASS_UNDEF    = 0x00,     /**< device class undefined */
+    SAUL_ACT_ANY        = 0x40,     /**< any actuator - wildcard */
+    SAUL_ACT_LED_RGB    = 0x42,     /**< actuator: RGB LED */
+    SAUL_ACT_SERVO      = 0x43,     /**< actuator: servo motor */
+    SAUL_ACT_MOTOR      = 0x44,     /**< actuator: motor */
+    SAUL_ACT_SWITCH     = 0x45,     /**< actuator: simple on/off switch */
+    SAUL_ACT_DIMMER     = 0x46,     /**< actuator: dimmable switch */
+    SAUL_SENSE_ANY      = 0x80,     /**< any sensor - wildcart */
+    SAUL_SENSE_BTN      = 0x81,     /**< sensor: simple button */
+    SAUL_SENSE_TEMP     = 0x82,     /**< sensor: temperature */
+    SAUL_SENSE_HUM      = 0x83,     /**< sensor: humidity */
+    SAUL_SENSE_LIGHT    = 0x84,     /**< sensor: light */
+    SAUL_SENSE_ACCEL    = 0x85,     /**< sensor: accelerometer */
+    SAUL_SENSE_MAG      = 0x86,     /**< sensor: magnetometer */
+    SAUL_SENSE_GYRO     = 0x87,     /**< sensor: gyroscope */
+    SAUL_SENSE_COLOR    = 0x88,     /**< sensor: (light) color */
+    SAUL_SENSE_PRESS    = 0x89,     /**< sensor: pressure */
+    SAUL_SENSE_ANALOG   = 0x8a,     /**< sensor: raw analog value */
+    SAUL_CLASS_ANY      = 0xff      /**< any device - wildcard */
+    /* extend this list as needed... */
+};
+
+/**
+ * @brief   Read a value (a set of values) from a device
+ *
+ * Simple sensors, as e.g. a temperature sensor, will return exactly one value
+ * together with the values scale and unit. Some sensors might return a touple
+ * or triple of data (e.g. a 3-axis accelerometer).
+ *
+ * Actuators can chose to either just return -ENOTSUP or to return their current
+ * set value (e.g. useful for reading back the current state of a switch)
+ *
+ * @param[in] dev       device descriptor of the target device
+ * @param[out] res      data read from the device
+ *
+ * @return  number of values written into to result data structure [1-3]
+ * @return  -ENOTSUP if the device does not support this operation
+ * @return  -ECANCELED on other errors
+ */
+typedef int(*saul_read_t)(void *dev, phydat_t *res);
+
+/**
+ * @brief   Write a value (a set of values) to a device
+ *
+ * Most sensors will probably just return -ENOTSUP, as writing values to a
+ * sensor is often without purpose. The interface can however be used to
+ * configure sensors, e.g. to switch a sensor's unit type by writing the
+ * newly selected type to it.
+ *
+ * For actuators this function is used to influence the actuators state, e.g.
+ * switching a switch or setting the speed of a motor.
+ *
+ * @param[in] dev       device descriptor of the target device
+ * @param[in] data      data to write to the device
+ *
+ * @return  number of values actually processed by the device [1-3]
+ * @return  -ENOTSUP if the device does not support this operation
+ * @return  -ECANCELED on other errors
+ */
+typedef int(*saul_write_t)(void *dev, phydat_t *data);
+
+/**
+ * @brief   Definition of the RIOT actuator/sensor interface
+ */
+typedef struct {
+    saul_read_t read;       /**< read function pointer */
+    saul_write_t write;     /**< write function pointer */
+    uint8_t type;           /**< device class the device belongs to */
+} saul_driver_t;
+
+/**
+ * @brief   Helper function converts a class ID to a string
+ *
+ * @param[in] class_id      device class ID
+ *
+ * @return      string representation of the device class
+ * @return      NULL if class ID is not known
+ */
+const char *saul_class_to_str(uint8_t class_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SAUL_H */
+/** @} */
diff --git a/drivers/include/saul/periph.h b/drivers/include/saul/periph.h
new file mode 100644
index 0000000000..963c3fdfa8
--- /dev/null
+++ b/drivers/include/saul/periph.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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_saul
+ * @{
+ *
+ * @file
+ * @brief       Parameter definitions for mapping peripherals directly to SAUL
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ */
+
+#ifndef SAUL_PERIPH_H
+#define SAUL_PERIPH_H
+
+#include "periph/gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Direct mapped GPIO configuration values
+ */
+typedef struct {
+    const char *name;       /**< name of the device connected to this pin */
+    gpio_t pin;             /**< GPIO pin to initialize and expose */
+    gpio_dir_t dir;         /**< use GPIO as input or output */
+} saul_gpio_params_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SAUL_PERIPH_H */
+/** @} */
diff --git a/drivers/saul/Makefile b/drivers/saul/Makefile
new file mode 100644
index 0000000000..3247d1d8ac
--- /dev/null
+++ b/drivers/saul/Makefile
@@ -0,0 +1,7 @@
+SRC = saul_str.c
+
+ifneq (,$(filter saul_gpio,$(USEMODULE)))
+  SRC += gpio_saul.c
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/saul/gpio_saul.c b/drivers/saul/gpio_saul.c
new file mode 100644
index 0000000000..62217e7290
--- /dev/null
+++ b/drivers/saul/gpio_saul.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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_saul
+ * @{
+ *
+ * @file
+ * @brief       SAUL wrapper for direct access to GPIO pins
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <string.h>
+
+#include "saul.h"
+#include "phydat.h"
+#include "periph/gpio.h"
+
+
+static int read(void *dev, phydat_t *res)
+{
+    gpio_t pin = *((gpio_t *)dev);
+    res->val[0] = (gpio_read(pin)) ? 1 : 0;
+    memset(&(res->val[1]), 0, 2 * sizeof(int16_t));
+    res->unit = UNIT_BOOL;
+    res->scale = 0;
+    return 1;
+}
+
+static int write(void *dev, phydat_t *state)
+{
+    gpio_t pin = *((gpio_t *)dev);
+    gpio_write(pin, state->val[0]);
+    return 1;
+}
+
+const saul_driver_t gpio_saul_driver = {
+    .read = read,
+    .write = write,
+    .type = SAUL_ACT_SWITCH,
+};
diff --git a/drivers/saul/saul_str.c b/drivers/saul/saul_str.c
new file mode 100644
index 0000000000..fb9b5d9ce7
--- /dev/null
+++ b/drivers/saul/saul_str.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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_saul
+ * @{
+ *
+ * @file
+ * @brief       SAUL string functions
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+
+#include "saul.h"
+
+/*
+ * This is surely not the most beautiful implementation of a stringification
+ * function, but works...
+ */
+const char *saul_class_to_str(uint8_t class_id)
+{
+    switch (class_id) {
+        case SAUL_CLASS_UNDEF:  return "CLASS_UNDEF";
+        case SAUL_ACT_ANY:      return "ACT_ANY";
+        case SAUL_ACT_LED_RGB:  return "ACT_LED_RGB";
+        case SAUL_ACT_SERVO:    return "ACT_SERVO";
+        case SAUL_ACT_MOTOR:    return "ACT_MOTOR";
+        case SAUL_ACT_SWITCH:   return "ACT_SWITCH";
+        case SAUL_ACT_DIMMER:   return "ACT_DIMMER";
+        case SAUL_SENSE_ANY:    return "SENSE_ANY";
+        case SAUL_SENSE_BTN:    return "SENSE_BTN";
+        case SAUL_SENSE_TEMP:   return "SENSE_TEMP";
+        case SAUL_SENSE_HUM:    return "SENSE_HUM";
+        case SAUL_SENSE_LIGHT:  return "SENSE_LIGHT";
+        case SAUL_SENSE_ACCEL:  return "SENSE_ACCEL";
+        case SAUL_SENSE_MAG:    return "SENSE_MAG";
+        case SAUL_SENSE_GYRO:   return "SENSE_GYRO";
+        case SAUL_SENSE_COLOR:  return "SENSE_COLOR";
+        case SAUL_SENSE_PRESS:  return "SENSE_PRESS";
+        case SAUL_CLASS_ANY:    return "CLASS_ANY";
+        default:                return "CLASS_UNKNOWN";
+    }
+}
-- 
GitLab