Merge pull request #16217 from fjmolinas/pr_driver_sm_pwm_01c
drivers/sm_pwm_01c: initial import
This commit is contained in:
commit
e7732d9a00
@ -121,6 +121,7 @@ rsource "shtc1/Kconfig"
|
|||||||
rsource "si70xx/Kconfig"
|
rsource "si70xx/Kconfig"
|
||||||
rsource "si114x/Kconfig"
|
rsource "si114x/Kconfig"
|
||||||
rsource "si1133/Kconfig"
|
rsource "si1133/Kconfig"
|
||||||
|
rsource "sm_pwm_01c/Kconfig"
|
||||||
rsource "sps30/Kconfig"
|
rsource "sps30/Kconfig"
|
||||||
rsource "srf02/Kconfig"
|
rsource "srf02/Kconfig"
|
||||||
rsource "srf04/Kconfig"
|
rsource "srf04/Kconfig"
|
||||||
|
|||||||
207
drivers/include/sm_pwm_01c.h
Normal file
207
drivers/include/sm_pwm_01c.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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_sm_pwm_01c SM_PWM_01C dust sensor
|
||||||
|
* @ingroup drivers_sensors
|
||||||
|
* @brief Driver for Amphenol SM_PWM_01C infrared dust sensor
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* * About
|
||||||
|
* =====
|
||||||
|
*
|
||||||
|
* This driver provides an interface for the Amphenol SM-PWM-Sensor.
|
||||||
|
* The Datasheet can be found [here](https://www.cdiweb.com/datasheets/telaire-amphenol/01c%20dust%20sensor%20datasheet.pdf).
|
||||||
|
* and the more complete application note [here](https://www.sgbotic.com/products/datasheets/sensors/app-SM-PWM-01C.pdf)
|
||||||
|
*
|
||||||
|
* The device can measure small particles (1~ 2μm) and large particle (3 ~10μm),
|
||||||
|
* so similar to PM2.5 and PM10. The dust sensor cannot count particles only
|
||||||
|
* measure estimated concentrations.
|
||||||
|
*
|
||||||
|
* It is recommended to compute values over a 30s moving average. By default
|
||||||
|
* a moving average is used since the module MODULE_SM_PWM_01C_MA is
|
||||||
|
* activated by default. To save memory an exponential average can be used
|
||||||
|
* by disabling this module.
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief SM_PWM_01C Device Driver
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SM_PWM_01C_H
|
||||||
|
#define SM_PWM_01C_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "timex.h"
|
||||||
|
#include "ztimer.h"
|
||||||
|
#include "periph/gpio.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup drivers_sm_pwm_01c_conf SM_PWM_01C compile configurations
|
||||||
|
* @ingroup drivers_sm_pwm_01c
|
||||||
|
* @ingroup config
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def CONFIG_SM_PWM_01C_SAMPLE_TIME
|
||||||
|
*
|
||||||
|
* @brief Frequency at witch LPO % is calculated
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SM_PWM_01C_SAMPLE_TIME
|
||||||
|
#define CONFIG_SM_PWM_01C_SAMPLE_TIME (100 * US_PER_MS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def CONFIG_SM_PWM_01C_WINDOW_TIME
|
||||||
|
*
|
||||||
|
* @brief Length in time of the measuring window, recommended 5-30s
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SM_PWM_01C_WINDOW_TIME
|
||||||
|
#define CONFIG_SM_PWM_01C_WINDOW_TIME (10 * US_PER_SEC)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODULE_SM_PWM_01C_MA) || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* @def SM_PWM_01C_BUFFER_LEN
|
||||||
|
*
|
||||||
|
* @brief Length in time of the measuring window
|
||||||
|
*/
|
||||||
|
#define SM_PWM_01C_BUFFER_LEN (CONFIG_SM_PWM_01C_WINDOW_TIME / \
|
||||||
|
CONFIG_SM_PWM_01C_SAMPLE_TIME)
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def CONFIG_SM_PWM_01C_EXP_WEIGHT
|
||||||
|
*
|
||||||
|
* @brief Weight of the exponential average filter where:
|
||||||
|
* CONFIG_SM_PWM_01C_EXP_WEIGHT = 1 / (1 - alpha).
|
||||||
|
*
|
||||||
|
* @note Should be chosen wisely, it can be done my minimizing MSE
|
||||||
|
* or other algorithms as Marquardt procedure.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SM_PWM_01C_EXP_WEIGHT
|
||||||
|
#define CONFIG_SM_PWM_01C_EXP_WEIGHT (5)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#if defined(MODULE_SM_PWM_01C_MA) || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* @brief Circular buffer holding moving average values
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t buf[SM_PWM_01C_BUFFER_LEN]; /**< circular buffer memory */
|
||||||
|
size_t head; /**< current buffer head */
|
||||||
|
} circ_buf_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parameters for the SM_PWM_01c sensor
|
||||||
|
*
|
||||||
|
* These parameters are needed to configure the device at startup.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
gpio_t tsp_pin; /**< Low Pulse Signal Output (P1) of small Particle,
|
||||||
|
active low, PM2.5 equivalent */
|
||||||
|
gpio_t tlp_pin; /**< Low Pulse Signal Output (P2) of large Particle,
|
||||||
|
active low, PM10 equivalent */
|
||||||
|
} sm_pwm_01c_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LPO and concentration (ug/m3) values for small and large particles
|
||||||
|
*
|
||||||
|
* @note Actual measured particle size are: 1~ 2μm for small particles and 3 ~10μm,
|
||||||
|
* for large particles, but this values are exposed as standard PM2.5 and
|
||||||
|
* PM10 measurements.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t mc_pm_2p5; /**< Small particle concentration ug/m3 */
|
||||||
|
uint16_t mc_pm_10; /**< Large particle concentration ug/m3 */
|
||||||
|
} sm_pwm_01c_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LPO and concentration (ug/m3) values for small and large particles
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t tsp_lpo; /**< Small particle low Pulse active time us */
|
||||||
|
uint32_t tlp_lpo; /**< Large Particle low Pulse active time us */
|
||||||
|
uint32_t tlp_start_time; /**< Last time tlp pin went low */
|
||||||
|
uint32_t tsp_start_time; /**< Last time tsp pin went low */
|
||||||
|
#ifdef MODULE_SM_PWM_01C_MA
|
||||||
|
circ_buf_t tsp_circ_buf; /**< Small particle moving average values */
|
||||||
|
circ_buf_t tlp_circ_buf; /**< Large particle moving average values */
|
||||||
|
#else
|
||||||
|
sm_pwm_01c_data_t data; /**< Current value for the exponentially averaged
|
||||||
|
particle concentration values */
|
||||||
|
#endif
|
||||||
|
} sm_pwm_01c_values_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device descriptor for the SM_PWM_01c sensor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
sm_pwm_01c_params_t params; /**< Device driver parameters */
|
||||||
|
sm_pwm_01c_values_t _values; /**< Internal data to calculate concentration
|
||||||
|
from tsl/tsp low Pulse Output Occupancy */
|
||||||
|
ztimer_t _sampler; /**< internal sampling timer */
|
||||||
|
} sm_pwm_01c_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the given SM_PWM_01C device
|
||||||
|
*
|
||||||
|
* @param[out] dev Initialized device descriptor of SM_PWM_01C device
|
||||||
|
* @param[in] params The parameters for the SM_PWM_01C device
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -EIO GPIO error
|
||||||
|
*/
|
||||||
|
int sm_pwm_01c_init(sm_pwm_01c_t *dev, const sm_pwm_01c_params_t *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start continuous measurement of Large and Small particle
|
||||||
|
* concentrations
|
||||||
|
*
|
||||||
|
* @param[in] dev Device descriptor of SM_PWM_01C device
|
||||||
|
*/
|
||||||
|
void sm_pwm_01c_start(sm_pwm_01c_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops continuous measurement of Large and Small particle
|
||||||
|
* concentration
|
||||||
|
*
|
||||||
|
* @param[in] dev Device descriptor of SM_PWM_01C device
|
||||||
|
*/
|
||||||
|
void sm_pwm_01c_stop(sm_pwm_01c_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads particle concentration values
|
||||||
|
*
|
||||||
|
* @param[in] dev Device descriptor of SM_PWM_01C device
|
||||||
|
* @param[out] data Pre-allocated memory to hold measured concentrations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void sm_pwm_01c_read_data(sm_pwm_01c_t *dev, sm_pwm_01c_data_t *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SM_PWM_01C_H */
|
||||||
|
/** @} */
|
||||||
76
drivers/saul/init_devs/auto_init_sm_pwm_01c.c
Normal file
76
drivers/saul/init_devs/auto_init_sm_pwm_01c.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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 SM_PWM_01C dust sensor
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
#include "sm_pwm_01c_params.h"
|
||||||
|
#include "sm_pwm_01c.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory for the device descriptors
|
||||||
|
*/
|
||||||
|
static sm_pwm_01c_t sm_pwm_01c_devs[SM_PWM_01C_NUMOF];
|
||||||
|
|
||||||
|
#if IS_ACTIVE(MODULE_SAUL)
|
||||||
|
/**
|
||||||
|
* @brief Memory for the SAUL registry entries
|
||||||
|
*/
|
||||||
|
static saul_reg_t saul_entries[SM_PWM_01C_NUMOF * 2];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define the number of saul info
|
||||||
|
*/
|
||||||
|
#define SM_PWM_01C_INFO_NUM ARRAY_SIZE(sm_pwm_01c_saul_info)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Import SAUL endpoints
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
extern const saul_driver_t sm_pwm_01c_saul_driver_mc_pm_2p5;
|
||||||
|
extern const saul_driver_t sm_pwm_01c_saul_driver_mc_pm_10;
|
||||||
|
/** @} */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void auto_init_sm_pwm_01c(void)
|
||||||
|
{
|
||||||
|
#if IS_ACTIVE(MODULE_SAUL)
|
||||||
|
assert(SM_PWM_01C_INFO_NUM == SM_PWM_01C_NUMOF);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < SM_PWM_01C_NUMOF; i++) {
|
||||||
|
LOG_DEBUG("[auto_init_saul] initializing sm_pwm_01c #%u\n", i);
|
||||||
|
|
||||||
|
if (sm_pwm_01c_init(&sm_pwm_01c_devs[i], &sm_pwm_01c_params[i])) {
|
||||||
|
LOG_ERROR("[auto_init_saul] error initializing sm_pwm_01c #%u\n",
|
||||||
|
i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sm_pwm_01c_start(&sm_pwm_01c_devs[i]);
|
||||||
|
#if IS_ACTIVE(MODULE_SAUL)
|
||||||
|
saul_entries[(i * 2)].dev = &(sm_pwm_01c_devs[i]);
|
||||||
|
saul_entries[(i * 2)].name = sm_pwm_01c_saul_info[i].name;
|
||||||
|
saul_entries[(i * 2)].driver = &sm_pwm_01c_saul_driver_mc_pm_2p5;
|
||||||
|
saul_entries[(i * 2) + 1].dev = &(sm_pwm_01c_devs[i]);
|
||||||
|
saul_entries[(i * 2) + 1].name = sm_pwm_01c_saul_info[i].name;
|
||||||
|
saul_entries[(i * 2) + 1].driver = &sm_pwm_01c_saul_driver_mc_pm_10;
|
||||||
|
saul_reg_add(&(saul_entries[(i * 2)]));
|
||||||
|
saul_reg_add(&(saul_entries[(i * 2) + 1]));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -271,6 +271,10 @@ void saul_init_devs(void)
|
|||||||
extern void auto_init_si70xx(void);
|
extern void auto_init_si70xx(void);
|
||||||
auto_init_si70xx();
|
auto_init_si70xx();
|
||||||
}
|
}
|
||||||
|
if (IS_USED(MODULE_SM_PWM_01C)) {
|
||||||
|
extern void auto_init_sm_pwm_01c(void);
|
||||||
|
auto_init_sm_pwm_01c();
|
||||||
|
}
|
||||||
if (IS_USED(MODULE_SPS30)) {
|
if (IS_USED(MODULE_SPS30)) {
|
||||||
extern void auto_init_sps30(void);
|
extern void auto_init_sps30(void);
|
||||||
auto_init_sps30();
|
auto_init_sps30();
|
||||||
|
|||||||
60
drivers/sm_pwm_01c/Kconfig
Normal file
60
drivers/sm_pwm_01c/Kconfig
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright (c) 2021 Inria
|
||||||
|
#
|
||||||
|
# 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 MODULE_SM_PWM_01C
|
||||||
|
bool "SM_PWM_01C Amphenol infrared dust sensor"
|
||||||
|
depends on HAS_PERIPH_GPIO
|
||||||
|
depends on HAS_PERIPH_GPIO_IRQ
|
||||||
|
depends on TEST_KCONFIG
|
||||||
|
select MODULE_CHECKSUM
|
||||||
|
select MODULE_PERIPH_GPIO
|
||||||
|
select MODULE_PERIPH_GPIO_IRQ
|
||||||
|
select MODULE_ZTIMER
|
||||||
|
select MODULE_ZTIMER_USEC
|
||||||
|
select MODULE_ZTIMER_PERIPH_TIMER
|
||||||
|
|
||||||
|
config MODULE_SM_PWM_01C_MA
|
||||||
|
bool "Use a moving average for sensor values"
|
||||||
|
depends on MODULE_SM_PWM_01C
|
||||||
|
default y
|
||||||
|
|
||||||
|
menuconfig KCONFIG_USEMODULE_SM_PWM_01C
|
||||||
|
bool "Configure SM_PWM_01C driver"
|
||||||
|
depends on USEMODULE_SM_PWM_01C
|
||||||
|
help
|
||||||
|
Configure the SM_PWM_01C driver using Kconfig.
|
||||||
|
|
||||||
|
if KCONFIG_USEMODULE_SM_PWM_01C
|
||||||
|
|
||||||
|
config SM_PWM_01C_WINDOW_TIME
|
||||||
|
int "Measuring Window length"
|
||||||
|
default 10000000
|
||||||
|
help
|
||||||
|
Length in time of the measuring window in microseconds,
|
||||||
|
recommended 5-30s.
|
||||||
|
|
||||||
|
config SM_PWM_01C_SAMPLE_TIME
|
||||||
|
int "PWM occupancy sampling period"
|
||||||
|
default 100000
|
||||||
|
help
|
||||||
|
Time, expressed in microseconds, at witch LPO is occupancy is
|
||||||
|
sampled and converted into particle matter concentration
|
||||||
|
|
||||||
|
if !USEMODULE_SM_PWM_01C_MA
|
||||||
|
|
||||||
|
config SM_PWM_01C_EXP_WEIGHT
|
||||||
|
int "Weight of the exponential"
|
||||||
|
default 100000
|
||||||
|
help
|
||||||
|
Weight of the exponential average filter where:
|
||||||
|
SM_PWM_01C_EXP_WEIGHT = 1 / (1 - alpha).
|
||||||
|
|
||||||
|
Should be chosen wisely, it can be done my minimizing MSE
|
||||||
|
or other algorithms as Marquardt procedure.
|
||||||
|
|
||||||
|
endif # USEMODULE_SM_PWM_01C_MA
|
||||||
|
|
||||||
|
endif # KCONFIG_USEMODULE_SM_PWM_01C
|
||||||
7
drivers/sm_pwm_01c/Makefile
Normal file
7
drivers/sm_pwm_01c/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
SRC := sm_pwm_01c.c
|
||||||
|
|
||||||
|
ifneq (,$(filter saul,$(USEMODULE)))
|
||||||
|
SRC += sm_pwm_01c_saul.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
5
drivers/sm_pwm_01c/Makefile.dep
Normal file
5
drivers/sm_pwm_01c/Makefile.dep
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
USEMODULE += ztimer_usec
|
||||||
|
DEFAULT_MODULE += sm_pwm_01c_ma
|
||||||
|
|
||||||
|
FEATURES_REQUIRED += periph_gpio
|
||||||
|
FEATURES_REQUIRED += periph_gpio_irq
|
||||||
4
drivers/sm_pwm_01c/Makefile.include
Normal file
4
drivers/sm_pwm_01c/Makefile.include
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
USEMODULE_INCLUDES_sm_pwm_01c := $(LAST_MAKEFILEDIR)/include
|
||||||
|
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_sm_pwm_01c)
|
||||||
|
|
||||||
|
PSEUDOMODULES += sm_pwm_01c_ma
|
||||||
80
drivers/sm_pwm_01c/include/sm_pwm_01c_params.h
Normal file
80
drivers/sm_pwm_01c/include/sm_pwm_01c_params.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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_sm_pwm_01c
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief Default configuration for SM_PWM_01C driver
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SM_PWM_01C_PARAMS_H
|
||||||
|
#define SM_PWM_01C_PARAMS_H
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
#include "sm_pwm_01c.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Set default configuration parameters for the SM_PWM_01C
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef SM_PWM_01C_TSP_PIN
|
||||||
|
#define SM_PWM_01C_TSP_PIN GPIO_PIN(0, 13)
|
||||||
|
#endif
|
||||||
|
#ifndef SM_PWM_01C_TLP_PIN
|
||||||
|
#define SM_PWM_01C_TLP_PIN GPIO_PIN(0, 28)
|
||||||
|
#endif
|
||||||
|
#ifndef SM_PWM_01C_SAUL_INFO
|
||||||
|
#define SM_PWM_01C_SAUL_INFO { .name = "sm-pwm-01c" }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SM_PWM_01C_PARAMS_DEFAULT
|
||||||
|
#define SM_PWM_01C_PARAMS_DEFAULT { .tsp_pin = SM_PWM_01C_TSP_PIN, \
|
||||||
|
.tlp_pin = SM_PWM_01C_TLP_PIN }
|
||||||
|
#endif
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure SM_PWM_01C
|
||||||
|
*/
|
||||||
|
static const sm_pwm_01c_params_t sm_pwm_01c_params[] =
|
||||||
|
{
|
||||||
|
#ifdef SM_PWM_01C_PARAMS_BOARD
|
||||||
|
SM_PWM_01C_PARAMS_BOARD,
|
||||||
|
#else
|
||||||
|
SM_PWM_01C_PARAMS_DEFAULT
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Additional meta information to keep in the SAUL registry
|
||||||
|
*/
|
||||||
|
static const saul_reg_info_t sm_pwm_01c_saul_info[] =
|
||||||
|
{
|
||||||
|
SM_PWM_01C_SAUL_INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The number of configured sensors
|
||||||
|
*/
|
||||||
|
#define SM_PWM_01C_NUMOF ARRAY_SIZE(sm_pwm_01c_params)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SM_PWM_01C_PARAMS_H */
|
||||||
|
/** @} */
|
||||||
206
drivers/sm_pwm_01c/sm_pwm_01c.c
Normal file
206
drivers/sm_pwm_01c/sm_pwm_01c.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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_sm_pwm_01c
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief Implementation of SM_PWM_01C dust sensor
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "ztimer.h"
|
||||||
|
|
||||||
|
#include "periph/gpio.h"
|
||||||
|
|
||||||
|
#include "sm_pwm_01c.h"
|
||||||
|
#include "sm_pwm_01c_params.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG 0
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/* Scaling value to get 1/100 of a % resolution for lpo values */
|
||||||
|
#define LPO_SCALING (100)
|
||||||
|
|
||||||
|
/* Circular average for moving average calculation, this is always
|
||||||
|
called in irq context */
|
||||||
|
#ifdef MODULE_SM_PWM_01C_MA
|
||||||
|
static void _circ_buf_push(circ_buf_t *buf, uint16_t data)
|
||||||
|
{
|
||||||
|
buf->buf[buf->head] = data;
|
||||||
|
buf->head = (buf->head + 1) % (SM_PWM_01C_BUFFER_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t _circ_buf_avg(circ_buf_t *buf)
|
||||||
|
{
|
||||||
|
uint32_t sum = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < SM_PWM_01C_BUFFER_LEN; i++) {
|
||||||
|
sum += buf->buf[i];
|
||||||
|
}
|
||||||
|
return (uint16_t)(sum / SM_PWM_01C_BUFFER_LEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Interval approximation of theoretical Dust Concentration / LPO % curve
|
||||||
|
https://www.sgbotic.com/products/datasheets/sensors/app-SM-PWM-01C.pdf */
|
||||||
|
static uint16_t _lpo_to_dust_cons(uint16_t lpo)
|
||||||
|
{
|
||||||
|
if (lpo <= (2 * LPO_SCALING)) {
|
||||||
|
return (143 * lpo) / (2 * LPO_SCALING);
|
||||||
|
}
|
||||||
|
else if (lpo <= (4 * LPO_SCALING)) {
|
||||||
|
return (208 * lpo + 130) / (3 * LPO_SCALING);
|
||||||
|
}
|
||||||
|
else if (lpo <= (15 * LPO_SCALING)) {
|
||||||
|
return (1155 * lpo - 1572) / (10 * LPO_SCALING);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (2354 * lpo - 19560) / (10 * LPO_SCALING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sample_timer_cb(void *arg)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_t *dev = (sm_pwm_01c_t *)arg;
|
||||||
|
|
||||||
|
/* schedule next sample */
|
||||||
|
ztimer_set(ZTIMER_USEC, &dev->_sampler, CONFIG_SM_PWM_01C_SAMPLE_TIME);
|
||||||
|
DEBUG("[sm_pwm_01c] tsp_lpo %" PRIu32 "\n", dev->_values.tsp_lpo);
|
||||||
|
DEBUG("[sm_pwm_01c] tlp_lpo %" PRIu32 "\n", dev->_values.tlp_lpo);
|
||||||
|
|
||||||
|
/* calculate low Pulse Output Occupancy in (% * LPO_SCALING),
|
||||||
|
e.g. 1% -> 100 */
|
||||||
|
uint16_t tsp_ratio =
|
||||||
|
(uint16_t)((uint64_t)(100 * LPO_SCALING * dev->_values.tsp_lpo) /
|
||||||
|
CONFIG_SM_PWM_01C_SAMPLE_TIME);
|
||||||
|
uint16_t tlp_ratio =
|
||||||
|
(uint16_t)((uint64_t)(100 * LPO_SCALING * dev->_values.tlp_lpo) /
|
||||||
|
CONFIG_SM_PWM_01C_SAMPLE_TIME);
|
||||||
|
DEBUG("[sm_pwm_01c] tsp_ratio %" PRIu16 "/%d %%\n", tsp_ratio, LPO_SCALING);
|
||||||
|
DEBUG("[sm_pwm_01c] tlp_ratio %" PRIu16 "/%d %%\n", tlp_ratio, LPO_SCALING);
|
||||||
|
|
||||||
|
/* convert lpo to particle concentration */
|
||||||
|
uint16_t tsp = _lpo_to_dust_cons(tsp_ratio);
|
||||||
|
uint16_t tlp = _lpo_to_dust_cons(tlp_ratio);
|
||||||
|
DEBUG("[sm_pwm_01c] new sample tsp conc: %" PRIu16 " ug/m3\n", tsp);
|
||||||
|
DEBUG("[sm_pwm_01c] new sample tlp conc: %" PRIu16 " ug/m3\n", tlp);
|
||||||
|
|
||||||
|
/* update concentration values*/
|
||||||
|
#ifdef MODULE_SM_PWM_01C_MA
|
||||||
|
_circ_buf_push(&dev->_values.tsp_circ_buf, tsp);
|
||||||
|
_circ_buf_push(&dev->_values.tlp_circ_buf, tlp);
|
||||||
|
#else
|
||||||
|
dev->_values.data.mc_pm_10 =
|
||||||
|
(uint16_t)((tlp + (uint32_t)(CONFIG_SM_PWM_01C_EXP_WEIGHT - 1) *
|
||||||
|
dev->_values.data.mc_pm_10) / CONFIG_SM_PWM_01C_EXP_WEIGHT);
|
||||||
|
dev->_values.data.mc_pm_2p5 =
|
||||||
|
(uint16_t)((tsp + (uint32_t)(CONFIG_SM_PWM_01C_EXP_WEIGHT - 1) *
|
||||||
|
dev->_values.data.mc_pm_2p5) / CONFIG_SM_PWM_01C_EXP_WEIGHT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* reset lpo */
|
||||||
|
dev->_values.tlp_lpo = 0;
|
||||||
|
dev->_values.tsp_lpo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tsp_pin_cb(void *arg)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_t *dev = (sm_pwm_01c_t *)arg;
|
||||||
|
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||||
|
|
||||||
|
if (gpio_read(dev->params.tsp_pin) == 0) {
|
||||||
|
dev->_values.tsp_start_time = now;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->_values.tsp_lpo += (now - dev->_values.tsp_start_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tlp_pin_cb(void *arg)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_t *dev = (sm_pwm_01c_t *)arg;
|
||||||
|
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||||
|
|
||||||
|
if (gpio_read(dev->params.tlp_pin) == 0) {
|
||||||
|
dev->_values.tlp_start_time = now;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->_values.tlp_lpo += (now - dev->_values.tlp_start_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sm_pwm_01c_init(sm_pwm_01c_t *dev, const sm_pwm_01c_params_t *params)
|
||||||
|
{
|
||||||
|
dev->params = *params;
|
||||||
|
|
||||||
|
/* set up irq */
|
||||||
|
if (gpio_init_int(dev->params.tsp_pin, GPIO_IN_PU, GPIO_BOTH, _tsp_pin_cb,
|
||||||
|
dev) < 0) {
|
||||||
|
DEBUG("[sm_pwm_01c] init_int of tsp_pin failed [ERROR]\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
if (gpio_init_int(dev->params.tlp_pin, GPIO_IN_PU, GPIO_BOTH, _tlp_pin_cb,
|
||||||
|
dev) < 0) {
|
||||||
|
DEBUG("[sm_pwm_01c] init_int of tlp_pin failed [ERROR]\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup timer */
|
||||||
|
dev->_sampler.callback = _sample_timer_cb;
|
||||||
|
dev->_sampler.arg = dev;
|
||||||
|
|
||||||
|
#ifdef MODULE_SM_PWM_01C_MA
|
||||||
|
memset(&dev->_values.tsp_circ_buf, 0, sizeof(circ_buf_t));
|
||||||
|
memset(&dev->_values.tlp_circ_buf, 0, sizeof(circ_buf_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_pwm_01c_start(sm_pwm_01c_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
/* reset old values */
|
||||||
|
memset((void *)&dev->_values, 0, sizeof(sm_pwm_01c_values_t));
|
||||||
|
/* enable irq and set timer */
|
||||||
|
ztimer_set(ZTIMER_USEC, &dev->_sampler, CONFIG_SM_PWM_01C_SAMPLE_TIME);
|
||||||
|
gpio_irq_enable(dev->params.tsp_pin);
|
||||||
|
gpio_irq_enable(dev->params.tlp_pin);
|
||||||
|
DEBUG("[sm_pwm_01c] started average measurements\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_pwm_01c_stop(sm_pwm_01c_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
/* disable irq and remove timer */
|
||||||
|
ztimer_remove(ZTIMER_USEC, &dev->_sampler);
|
||||||
|
gpio_irq_disable(dev->params.tsp_pin);
|
||||||
|
gpio_irq_disable(dev->params.tlp_pin);
|
||||||
|
DEBUG("[sm_pwm_01c] stopped average measurements\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_pwm_01c_read_data(sm_pwm_01c_t *dev, sm_pwm_01c_data_t *data)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
unsigned int state = irq_disable();
|
||||||
|
#ifdef MODULE_SM_PWM_01C_MA
|
||||||
|
data->mc_pm_10 = _circ_buf_avg(&dev->_values.tlp_circ_buf);
|
||||||
|
data->mc_pm_2p5 = _circ_buf_avg(&dev->_values.tsp_circ_buf);
|
||||||
|
#else
|
||||||
|
data->mc_pm_10 = dev->_values.data.mc_pm_10;
|
||||||
|
data->mc_pm_2p5 = dev->_values.data.mc_pm_2p5;
|
||||||
|
#endif
|
||||||
|
irq_restore(state);
|
||||||
|
}
|
||||||
66
drivers/sm_pwm_01c/sm_pwm_01c_saul.c
Normal file
66
drivers/sm_pwm_01c/sm_pwm_01c_saul.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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_sm_pwm_01c
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief SAUL adaption of the SM_PWM_01C dust sensor driver
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "phydat.h"
|
||||||
|
#include "saul.h"
|
||||||
|
#include "sm_pwm_01c.h"
|
||||||
|
#include "sm_pwm_01c_params.h"
|
||||||
|
|
||||||
|
static int read_mc_pm_2p5(const void *_dev, phydat_t *data)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_data_t values;
|
||||||
|
sm_pwm_01c_t *dev = (sm_pwm_01c_t *)_dev;
|
||||||
|
|
||||||
|
sm_pwm_01c_read_data(dev, &values);
|
||||||
|
data->unit = UNIT_GPM3;
|
||||||
|
data->scale = -6;
|
||||||
|
uint32_t value = values.mc_pm_2p5;
|
||||||
|
phydat_fit(data, (int32_t *)&value, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_mc_pm_10(const void *_dev, phydat_t *data)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_data_t values;
|
||||||
|
sm_pwm_01c_t *dev = (sm_pwm_01c_t *)_dev;
|
||||||
|
|
||||||
|
sm_pwm_01c_read_data(dev, &values);
|
||||||
|
data->unit = UNIT_GPM3;
|
||||||
|
data->scale = -6;
|
||||||
|
uint32_t value = values.mc_pm_10;
|
||||||
|
phydat_fit(data, (int32_t *)&value, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saul_driver_t sm_pwm_01c_saul_driver_mc_pm_10 = {
|
||||||
|
.read = read_mc_pm_10,
|
||||||
|
.write = saul_notsup,
|
||||||
|
.type = SAUL_SENSE_PM,
|
||||||
|
.subtype = SAUL_SENSE_PM_10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const saul_driver_t sm_pwm_01c_saul_driver_mc_pm_2p5 = {
|
||||||
|
.read = read_mc_pm_2p5,
|
||||||
|
.write = saul_notsup,
|
||||||
|
.type = SAUL_SENSE_PM,
|
||||||
|
.subtype = SAUL_SENSE_PM_2p5,
|
||||||
|
};
|
||||||
@ -42,6 +42,7 @@ rsource "posix/Kconfig"
|
|||||||
rsource "oneway-malloc/Kconfig"
|
rsource "oneway-malloc/Kconfig"
|
||||||
rsource "phydat/Kconfig"
|
rsource "phydat/Kconfig"
|
||||||
rsource "pm_layered/Kconfig"
|
rsource "pm_layered/Kconfig"
|
||||||
|
rsource "progress_bar/Kconfig"
|
||||||
rsource "ps/Kconfig"
|
rsource "ps/Kconfig"
|
||||||
rsource "random/Kconfig"
|
rsource "random/Kconfig"
|
||||||
rsource "saul_reg/Kconfig"
|
rsource "saul_reg/Kconfig"
|
||||||
|
|||||||
@ -29,50 +29,50 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* @brief Progress bar maximum characters length
|
* @brief Progress bar maximum characters length
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_LENGTH
|
#ifndef CONFIG_PROGRESS_BAR_LENGTH
|
||||||
#define PROGRESS_BAR_LENGTH (25U)
|
#define CONFIG_PROGRESS_BAR_LENGTH (25U)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Progress bar character
|
* @brief Progress bar character
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_FULL_CHARACTER
|
#ifndef CONFIG_PROGRESS_BAR_FULL_CHARACTER
|
||||||
#define PROGRESS_BAR_FULL_CHARACTER "█"
|
#define CONFIG_PROGRESS_BAR_FULL_CHARACTER "█"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Progress bar empty character
|
* @brief Progress bar empty character
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_EMPTY_CHARACTER
|
#ifndef CONFIG_PROGRESS_BAR_EMPTY_CHARACTER
|
||||||
#define PROGRESS_BAR_EMPTY_CHARACTER " "
|
#define CONFIG_PROGRESS_BAR_EMPTY_CHARACTER " "
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Character displayed on the left of the progress bar
|
* @brief Character displayed on the left of the progress bar
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_PREFIX_CHARACTER
|
#ifndef CONFIG_PROGRESS_BAR_PREFIX_CHARACTER
|
||||||
#define PROGRESS_BAR_PREFIX_CHARACTER "|"
|
#define CONFIG_PROGRESS_BAR_PREFIX_CHARACTER "|"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Character displayed on the left of the progress bar
|
* @brief Character displayed on the left of the progress bar
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_SUFFIX_CHARACTER
|
#ifndef CONFIG_PROGRESS_BAR_SUFFIX_CHARACTER
|
||||||
#define PROGRESS_BAR_SUFFIX_CHARACTER "|"
|
#define CONFIG_PROGRESS_BAR_SUFFIX_CHARACTER "|"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Progress bar prefix max length
|
* @brief Progress bar prefix max length
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_PREFIX_MAX_LENGTH
|
#ifndef CONFIG_PROGRESS_BAR_PREFIX_MAX_LENGTH
|
||||||
#define PROGRESS_BAR_PREFIX_MAX_LENGTH (32U)
|
#define CONFIG_PROGRESS_BAR_PREFIX_MAX_LENGTH (32U)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Progress bar suffix max length
|
* @brief Progress bar suffix max length
|
||||||
*/
|
*/
|
||||||
#ifndef PROGRESS_BAR_SUFFIX_MAX_LENGTH
|
#ifndef CONFIG_PROGRESS_BAR_SUFFIX_MAX_LENGTH
|
||||||
#define PROGRESS_BAR_SUFFIX_MAX_LENGTH (32U)
|
#define CONFIG_PROGRESS_BAR_SUFFIX_MAX_LENGTH (32U)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,9 +82,9 @@ typedef struct {
|
|||||||
/** Current value of the progress bar. Must be between 0 and 100 (included) */
|
/** Current value of the progress bar. Must be between 0 and 100 (included) */
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
/** Prefix displayed on the left of the progress bar */
|
/** Prefix displayed on the left of the progress bar */
|
||||||
char prefix[PROGRESS_BAR_PREFIX_MAX_LENGTH];
|
char prefix[CONFIG_PROGRESS_BAR_PREFIX_MAX_LENGTH];
|
||||||
/** Suffix displayed on the right of the progress bar */
|
/** Suffix displayed on the right of the progress bar */
|
||||||
char suffix[PROGRESS_BAR_SUFFIX_MAX_LENGTH];
|
char suffix[CONFIG_PROGRESS_BAR_SUFFIX_MAX_LENGTH];
|
||||||
} progress_bar_t;
|
} progress_bar_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
58
sys/progress_bar/Kconfig
Normal file
58
sys/progress_bar/Kconfig
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Copyright (c) 2021 Inria
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
config MODULE_PROGRESS_BAR
|
||||||
|
bool "A simple CLI progress bar"
|
||||||
|
depends on TEST_KCONFIG
|
||||||
|
|
||||||
|
menuconfig KCONFIG_USEMODULE_PROGRESS_BAR
|
||||||
|
bool "Configure progress bar module"
|
||||||
|
depends on USEMODULE_PROGRESS_BAR
|
||||||
|
help
|
||||||
|
Configure the progress bar module using Kconfig.
|
||||||
|
|
||||||
|
if KCONFIG_USEMODULE_PROGRESS_BAR
|
||||||
|
|
||||||
|
config PROGRESS_BAR_LENGTH
|
||||||
|
int "Progress bar length"
|
||||||
|
default 25
|
||||||
|
help
|
||||||
|
Progress bar maximum characters length
|
||||||
|
|
||||||
|
config PROGRESS_BAR_FULL_CHARACTER
|
||||||
|
string "Progress bar character"
|
||||||
|
default "█"
|
||||||
|
help
|
||||||
|
The character that will be printed when the progress bar fills up.
|
||||||
|
|
||||||
|
config PROGRESS_BAR_EMPTY_CHARACTER
|
||||||
|
string "Progress bar empty character"
|
||||||
|
default " "
|
||||||
|
help
|
||||||
|
The character that will be printed when the progress bar empties.
|
||||||
|
|
||||||
|
config PROGRESS_BAR_PREFIX_CHARACTER
|
||||||
|
string "Progress bar prefix"
|
||||||
|
default "|"
|
||||||
|
help
|
||||||
|
Character displayed on the left of the progress bar
|
||||||
|
|
||||||
|
config PROGRESS_BAR_SUFFIX_CHARACTER
|
||||||
|
string "Progress bar suffix"
|
||||||
|
default "|"
|
||||||
|
help
|
||||||
|
Character displayed on the left of the progress bar
|
||||||
|
|
||||||
|
config PROGRESS_BAR_PREFIX_MAX_LENGTH
|
||||||
|
int "Progress bar prefix max length"
|
||||||
|
default 32
|
||||||
|
|
||||||
|
config PROGRESS_BAR_SUFFIX_MAX_LENGTH
|
||||||
|
int "Progress bar suffix max length"
|
||||||
|
default 32
|
||||||
|
|
||||||
|
endif # KCONFIG_USEMODULE_PROGRESS_BAR
|
||||||
@ -44,19 +44,19 @@ void progress_bar_print(char *prefix, char *suffix, uint8_t value)
|
|||||||
printf("%s", prefix);
|
printf("%s", prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(PROGRESS_BAR_PREFIX_CHARACTER);
|
printf(CONFIG_PROGRESS_BAR_PREFIX_CHARACTER);
|
||||||
|
|
||||||
/* Fully reprint the progress bar */
|
/* Fully reprint the progress bar */
|
||||||
for (unsigned i = 0; i < PROGRESS_BAR_LENGTH; ++i) {
|
for (unsigned i = 0; i < CONFIG_PROGRESS_BAR_LENGTH; ++i) {
|
||||||
if (100 * i < (uint16_t)(value * PROGRESS_BAR_LENGTH)) {
|
if (100 * i < (uint16_t)(value * CONFIG_PROGRESS_BAR_LENGTH)) {
|
||||||
printf(PROGRESS_BAR_FULL_CHARACTER);
|
printf(CONFIG_PROGRESS_BAR_FULL_CHARACTER);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf(PROGRESS_BAR_EMPTY_CHARACTER);
|
printf(CONFIG_PROGRESS_BAR_EMPTY_CHARACTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(PROGRESS_BAR_SUFFIX_CHARACTER);
|
printf(CONFIG_PROGRESS_BAR_SUFFIX_CHARACTER);
|
||||||
|
|
||||||
/* Display progress bar suffix if any */
|
/* Display progress bar suffix if any */
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
|
|||||||
8
tests/driver_sm_pwm_01c/Makefile
Normal file
8
tests/driver_sm_pwm_01c/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
BOARD ?= samr21-xpro
|
||||||
|
|
||||||
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
|
USEMODULE += progress_bar
|
||||||
|
USEMODULE += sm_pwm_01c
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
3
tests/driver_sm_pwm_01c/Makefile.ci
Normal file
3
tests/driver_sm_pwm_01c/Makefile.ci
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
nucleo-l011k4
|
||||||
|
#
|
||||||
27
tests/driver_sm_pwm_01c/README.md
Normal file
27
tests/driver_sm_pwm_01c/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Test Application for the Amphenol SM_PWM_01C infrared dust sensor
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
This is a simple test application for the SM_PWM_01C driver.
|
||||||
|
|
||||||
|
## Expected result
|
||||||
|
|
||||||
|
If everything works then you should see the progress bar vary if dust
|
||||||
|
concentration changes in the room, or manually block the infrared inputs
|
||||||
|
to force a change.
|
||||||
|
|
||||||
|
Overly exaggerated values (blocked infrared sensor) can be seen here:
|
||||||
|
|
||||||
|
```
|
||||||
|
# main(): This is RIOT! (Version: 2021.04-devel-1044-gfd36c-HEAD)
|
||||||
|
# sm_pwm_01c driver test application
|
||||||
|
# starting weighted average PM2.5 and PM10 measurements
|
||||||
|
#
|
||||||
|
# PM2.5 level: 1272 ug/m3|███████████ |
|
||||||
|
# PM10 level: 490 ug/m3|████ |
|
||||||
|
````
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
By default a moving average over a 30s window is returned ad the
|
||||||
|
read value. The progress bar is updated every 200ms.
|
||||||
6
tests/driver_sm_pwm_01c/app.config.test
Normal file
6
tests/driver_sm_pwm_01c/app.config.test
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# this file enables modules defined in Kconfig. Do not use this file for
|
||||||
|
# application configuration. This is only needed during migration.
|
||||||
|
CONFIG_MODULE_SM_PWM_01C=y
|
||||||
|
CONFIG_MODULE_ZTIMER=y
|
||||||
|
CONFIG_MODULE_ZTIMER_USEC=y
|
||||||
|
CONFIG_MODULE_PROGRESS_BAR=y
|
||||||
61
tests/driver_sm_pwm_01c/main.c
Normal file
61
tests/driver_sm_pwm_01c/main.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Inria
|
||||||
|
*
|
||||||
|
* 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 SM_PWM_01C driver
|
||||||
|
*
|
||||||
|
* @author Francisco Molina <francois-xavier.molina@inria.fr>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ztimer.h"
|
||||||
|
|
||||||
|
#include "sm_pwm_01c.h"
|
||||||
|
#include "sm_pwm_01c_params.h"
|
||||||
|
|
||||||
|
#include "progress_bar.h"
|
||||||
|
|
||||||
|
static progress_bar_t progress_bar_list[2];
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
sm_pwm_01c_t dev;
|
||||||
|
|
||||||
|
puts("sm_pwm_01c driver test application");
|
||||||
|
if (sm_pwm_01c_init(&dev, &sm_pwm_01c_params[0]) != 0) {
|
||||||
|
puts("init device [ERROR]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("starting weighted average PM2.5 and PM10 measurements\n");
|
||||||
|
sm_pwm_01c_start(&dev);
|
||||||
|
progress_bar_prepare_multi(2);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ztimer_sleep(ZTIMER_USEC, 200 * US_PER_MS);
|
||||||
|
sm_pwm_01c_data_t data;
|
||||||
|
sm_pwm_01c_read_data(&dev, &data);
|
||||||
|
sprintf(progress_bar_list[0].prefix,
|
||||||
|
"%s %4d ug/m3", "PM2.5 level:",
|
||||||
|
data.mc_pm_2p5);
|
||||||
|
sprintf(progress_bar_list[1].prefix, "%s %4d ug/m3", "PM10 level:",
|
||||||
|
data.mc_pm_10);
|
||||||
|
progress_bar_list[0].value = data.mc_pm_2p5 >
|
||||||
|
3000 ? 100 : (data.mc_pm_2p5 * 100) / 3000;
|
||||||
|
progress_bar_list[1].value = data.mc_pm_10 >
|
||||||
|
3000 ? 100 : (data.mc_pm_10 * 100) / 3000;
|
||||||
|
progress_bar_update_multi(progress_bar_list, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -3,24 +3,24 @@ include ../Makefile.tests_common
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
USEMODULE += progress_bar
|
USEMODULE += progress_bar
|
||||||
|
|
||||||
PROGRESS_BAR_LENGTH ?= 50
|
CONFIG_PROGRESS_BAR_LENGTH ?= 50
|
||||||
PROGRESS_BAR_FULL_CHARACTER ?= "█"
|
CONFIG_PROGRESS_BAR_FULL_CHARACTER ?= "█"
|
||||||
PROGRESS_BAR_EMPTY_CHARACTER ?= " "
|
CONFIG_PROGRESS_BAR_EMPTY_CHARACTER ?= " "
|
||||||
|
|
||||||
# Other nice progress bar characters:
|
# Other nice progress bar characters:
|
||||||
#PROGRESS_BAR_FULL_CHARACTER ?= "◉"
|
#CONFIG_PROGRESS_BAR_FULL_CHARACTER ?= "◉"
|
||||||
#PROGRESS_BAR_EMPTY_CHARACTER ?= "◯"
|
#CONFIG_PROGRESS_BAR_EMPTY_CHARACTER ?= "◯"
|
||||||
#PROGRESS_BAR_FULL_CHARACTER ?= "▣"
|
#CONFIG_PROGRESS_BAR_FULL_CHARACTER ?= "▣"
|
||||||
#PROGRESS_BAR_EMPTY_CHARACTER ?= "▢"
|
#CONFIG_PROGRESS_BAR_EMPTY_CHARACTER ?= "▢"
|
||||||
|
|
||||||
CFLAGS += -DPROGRESS_BAR_FULL_CHARACTER=\"$(PROGRESS_BAR_FULL_CHARACTER)\"
|
CFLAGS += -DCONFIG_PROGRESS_BAR_FULL_CHARACTER=\"$(CONFIG_PROGRESS_BAR_FULL_CHARACTER)\"
|
||||||
CFLAGS += -DPROGRESS_BAR_EMPTY_CHARACTER=\"$(PROGRESS_BAR_EMPTY_CHARACTER)\"
|
CFLAGS += -DCONFIG_PROGRESS_BAR_EMPTY_CHARACTER=\"$(CONFIG_PROGRESS_BAR_EMPTY_CHARACTER)\"
|
||||||
CFLAGS += -DPROGRESS_BAR_LENGTH=$(PROGRESS_BAR_LENGTH)
|
CFLAGS += -DCONFIG_PROGRESS_BAR_LENGTH=$(CONFIG_PROGRESS_BAR_LENGTH)
|
||||||
|
|
||||||
include $(RIOTBASE)/Makefile.include
|
include $(RIOTBASE)/Makefile.include
|
||||||
|
|
||||||
# Make custom progress bar characters available in Python test script via
|
# Make custom progress bar characters available in Python test script via
|
||||||
# environment variables
|
# environment variables
|
||||||
export PROGRESS_BAR_FULL_CHARACTER
|
export CONFIG_PROGRESS_BAR_FULL_CHARACTER
|
||||||
export PROGRESS_BAR_EMPTY_CHARACTER
|
export CONFIG_PROGRESS_BAR_EMPTY_CHARACTER
|
||||||
export PROGRESS_BAR_LENGTH
|
export CONFIG_PROGRESS_BAR_LENGTH
|
||||||
|
|||||||
@ -12,9 +12,9 @@ from testrunner import run
|
|||||||
|
|
||||||
|
|
||||||
TIMEOUT = 60
|
TIMEOUT = 60
|
||||||
LENGTH = int(os.getenv('PROGRESS_BAR_LENGTH'))
|
LENGTH = int(os.getenv('CONFIG_PROGRESS_BAR_LENGTH'))
|
||||||
FULL_CHARACTER = os.getenv('PROGRESS_BAR_FULL_CHARACTER')[1:-1]
|
FULL_CHARACTER = os.getenv('CONFIG_PROGRESS_BAR_FULL_CHARACTER')[1:-1]
|
||||||
EMPTY_CHARACTER = os.getenv('PROGRESS_BAR_EMPTY_CHARACTER')[1:-1]
|
EMPTY_CHARACTER = os.getenv('CONFIG_PROGRESS_BAR_EMPTY_CHARACTER')[1:-1]
|
||||||
|
|
||||||
|
|
||||||
def testfunc(child):
|
def testfunc(child):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user