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:
parent
36fca364f8
commit
7e089bce7b
@ -9,6 +9,7 @@
|
||||
/**
|
||||
* @defgroup drivers_sps30 Sensirion SPS30 Particulate Matter Sensor
|
||||
* @ingroup drivers_sensors
|
||||
* @ingroup drivers_saul
|
||||
*
|
||||
* About
|
||||
* =====
|
||||
|
@ -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
185
drivers/sps30/sps30_saul.c
Normal 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
|
||||
};
|
@ -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();
|
||||
|
79
sys/auto_init/saul/auto_init_sps30.c
Normal file
79
sys/auto_init/saul/auto_init_sps30.c
Normal 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 */
|
Loading…
Reference in New Issue
Block a user