From 7ea8f738fdbf07f9aa6550585b7c6219839ca9a3 Mon Sep 17 00:00:00 2001 From: Viktor Gal Date: Wed, 23 Sep 2020 17:35:33 +0200 Subject: [PATCH] Add support for Adafruit Seesaw Soil moisture sensor (#14835) drivers/seesaw_soil: Add support for Adafruit Seesaw Soil moisture sensor --- drivers/include/seesaw_soil.h | 119 ++++++++++++++++++ .../saul/init_devs/auto_init_seesaw_soil.c | 74 +++++++++++ drivers/saul/init_devs/init.c | 4 + drivers/seesaw_soil/Kconfig | 23 ++++ drivers/seesaw_soil/Makefile | 1 + drivers/seesaw_soil/Makefile.dep | 2 + drivers/seesaw_soil/Makefile.include | 2 + .../seesaw_soil/include/seesaw_soil_params.h | 71 +++++++++++ .../seesaw_soil/include/seesaw_soil_regs.h | 49 ++++++++ drivers/seesaw_soil/seesaw_soil.c | 119 ++++++++++++++++++ drivers/seesaw_soil/seesaw_soil_saul.c | 43 +++++++ tests/driver_seesaw_soil/Makefile | 7 ++ tests/driver_seesaw_soil/README.md | 6 + tests/driver_seesaw_soil/main.c | 64 ++++++++++ 14 files changed, 584 insertions(+) create mode 100644 drivers/include/seesaw_soil.h create mode 100644 drivers/saul/init_devs/auto_init_seesaw_soil.c create mode 100644 drivers/seesaw_soil/Kconfig create mode 100644 drivers/seesaw_soil/Makefile create mode 100644 drivers/seesaw_soil/Makefile.dep create mode 100644 drivers/seesaw_soil/Makefile.include create mode 100644 drivers/seesaw_soil/include/seesaw_soil_params.h create mode 100644 drivers/seesaw_soil/include/seesaw_soil_regs.h create mode 100644 drivers/seesaw_soil/seesaw_soil.c create mode 100644 drivers/seesaw_soil/seesaw_soil_saul.c create mode 100644 tests/driver_seesaw_soil/Makefile create mode 100644 tests/driver_seesaw_soil/README.md create mode 100644 tests/driver_seesaw_soil/main.c diff --git a/drivers/include/seesaw_soil.h b/drivers/include/seesaw_soil.h new file mode 100644 index 0000000000..62c84b6afb --- /dev/null +++ b/drivers/include/seesaw_soil.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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_seesaw_soil Adafruit Seesaw Soil Moisture and Temperature Sensor + * @ingroup drivers_sensors + * @ingroup drivers_saul + * @brief Driver for the Adafruit Seesaw Soil Moisture and Temperature Sensor + * + * + * This driver provides @ref drivers_saul capabilities. + * + * @{ + * + * @file + * @brief Interface definition for the Adafruit Seesaw Soil sensor. + * + * @author Viktor Gal + */ + +#ifndef SEESAW_SOIL_H +#define SEESAW_SOIL_H + +#include + +#include "periph/i2c.h" +#include "seesaw_soil_regs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @defgroup drivers_seesaw_soil_config Adafruit Seesaw Soil Moisture and Temperature Sensor driver compile configuration + * @ingroup config_drivers_sensors + * @{ + */ +/** + * @brief Default I2C bus address of Adafruit Seesaw Soil devices + * + * The address value depends on the state of AD0 and AD1 Pins + */ +#ifndef CONFIG_SEESAW_SOIL_I2C_ADDRESS +#define CONFIG_SEESAW_SOIL_I2C_ADDRESS (0x36) +#endif +/** @} */ + +/** + * @brief Seesaw Soil specific return values + */ +enum { + SEESAW_SOIL_OK = 0, /**< everything went as expected */ + SEESAW_SOIL_NODEV = -1, /**< no SEESAW_SOIL device found on the bus */ + SEESAW_SOIL_NOBUS = -2, /**< errors while initializing the I2C bus */ + SEESAW_SOIL_BUSERR = -3 /**< error during I2C communication */ +}; + +/** + * @brief Parameters needed for device initialization + */ +typedef struct { + i2c_t i2c; /**< bus the device is connected to */ + uint8_t addr; /**< address on that bus */ +} seesaw_soil_params_t; + +/** + * @brief Device descriptor for Seesaw Soil sensors + */ +typedef struct { + seesaw_soil_params_t params; /**< Configuration parameters */ +} seesaw_soil_t; + +/** + * @brief Initialize the given Seesaw Soil device + * + * @param[out] dev device descriptor of sensor to initialize + * @param[in] params configuration parameters + * + * @return SEESAW_SOIL_OK on success + * @return SEESAW_SOIL_NOBUS if initialization of I2C bus fails + * @return SEESAW_SOIL_NODEV if no Seesaw Soil device found on bus + */ +int seesaw_soil_init(seesaw_soil_t *dev, const seesaw_soil_params_t *params); + +/** + * @brief Convenience function for reading temperature + * + * @param[in] dev device descriptor of sensor + * @param[out] temp temperature [in 100 * degree centigrade] + * + * @return SEESAW_SOIL_OK on success + * @return SEESAW_SOIL_BUSERR on I2C communication failures + */ +int seesaw_soil_temperature(const seesaw_soil_t *dev, int16_t *temp); + +/** + * @brief Convenience function for reading ca + * + * @param[in] dev device descriptor of sensor + * @param[out] moist moisture using capacitive measurement. + * Value is ranging from 200 (very dry) to 2000 (very wet). + * + * @return SEESAW_SOIL_OK on success + * @return SEESAW_SOIL_BUSERR on I2C communication failures + */ +int seesaw_soil_moisture(const seesaw_soil_t *dev, uint16_t *moist); + +#ifdef __cplusplus +} +#endif + +#endif /* SEESAW_SOIL_H */ +/** @} */ diff --git a/drivers/saul/init_devs/auto_init_seesaw_soil.c b/drivers/saul/init_devs/auto_init_seesaw_soil.c new file mode 100644 index 0000000000..e7dc50cafe --- /dev/null +++ b/drivers/saul/init_devs/auto_init_seesaw_soil.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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 sys_auto_init_saul + * @{ + * + * @file + * @brief Auto initialization for Adafruit Seesaw Soil devices + * + * @author Viktor Gal + * + * @} + */ + +#include "assert.h" +#include "log.h" +#include "saul_reg.h" +#include "seesaw_soil.h" +#include "seesaw_soil_params.h" + +/** + * @brief Define the number of configured sensors + */ +#define SEESAW_SOIL_NUM ARRAY_SIZE(seesaw_soil_params) + +/** + * @brief Allocate memory for the device descriptors + */ +static seesaw_soil_t seesaw_soil_devs[SEESAW_SOIL_NUM]; + +/** + * @brief Memory for the SAUL registry entries + */ +static saul_reg_t saul_entries[SEESAW_SOIL_NUM]; + +/** + * @brief Define the number of saul info + */ +#define SEESAW_SOIL_INFO_NUM ARRAY_SIZE(seesaw_soil_saul_info) + +/** + * @name Reference the driver struct + * @{ + */ +extern saul_driver_t seesaw_soil_saul_temp_driver; +/** @} */ + + +void auto_init_seesaw_soil(void) +{ + assert(SEESAW_SOIL_NUM == SEESAW_SOIL_INFO_NUM); + + for (unsigned i = 0; i < SEESAW_SOIL_NUM; i++) { + LOG_DEBUG("[auto_init_saul] initializing seesaw_soil #%u\n", i); + + int res = seesaw_soil_init(&seesaw_soil_devs[i], &seesaw_soil_params[i]); + if (res < 0) { + LOG_ERROR("[auto_init_saul] error initializing seesaw_soil #%u\n", i); + continue; + } + + saul_entries[i].dev = &(seesaw_soil_devs[i]); + saul_entries[i].name = seesaw_soil_saul_info[i].name; + saul_entries[i].driver = &seesaw_soil_saul_temp_driver; + saul_reg_add(&(saul_entries[i])); + } +} diff --git a/drivers/saul/init_devs/init.c b/drivers/saul/init_devs/init.c index 8f745d6871..db50b81e85 100644 --- a/drivers/saul/init_devs/init.c +++ b/drivers/saul/init_devs/init.c @@ -227,6 +227,10 @@ void saul_init_devs(void) extern void auto_init_sdp3x(void); auto_init_sdp3x(); } + if (IS_USED(MODULE_SEESAW_SOIL)) { + extern void auto_init_seesaw_soil(void); + auto_init_seesaw_soil(); + } if (IS_USED(MODULE_SHT3X)) { extern void auto_init_sht3x(void); auto_init_sht3x(); diff --git a/drivers/seesaw_soil/Kconfig b/drivers/seesaw_soil/Kconfig new file mode 100644 index 0000000000..920487a604 --- /dev/null +++ b/drivers/seesaw_soil/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2020 Viktor Gal +# +# 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. +# +menuconfig KCONFIG_MODULE_SEESAW_SOIL + bool "Configure SEESAW_SOIL driver" + depends on MODULE_SEESAW_SOIL + help + Configure the SEESAW_SOIL driver using Kconfig. + +if KCONFIG_MODULE_SEESAW_SOIL + +config SEESAW_SOIL_I2C_ADDRESS + hex "I2C default address" + range 0x36 0x39 + default 0x36 + help + SEESAW_SOIL allows for up to 4 devices on single bus. The value depends on + the state of AD1 and AD0 pins. + +endif # KCONFIG_MODULE_SEESAW_SOIL diff --git a/drivers/seesaw_soil/Makefile b/drivers/seesaw_soil/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/seesaw_soil/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/seesaw_soil/Makefile.dep b/drivers/seesaw_soil/Makefile.dep new file mode 100644 index 0000000000..095389d9a5 --- /dev/null +++ b/drivers/seesaw_soil/Makefile.dep @@ -0,0 +1,2 @@ +USEMODULE += xtimer +FEATURES_REQUIRED += periph_i2c diff --git a/drivers/seesaw_soil/Makefile.include b/drivers/seesaw_soil/Makefile.include new file mode 100644 index 0000000000..0dc7399911 --- /dev/null +++ b/drivers/seesaw_soil/Makefile.include @@ -0,0 +1,2 @@ +USEMODULE_INCLUDES_seesaw_soil := $(LAST_MAKEFILEDIR)/include +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_seesaw_soil) diff --git a/drivers/seesaw_soil/include/seesaw_soil_params.h b/drivers/seesaw_soil/include/seesaw_soil_params.h new file mode 100644 index 0000000000..6f8ba2fe78 --- /dev/null +++ b/drivers/seesaw_soil/include/seesaw_soil_params.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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_seesaw_soil + * + * @{ + * @file + * @brief Default configuration for Seesaw Soil devices + * + * @author Viktor Gal + */ + +#ifndef SEESAW_SOIL_PARAMS_H +#define SEESAW_SOIL_PARAMS_H + +#include "board.h" +#include "seesaw_soil.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for the SEESAW_SOIL driver + * @{ + */ +#ifndef SEESAW_SOIL_PARAM_I2C +#define SEESAW_SOIL_PARAM_I2C I2C_DEV(0) +#endif +#ifndef SEESAW_SOIL_PARAM_ADDR +#define SEESAW_SOIL_PARAM_ADDR (CONFIG_SEESAW_SOIL_I2C_ADDRESS) +#endif + +#ifndef SEESAW_SOIL_PARAMS +#define SEESAW_SOIL_PARAMS { .i2c = SEESAW_SOIL_PARAM_I2C, \ + .addr = SEESAW_SOIL_PARAM_ADDR } +#endif +#ifndef SEESAW_SOIL_SAUL_INFO +#define SEESAW_SOIL_SAUL_INFO { .name = "seesaw_soil" } +#endif +/**@}*/ + +/** + * @brief Seesaw Soil configuration + */ +static const seesaw_soil_params_t seesaw_soil_params[] = +{ + SEESAW_SOIL_PARAMS +}; + +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t seesaw_soil_saul_info[] = +{ + SEESAW_SOIL_SAUL_INFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* SEESAW_SOIL_PARAMS_H */ +/** @} */ diff --git a/drivers/seesaw_soil/include/seesaw_soil_regs.h b/drivers/seesaw_soil/include/seesaw_soil_regs.h new file mode 100644 index 0000000000..a884a706da --- /dev/null +++ b/drivers/seesaw_soil/include/seesaw_soil_regs.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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_seesaw_soil + * @{ + * + * @file + * @brief Register definitions for Seesaw Soil devices + * + * @author Viktor Gal + */ + +#ifndef SEESAW_SOIL_REGS_H +#define SEESAW_SOIL_REGS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @name Manufacturer ID + * @{ + */ +#define SEESAW_SOIL_MID_VALUE 0x55 +/** @} */ + +/** + * @name Register Map + * @{ + */ +#define SEESAW_SOIL_MANUFACTURER_ID (0x01) +#define SEESAW_SOIL_TEMPERATURE (0x04) +#define SEESAW_SOIL_MOISTURE (0x0F10) +#define SEESAW_SOIL_RST (0x7F) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* SEESAW_SOIL_REGS_H */ +/** @} */ diff --git a/drivers/seesaw_soil/seesaw_soil.c b/drivers/seesaw_soil/seesaw_soil.c new file mode 100644 index 0000000000..d867a69091 --- /dev/null +++ b/drivers/seesaw_soil/seesaw_soil.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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_seesaw_soil + * @{ + * + * @file + * @brief Driver for the Adafruit Seesaw Soil Moisture and Temperature Sensor. + * + * @author Viktor Gal + * + * @} + */ + +#include + +#include "assert.h" +#include "byteorder.h" +#include "xtimer.h" +#include "periph/i2c.h" +#include "seesaw_soil.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static int _seesaw_read_regs(const seesaw_soil_t *dev, uint16_t reg_addr, void* data, size_t len) { + int r; + + reg_addr = htons(reg_addr); + /* send the 16bit register address we want to read with STOP bit */ + if ((r = i2c_write_bytes(dev->params.i2c, dev->params.addr, + ®_addr, 2, 0)) < 0) { + return r; + } + + /* wait for the answer */ + xtimer_usleep(5000); + + /* and now we read the register value */ + if ((r = i2c_read_bytes(dev->params.i2c, dev->params.addr, + data, len, 0)) < 0) { + return r; + } + + return r; +} + +static int _seesaw_read_reg(seesaw_soil_t *dev, uint16_t reg_addr, void* data) { + return _seesaw_read_regs(dev, reg_addr, data, 1); +} + +int seesaw_soil_init(seesaw_soil_t *dev, const seesaw_soil_params_t *params) +{ + uint8_t reg; + + /* write device descriptor */ + dev->params = *params; + + DEBUG("[SEESAW SOIL] Initializing seesaw soil device.\n"); + /* try if we can interact with the device by reading its manufacturer ID */ + i2c_acquire(dev->params.i2c); + if (_seesaw_read_reg(dev, SEESAW_SOIL_MANUFACTURER_ID, ®) < 0) { + DEBUG("[SEESAW SOIL] Could not read manufacture id.\n"); + i2c_release(dev->params.i2c); + return SEESAW_SOIL_NOBUS; + } + + if (reg != SEESAW_SOIL_MID_VALUE) { + DEBUG("[SEESAW SOIL] Wrong manufacture id: %x\n", reg); + i2c_release(dev->params.i2c); + return SEESAW_SOIL_NODEV; + } + i2c_release(dev->params.i2c); + + /* all set */ + return SEESAW_SOIL_OK; +} + +int seesaw_soil_temperature(const seesaw_soil_t *dev, int16_t *temp) +{ + int status = SEESAW_SOIL_OK; + uint32_t raw_temp; + + i2c_acquire(dev->params.i2c); + if (_seesaw_read_regs(dev, SEESAW_SOIL_TEMPERATURE, &raw_temp, sizeof(raw_temp)) < 0) { + status = SEESAW_SOIL_BUSERR; + } + i2c_release(dev->params.i2c); + + if (temp && (status == SEESAW_SOIL_OK)) { + *temp = (ntohl(raw_temp) * 100) >> 16; + } + + return status; +} + +int seesaw_soil_moisture(const seesaw_soil_t *dev, uint16_t *moist) +{ + int status = SEESAW_SOIL_OK; + uint16_t raw_moist; + + i2c_acquire(dev->params.i2c); + if (_seesaw_read_regs(dev, SEESAW_SOIL_MOISTURE, &raw_moist, 2) < 0) { + status = SEESAW_SOIL_BUSERR; + } + i2c_release(dev->params.i2c); + + if (moist && (status == SEESAW_SOIL_OK)) { + *moist = ntohs(raw_moist); + } + return status; +} diff --git a/drivers/seesaw_soil/seesaw_soil_saul.c b/drivers/seesaw_soil/seesaw_soil_saul.c new file mode 100644 index 0000000000..7dd2732441 --- /dev/null +++ b/drivers/seesaw_soil/seesaw_soil_saul.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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_seesaw_soil + * @{ + * + * @file + * @brief Seesaw Soil adaption to the RIOT actuator/sensor interface + * + * @author Viktor Gal + * + * @} + */ + +#include + +#include "saul.h" +#include "seesaw_soil.h" + +static int read_temp(const void *dev, phydat_t *res) +{ + if (seesaw_soil_temperature((const seesaw_soil_t *)dev, &(res->val[0])) != SEESAW_SOIL_OK) { + return -ECANCELED; + } + res->val[1] = 0; + res->val[2] = 0; + res->unit = UNIT_TEMP_C; + res->scale = -2; + + return 1; +} + +const saul_driver_t seesaw_soil_saul_temp_driver = { + .read = read_temp, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP, +}; diff --git a/tests/driver_seesaw_soil/Makefile b/tests/driver_seesaw_soil/Makefile new file mode 100644 index 0000000000..3a977ee3e7 --- /dev/null +++ b/tests/driver_seesaw_soil/Makefile @@ -0,0 +1,7 @@ +include ../Makefile.tests_common + +USEMODULE += seesaw_soil +USEMODULE += xtimer +USEMODULE += fmt + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_seesaw_soil/README.md b/tests/driver_seesaw_soil/README.md new file mode 100644 index 0000000000..4c5d86ecf1 --- /dev/null +++ b/tests/driver_seesaw_soil/README.md @@ -0,0 +1,6 @@ +# About +This is a manual test application for the Adafruit Seesaw Soil driver. + +# Usage +After initialization, the sensor reads the temperature and moisture values every +second and prints them to STDOUT. diff --git a/tests/driver_seesaw_soil/main.c b/tests/driver_seesaw_soil/main.c new file mode 100644 index 0000000000..1662958ee1 --- /dev/null +++ b/tests/driver_seesaw_soil/main.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Viktor Gal + * + * 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 tests + * @{ + * + * @file + * @brief Test application for the Adafruit Seesaw Soil sensor driver + * + * @author Viktor Gal + * + * @} + */ + +#include + +#include "fmt.h" +#include "xtimer.h" +#include "seesaw_soil.h" +#include "seesaw_soil_params.h" + +#define SLEEP_USEC (1000 * 1000U) + +int main(void) +{ + seesaw_soil_t dev; + int16_t temp; + uint16_t moist; + char tstr[8]; + char mstr[8]; + + puts("Seesaw Soil Temperature and Moisture Sensor driver test application\n"); + printf("Initializing Seesaw Soil sensor at I2C_DEV(%i)... ", + (int)seesaw_soil_params[0].i2c); + if (seesaw_soil_init(&dev, &seesaw_soil_params[0]) == SEESAW_SOIL_OK) { + puts("[OK]\n"); + } + else { + puts("[Failed]"); + return 1; + } + + while (1) { + size_t len; + seesaw_soil_temperature(&dev, &temp); + seesaw_soil_moisture(&dev, &moist); + + len = fmt_s16_dfp(tstr, temp, -2); + tstr[len] = '\0'; + len = fmt_u16_dec(mstr, moist); + mstr[len] = '\0'; + printf("Reading: T: %s °C Moist: %s\n", tstr, mstr); + + xtimer_usleep(SLEEP_USEC); + } + + return 0; +}