1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/sps30: add saul integration

This commit is contained in:
Michel Rottleuthner 2020-02-03 17:24:52 +01:00
parent 36fca364f8
commit 7e089bce7b
5 changed files with 283 additions and 1 deletions

View File

@ -9,6 +9,7 @@
/**
* @defgroup drivers_sps30 Sensirion SPS30 Particulate Matter Sensor
* @ingroup drivers_sensors
* @ingroup drivers_saul
*
* About
* =====

View File

@ -19,6 +19,7 @@
#include "board.h"
#include "sps30.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
@ -31,7 +32,6 @@ extern "C" {
#ifndef SPS30_PARAM_I2C_DEV
#define SPS30_PARAM_I2C_DEV (I2C_DEV(0))
#endif
#ifndef SPS30_PARAMS
#define SPS30_PARAMS { .i2c_dev = SPS30_PARAM_I2C_DEV }
#endif
@ -53,6 +53,19 @@ static const sps30_params_t sps30_params[] =
*/
#define SPS30_NUM ARRAY_SIZE(sps30_params)
/**
* @brief Additional meta information to keep in the SAUL registry
*/
static const saul_reg_info_t sps30_saul_info[] =
{
SPS30_SAUL_INFO
};
/**
* @brief Number of saul info structs
*/
#define SPS30_INFO_NUM ARRAY_SIZE(sps30_saul_info)
#ifdef __cplusplus
}
#endif

185
drivers/sps30/sps30_saul.c Normal file
View File

@ -0,0 +1,185 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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_sps30
* @brief SAUL adaption for Sensirion SPS30 sensor
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
* @file
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "phydat.h"
#include "saul.h"
#include "sps30.h"
#include "sps30_params.h"
/**
* @brief Mapping of sensor values to logical SAUL instances
*/
#define SPS30_SAUL_VAL_IDX_MC_PM_1_2P5_4 (0)
#define SPS30_SAUL_VAL_IDX_MC_PM_10 (1)
#define SPS30_SAUL_VAL_IDX_NC_PM_0P5_1_2P5 (2)
#define SPS30_SAUL_VAL_IDX_NC_PM_4_10 (3)
#define SPS30_SAUL_VAL_IDX_PS (4)
/**
* @brief Number of logical saul devices per physical sensor
*/
#define SPS30_SAUL_DEV_NUM (SPS30_SAUL_VAL_IDX_PS + 1)
extern sps30_t sps30_devs[SPS30_NUM];
/* contains a temporary copy of all sensor readings to allow returning all
* values as one consistent group over multiple read calls */
static sps30_data_t _readings[SPS30_NUM];
static bool _valid[SPS30_NUM][SPS30_SAUL_DEV_NUM] = { {false} };
static unsigned _dev2index (const sps30_t *dev)
{
for (unsigned i = 0; i < SPS30_NUM; i++) {
if (dev == &sps30_devs[i]) {
return i;
}
}
return SPS30_NUM;
}
static void _float_fit(float *src, phydat_t *data, size_t dim, uint32_t mul)
{
int32_t i32[dim];
for (unsigned i = 0; i < dim; i++) {
i32[i] = src[i] * mul;
}
data->scale = 0;
phydat_fit(data, &i32[0], dim);
}
static int read(const void *dev, phydat_t *data, unsigned int val_idx)
{
/* find the device index */
unsigned dev_idx = _dev2index((sps30_t*)dev);
if (dev_idx == SPS30_NUM) {
return -ECANCELED;
}
/* if data isn't valid form the last reading anymore, read again */
if (!_valid[dev_idx][val_idx]) {
int error_state = SPS30_OK;
while (!sps30_data_ready(&sps30_devs[dev_idx], &error_state)) {
if (error_state != SPS30_OK) {
return -ECANCELED;
}
}
if (!(sps30_read_measurement(&sps30_devs[dev_idx],
&_readings[dev_idx]) == SPS30_OK)) {
/* failure on read may corrupt _readings -> mark invalid */
for (unsigned i = 0; i < SPS30_SAUL_DEV_NUM; i++) {
_valid[dev_idx][i] = false;
}
return -ECANCELED;
}
for (unsigned i = 0; i < SPS30_SAUL_DEV_NUM; i++) {
_valid[dev_idx][i] = true;
}
}
/* mark read values as invalid */
_valid[dev_idx][val_idx] = false;
switch (val_idx) {
case SPS30_SAUL_VAL_IDX_MC_PM_1_2P5_4:
_float_fit(&_readings[dev_idx].mc_pm1, data, 3, 1000);
data->unit = UNIT_GPM3;
data->scale -= 9; /* fitted [ng/m^3] but unit is [g/m^3] */
return 3;
case SPS30_SAUL_VAL_IDX_MC_PM_10:
_float_fit(&_readings[dev_idx].mc_pm10, data, 1, 1000);
data->unit = UNIT_GPM3;
data->scale = -9; /* fitted [ng/m^3] but unit is [g/m^3] */
return 1;
case SPS30_SAUL_VAL_IDX_NC_PM_0P5_1_2P5:
_float_fit(&_readings[dev_idx].nc_pm0_5, data, 3, 1000);
data->unit = UNIT_CPM3;
data->scale = 3; /* fitted [#/dm^3] but unit is [#/m^3] */
return 3;
case SPS30_SAUL_VAL_IDX_NC_PM_4_10:
_float_fit(&_readings[dev_idx].nc_pm4, data, 2, 1000);
data->unit = UNIT_CPM3;
data->scale = 3; /* fitted [#/dm^3] but unit is [#/m^3] */
return 2;
case SPS30_SAUL_VAL_IDX_PS:
_float_fit(&_readings[dev_idx].ps, data, 1, 1000);
data->unit = UNIT_M;
data->scale -= 9; /* fitted [nm] but unit is [m] */
return 1;
}
return -ECANCELED;
}
static int read_mc_pm_1_2p5_4(const void *dev, phydat_t *data)
{
return read(dev, data, SPS30_SAUL_VAL_IDX_MC_PM_1_2P5_4);
}
static int read_mc_pm_10(const void *dev, phydat_t *data)
{
return read(dev, data, SPS30_SAUL_VAL_IDX_MC_PM_10);
}
static int read_nc_pm_0p5_1_2p5(const void *dev, phydat_t *data)
{
return read(dev, data, SPS30_SAUL_VAL_IDX_NC_PM_0P5_1_2P5);
}
static int read_nc_pm_4_10(const void *dev, phydat_t *data)
{
return read(dev, data, SPS30_SAUL_VAL_IDX_NC_PM_4_10);
}
static int read_ps(const void *dev, phydat_t *data)
{
return read(dev, data, SPS30_SAUL_VAL_IDX_PS);
}
const saul_driver_t sps30_saul_driver_mc_pm_1_2p5_4 = {
.read = read_mc_pm_1_2p5_4,
.write = saul_notsup,
.type = SAUL_SENSE_PM
};
const saul_driver_t sps30_saul_driver_mc_pm_10 = {
.read = read_mc_pm_10,
.write = saul_notsup,
.type = SAUL_SENSE_PM
};
const saul_driver_t sps30_saul_driver_nc_pm_0p5_1_2p5 = {
.read = read_nc_pm_0p5_1_2p5,
.write = saul_notsup,
.type = SAUL_SENSE_COUNT
};
const saul_driver_t sps30_saul_driver_nc_pm_4_10 = {
.read = read_nc_pm_4_10,
.write = saul_notsup,
.type = SAUL_SENSE_COUNT
};
const saul_driver_t sps30_saul_driver_ps = {
.read = read_ps,
.write = saul_notsup,
.type = SAUL_SENSE_SIZE
};

View File

@ -563,6 +563,10 @@ void auto_init(void)
extern void auto_init_si70xx(void);
auto_init_si70xx();
#endif
#ifdef MODULE_SPS30
extern void auto_init_sps30(void);
auto_init_sps30();
#endif
#ifdef MODULE_TCS37727
extern void auto_init_tcs37727(void);
auto_init_tcs37727();

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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
* @brief Auto initialization of Sensirion SPS30 device driver
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
* @file
*/
#ifdef MODULE_SPS30
#include "assert.h"
#include "log.h"
#include "saul_reg.h"
#include "sps30.h"
#include "sps30_params.h"
/**
* @brief Number of logical saul devices per physical sensor
*/
#define SPS30_SAUL_DEV_NUM (5)
/**
* @brief Allocation of memory for device descriptors
*/
sps30_t sps30_devs[SPS30_NUM];
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[SPS30_NUM * SPS30_SAUL_DEV_NUM];
/**
* @name Reference the driver structs.
* @{
*/
extern const saul_driver_t sps30_saul_driver_mc_pm_1_2p5_4;
extern const saul_driver_t sps30_saul_driver_mc_pm_10;
extern const saul_driver_t sps30_saul_driver_nc_pm_0p5_1_2p5;
extern const saul_driver_t sps30_saul_driver_nc_pm_4_10;
extern const saul_driver_t sps30_saul_driver_ps;
/** @} */
void auto_init_sps30(void)
{
assert(SPS30_INFO_NUM == SPS30_NUM);
for (unsigned i = 0; i < SPS30_NUM; i++) {
LOG_DEBUG("[auto_init_saul] initializing sps30 #%u\n", i);
if (sps30_init(&sps30_devs[i],
&sps30_params[i]) != SPS30_OK) {
LOG_ERROR("[auto_init_saul] error initializing sps30 #%u\n", i);
continue;
}
saul_entries[i * 5].driver = &sps30_saul_driver_mc_pm_1_2p5_4;
saul_entries[i * 5 + 1].driver = &sps30_saul_driver_mc_pm_10;
saul_entries[i * 5 + 2].driver = &sps30_saul_driver_nc_pm_0p5_1_2p5;
saul_entries[i * 5 + 3].driver = &sps30_saul_driver_nc_pm_4_10;
saul_entries[i * 5 + 4].driver = &sps30_saul_driver_ps;
/* the physical device is the same for all logical SAUL instances */
for (unsigned x = 0; x < SPS30_SAUL_DEV_NUM; x++) {
saul_entries[i * 5 + x].dev = &(sps30_devs[i]);
saul_entries[i * 5 + x].name = sps30_saul_info[i].name;
saul_reg_add(&saul_entries[i * 5 + x]);
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SPS30 */