mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-16 10:03:50 +01:00
drivers/sen5x: added dedicated driver for the SEN5x
This commit is contained in:
parent
8a76cee6c5
commit
fadeafdf85
@ -46,6 +46,7 @@ rsource "matrix_keypad/Kconfig"
|
||||
rsource "mma8x5x/Kconfig"
|
||||
rsource "opt3001/Kconfig"
|
||||
rsource "seesaw_soil/Kconfig"
|
||||
rsource "sen5x/Kconfig"
|
||||
rsource "sht2x/Kconfig"
|
||||
rsource "sm_pwm_01c/Kconfig"
|
||||
rsource "sps30/Kconfig"
|
||||
|
||||
@ -188,6 +188,10 @@ ifneq (,$(filter sdp3x_%,$(USEMODULE)))
|
||||
USEMODULE += sdp3x
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sen5%,$(USEMODULE)))
|
||||
USEMODULE += sen5x
|
||||
endif
|
||||
|
||||
ifneq (,$(filter servo_%,$(USEMODULE)))
|
||||
USEMODULE += servo
|
||||
endif
|
||||
|
||||
300
drivers/include/sen5x.h
Normal file
300
drivers/include/sen5x.h
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TUÚ Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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_sen5x Sensirion Embedded I2C SEN5x Driver
|
||||
* @ingroup drivers_sensors
|
||||
* @ingroup drivers_saul
|
||||
* @brief Driver for I2C communication to SEN5x devices.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Daniel Prigoshij <d.prigoshij@tu-braunschweig.de>
|
||||
*/
|
||||
|
||||
#ifndef SEN5X_H
|
||||
#define SEN5X_H
|
||||
|
||||
/* Add header includes here */
|
||||
|
||||
#include "periph/i2c.h"
|
||||
#include <stdint.h>
|
||||
#include "saul.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Declare the API of the driver */
|
||||
|
||||
/**
|
||||
* @brief Wrapper for measured values
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t mass_concentration_pm1p0; /**< raw value is scaled with factor 10: PM1.0 [µg/m³] = value / 10 */
|
||||
uint16_t mass_concentration_pm2p5; /**< raw value is scaled with factor 10: PM2.5 [µg/m³] = value / 10 */
|
||||
uint16_t mass_concentration_pm4p0; /**< raw value is scaled with factor 10: PM4.0 [µg/m³] = value / 10 */
|
||||
uint16_t mass_concentration_pm10p0; /**< raw value is scaled with factor 10: PM10.0 [µg/m³] = value / 10 */
|
||||
uint16_t number_concentration_pm0p5; /**< raw value is scaled with factor 10: PM0.5 [#/cm³] = value / 10 */
|
||||
uint16_t number_concentration_pm1p0; /**< raw value is scaled with factor 10: PM1.0 [#/cm³] = value / 10 */
|
||||
uint16_t number_concentration_pm2p5; /**< raw value is scaled with factor 10: PM2.5 [#/cm³] = value / 10 */
|
||||
uint16_t number_concentration_pm4p0; /**< raw value is scaled with factor 10: PM4.0 [#/cm³] = value / 10 */
|
||||
uint16_t number_concentration_pm10p0; /**< raw value is scaled with factor 10: PM10.0 [#/cm³] = value / 10 */
|
||||
uint16_t typical_particle_size; /**< raw value is scaled with factor 1000: Size [µm] = value / 1000*/
|
||||
int16_t ambient_humidity; /**< raw value is scaled with factor 100: RH [%] = value / 100 */
|
||||
int16_t ambient_temperature; /**< raw value is scaled with factor 200: T [°C] = value / 200 */
|
||||
int16_t voc_index; /**< raw value is scaled with factor 10: VOC Index = value / 10 */
|
||||
int16_t nox_index; /**< raw value is scaled with factor 10: NOx Index = value / 10 */
|
||||
} sen5x_measurement_t;
|
||||
|
||||
/**
|
||||
* @brief Device initialization parameters
|
||||
*/
|
||||
typedef struct {
|
||||
i2c_t i2c_dev; /**< I2C device which is used */
|
||||
uint8_t i2c_addr; /**< I2C address */
|
||||
} sen5x_params_t;
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for the driver
|
||||
*/
|
||||
typedef struct {
|
||||
sen5x_params_t params; /**< Device initialization parameters */
|
||||
} sen5x_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the given device
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] params Initialization parameters
|
||||
*/
|
||||
void sen5x_init(sen5x_t *dev, const sen5x_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Execute a reset on the given device
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*/
|
||||
void sen5x_reset(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Starts a continuous measurement
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*/
|
||||
void sen5x_wake(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Starts a continuous measurement without PM. Only humidity, temperature, VOC and NOx are measured.
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*/
|
||||
void sen5x_wake_no_pm(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Stops the measurement and returns to idle mode
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*/
|
||||
void sen5x_sleep(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the fan to maximum speed, to clean it within 10 seconds
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*/
|
||||
void sen5x_clean_fan(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the fan to maximum speed, to clean it within 10 seconds
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*
|
||||
* @return 0 if no new measurements are available
|
||||
* @return 1 if new measuremtns are ready to be read
|
||||
*/
|
||||
bool sen5x_data_ready_flag(const sen5x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Read measured mass concentration, humidity and temperature values
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] values Pointer to wrapper containing all measured values
|
||||
*/
|
||||
void sen5x_read_values(const sen5x_t *dev, sen5x_measurement_t *values);
|
||||
|
||||
/**
|
||||
* @brief Read measured particle matter values
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] values Pointer to wrapper containing all measured values
|
||||
*/
|
||||
void sen5x_read_pm_values(const sen5x_t *dev, sen5x_measurement_t *values);
|
||||
|
||||
/**
|
||||
* @brief Set a custom temperature offset to the ambient temperature
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] temp_offset Temperature offset in °C
|
||||
* @param[in] slope Normalized temperature offset slope
|
||||
* @param[in] time_constant Time constant in seconds
|
||||
*/
|
||||
void sen5x_set_temperature_offset(const sen5x_t *dev, int16_t temp_offset, int16_t slope, uint16_t time_constant);
|
||||
|
||||
/**
|
||||
* @brief Set a custom temperature offset to the ambient temperature
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] temp_offset Temperature offset in °C
|
||||
* @param[out] slope Normalized temperature offset slope
|
||||
* @param[out] time_constant Time constant in seconds
|
||||
*/
|
||||
void sen5x_get_temperature_offset(const sen5x_t *dev, int16_t *temp_offset, int16_t *slope, uint16_t *time_constant);
|
||||
|
||||
/**
|
||||
* @brief Set the parameter for a warm start on the device, to improve initial accuracy of the ambient temperature output
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] warm_start Warm start behavior as a value in the range from
|
||||
* 0 (cold start, default) to 65535 (warm start).
|
||||
*/
|
||||
void sen5x_set_warm_start(const sen5x_t *dev, uint16_t warm_start);
|
||||
|
||||
/**
|
||||
* @brief Get the warm start paramater
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] warm_start Warm start behavior as a value in the range from
|
||||
* 0 (cold start, default) to 65535 (warm start).
|
||||
*/
|
||||
void sen5x_get_warm_start(const sen5x_t *dev, uint16_t *warm_start);
|
||||
|
||||
/**
|
||||
* @brief Set the parameters for the VOC Algorithm tuning
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] index_offset VOC index representing typical (average) conditions
|
||||
* @param[in] learning_time_offset_hours Time constant to estimate the VOC algorithm offset from the
|
||||
* history in hours
|
||||
* @param[in] learning_time_gain_hours Time constant to estimate the VOC algorithm gain from the history
|
||||
* in hours
|
||||
* @param[in] gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* @param[in] std_initial Initial estimate for standard deviation
|
||||
* @param[in] gain_factor Gain factor to amplify or to attenuate the VOC index output
|
||||
*/
|
||||
void sen5x_set_voc_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor);
|
||||
|
||||
/**
|
||||
* @brief Get the VOC Algortihm tuning parameters
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] index_offset VOC index representing typical (average) conditions
|
||||
* @param[out] learning_time_offset_hours Time constant to estimate the VOC algorithm offset from the
|
||||
* history in hours
|
||||
* @param[out] learning_time_gain_hours Time constant to estimate the VOC algorithm gain from the history
|
||||
* in hours
|
||||
* @param[out] gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* @param[out] std_initial Initial estimate for standard deviation
|
||||
* @param[out] gain_factor Gain factor to amplify or to attenuate the VOC index output
|
||||
*/
|
||||
void sen5x_get_voc_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t *index_offset, int16_t *learning_time_offset_hours,
|
||||
int16_t *learning_time_gain_hours, int16_t *gating_max_duration_minutes,
|
||||
int16_t *std_initial, int16_t *gain_factor);
|
||||
|
||||
/**
|
||||
* @brief Set the parameters for the NOx Algorithm tuning
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] index_offset NOx index representing typical (average) conditions
|
||||
* @param[in] learning_time_offset_hours Time constant to estimate the NOx algorithm offset from the
|
||||
* history in hours
|
||||
* @param[in] learning_time_gain_hours The time constant to estimate the NOx algorithm gain from the
|
||||
* history has no impact for NOx. This parameter is still in place for
|
||||
* consistency reasons with the VOC tuning parameters command.
|
||||
* This parameter must always be set to 12 hours
|
||||
* @param[in] gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* @param[in] std_initial Initial estimate for standard deviation
|
||||
* @param[in] gain_factor Gain factor to amplify or to attenuate the NOx index output
|
||||
*/
|
||||
void sen5x_set_nox_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor);
|
||||
|
||||
/**
|
||||
* @brief Get the NOx Algortihm tuning parameters
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] index_offset NOx index representing typical (average) conditions
|
||||
* @param[out] learning_time_offset_hours Time constant to estimate the NOx algorithm offset from the
|
||||
* history in hours
|
||||
* @param[out] learning_time_gain_hours The time constant to estimate the NOx algorithm gain from the
|
||||
* history has no impact for NOx. This parameter is still in place for
|
||||
* consistency reasons with the VOC tuning parameters command.
|
||||
* This parameter must always be set to 12 hours
|
||||
* @param[out] gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* @param[out] std_initial Initial estimate for standard deviation
|
||||
* @param[out] gain_factor Gain factor to amplify or to attenuate the NOx index output
|
||||
*/
|
||||
void sen5x_get_nox_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t *index_offset, int16_t *learning_time_offset_hours,
|
||||
int16_t *learning_time_gain_hours, int16_t *gating_max_duration_minutes,
|
||||
int16_t *std_initial, int16_t *gain_factor);
|
||||
|
||||
/**
|
||||
* @brief Set the mode for the RH/T acceleration algorithm
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] mode RH/T accelaration mode:
|
||||
* = 0: Low Acceleration
|
||||
* = 1: High Acceleration
|
||||
* = 2: Medium Acceleration
|
||||
*/
|
||||
void sen5x_set_rht_acceleration(const sen5x_t *dev, uint16_t mode);
|
||||
|
||||
/**
|
||||
* @brief Get the mode for the RH/T acceleration algorithm
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] mode RH/T accelaration mode:
|
||||
* = 0: Low Acceleration
|
||||
* = 1: High Acceleration
|
||||
* = 2: Medium Acceleration
|
||||
*/
|
||||
void sen5x_get_rht_acceleration(const sen5x_t *dev, uint16_t *mode);
|
||||
|
||||
/**
|
||||
* @brief Get the VOC Algorithm state
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[in] state VOC Algorithm state
|
||||
* @param[in] state_size Size of the VOC Algorithm state
|
||||
*/
|
||||
void sen5x_set_voc_state(const sen5x_t *dev, const uint8_t *state, uint8_t state_size);
|
||||
|
||||
/**
|
||||
* @brief Set the VOC Algorithm state
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
* @param[out] state VOC Algorithm state
|
||||
* @param[in] state_size Size of the VOC Algorithm state
|
||||
*/
|
||||
void sen5x_get_voc_state(const sen5x_t *dev, uint8_t *state, uint8_t state_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEN5X_H */
|
||||
/** @} */
|
||||
139
drivers/saul/init_devs/auto_init_sen5x.c
Normal file
139
drivers/saul/init_devs/auto_init_sen5x.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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 of sen5x device driver.
|
||||
*
|
||||
* @author Daniel Prigoshij <prigoshi@ibr.cs.tu-bs.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "log.h"
|
||||
#include "saul_reg.h"
|
||||
#include "sen5x.h"
|
||||
#include "sen5x_params.h"
|
||||
|
||||
/**
|
||||
* @brief Allocation of memory for device descriptors
|
||||
*/
|
||||
static sen5x_t sen5x_devs[SEN5X_NUM];
|
||||
|
||||
/**
|
||||
* @brief Memory for the SAUL registry entries
|
||||
*/
|
||||
static saul_reg_t saul_entries[SEN5X_NUM * 12];
|
||||
|
||||
/**
|
||||
* @brief Define the number of saul info
|
||||
*/
|
||||
#define SEN5X_INFO_NUM ARRAY_SIZE(sen5x_saul_info)
|
||||
|
||||
/**
|
||||
* @name Reference the driver structs.
|
||||
* @{
|
||||
*/
|
||||
extern const saul_driver_t sen5x_mass_concentration_pm1p0_driver;
|
||||
extern const saul_driver_t sen5x_mass_concentration_pm2p5_driver;
|
||||
extern const saul_driver_t sen5x_mass_concentration_pm4p0_driver;
|
||||
extern const saul_driver_t sen5x_mass_concentration_pm10p0_driver;
|
||||
extern const saul_driver_t sen5x_number_concentration_pm0p5_driver;
|
||||
extern const saul_driver_t sen5x_number_concentration_pm1p0_driver;
|
||||
extern const saul_driver_t sen5x_number_concentration_pm2p5_driver;
|
||||
extern const saul_driver_t sen5x_number_concentration_pm4p0_driver;
|
||||
extern const saul_driver_t sen5x_number_concentration_pm10p0_driver;
|
||||
extern const saul_driver_t sen5x_typical_particle_size_driver;
|
||||
extern const saul_driver_t sen5x_ambient_humidity_driver;
|
||||
extern const saul_driver_t sen5x_ambient_temperature_driver;
|
||||
/** @} */
|
||||
|
||||
void auto_init_sen5x(void)
|
||||
{
|
||||
assert(SEN5X_INFO_NUM == SEN5X_NUM);
|
||||
|
||||
for (unsigned i = 0; i < SEN5X_NUM; i++) {
|
||||
LOG_DEBUG("[auto_init_saul] initializing SEN5X #%u\n", i);
|
||||
|
||||
if (sen5x_init(&sen5x_devs[i], &sen5x_params[i]) != 0) {
|
||||
LOG_ERROR("[auto_init_saul] error initializing SEN5X #%u\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
sen5x_wake(&sen5x_devs[i]);
|
||||
|
||||
/* Mass Concentration pm1p0 */
|
||||
saul_entries[(i * 12)].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12)].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12)].driver = &sen5x_mass_concentration_pm1p0_driver;
|
||||
|
||||
/* Mass Concentration pm2p5 */
|
||||
saul_entries[(i * 12) + 1].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 1].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 1].driver = &sen5x_mass_concentration_pm2p5_driver;
|
||||
|
||||
/* Mass Concentration pm4p0 */
|
||||
saul_entries[(i * 12) + 2].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 2].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 2].driver = &sen5x_mass_concentration_pm4p0_driver;
|
||||
|
||||
/* Mass Concentration pm10p0 */
|
||||
saul_entries[(i * 12) + 3].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 3].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 3].driver = &sen5x_mass_concentration_pm10p0_driver;
|
||||
|
||||
/* Number Concentration pm0p5 */
|
||||
saul_entries[(i * 12) + 4].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 4].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 4].driver = &sen5x_number_concentration_pm0p5_driver;
|
||||
|
||||
/* Number Concentration pm1p0 */
|
||||
saul_entries[(i * 12) + 5].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 5].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 5].driver = &sen5x_number_concentration_pm1p0_driver;
|
||||
|
||||
/* Number Concentration pm2p5 */
|
||||
saul_entries[(i * 12) + 6].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 6].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 6].driver = &sen5x_number_concentration_pm2p5_driver;
|
||||
|
||||
/* Number Concentration pm4p0 */
|
||||
saul_entries[(i * 12) + 7].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 7].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 7].driver = &sen5x_number_concentration_pm4p0_driver;
|
||||
|
||||
/* Number Concentration pm10p0 */
|
||||
saul_entries[(i * 12) + 8].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 8].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 8].driver = &sen5x_number_concentration_pm10p0_driver;
|
||||
|
||||
/* Typical particle size */
|
||||
saul_entries[(i * 12) + 9].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 9].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 9].driver = &sen5x_typical_particle_size_driver;
|
||||
|
||||
/* Ambient humidity */
|
||||
saul_entries[(i * 12) + 10].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 10].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 10].driver = &sen5x_ambient_humidity_driver;
|
||||
|
||||
/* Ambient temperature */
|
||||
saul_entries[(i * 12) + 11].dev = &(sen5x_devs[i]);
|
||||
saul_entries[(i * 12) + 11].name = sen5x_saul_info[i].name;
|
||||
saul_entries[(i * 12) + 11].driver = &sen5x_ambient_temperature_driver;
|
||||
|
||||
/* Add register entries to saul */
|
||||
for (unsigned int j = 0; j < 12; j++) {
|
||||
saul_reg_add(&(saul_entries[(i * 4) + j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
drivers/sen5x/Kconfig
Normal file
11
drivers/sen5x/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
#
|
||||
# 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_SEN5X
|
||||
bool "Sensirion Embedded I2C SEN5x Driver"
|
||||
depends on TEST_KCONFIG
|
||||
select MODULE_PERIPH_I2C
|
||||
select MODULE_ZTIMER
|
||||
1
drivers/sen5x/Makefile
Normal file
1
drivers/sen5x/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
2
drivers/sen5x/Makefile.dep
Normal file
2
drivers/sen5x/Makefile.dep
Normal file
@ -0,0 +1,2 @@
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
USEMODULE += xtimer
|
||||
2
drivers/sen5x/Makefile.include
Normal file
2
drivers/sen5x/Makefile.include
Normal file
@ -0,0 +1,2 @@
|
||||
USEMODULE_INCLUDES_sen5x := $(LAST_MAKEFILEDIR)/include
|
||||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_sen5x)
|
||||
37
drivers/sen5x/include/sen5x_constants.h
Normal file
37
drivers/sen5x/include/sen5x_constants.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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_sen5x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Internal addresses, registers and constants
|
||||
*
|
||||
* @author Daniel Prigoshij <d.prigoshij@tu-braunschweig.de>
|
||||
*/
|
||||
|
||||
#ifndef SEN5X_CONSTANTS_H
|
||||
#define SEN5X_CONSTANTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* define here the addresses, register and constants of the driver */
|
||||
|
||||
#ifndef SEN5X_I2C_ADDRESS
|
||||
#define SEN5X_I2C_ADDRESS (0x69)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEN5X_CONSTANTS_H */
|
||||
/** @} */
|
||||
715
drivers/sen5x/include/sen5x_i2c.h
Normal file
715
drivers/sen5x/include/sen5x_i2c.h
Normal file
@ -0,0 +1,715 @@
|
||||
/*
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED
|
||||
*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-109-gb259776
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SEN5X_I2C_H
|
||||
#define SEN5X_I2C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sensirion_config.h"
|
||||
|
||||
/**
|
||||
* sen5x_start_measurement() - Starts a continuous measurement.
|
||||
*
|
||||
* After starting the measurement, it takes some time (~1s) until the first
|
||||
* measurement results are available. You could poll with the command
|
||||
* 0x0202 \"Read Data Ready\" to check when the results are ready to read.
|
||||
*
|
||||
* This command is only available in idle mode. If the device is already
|
||||
* in any measure mode, this command has no effect.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_start_measurement(void);
|
||||
|
||||
/**
|
||||
* sen5x_start_measurement_without_pm() - Starts a continuous measurement
|
||||
* without PM. Only humidity, temperature, VOC and NOx are available in this
|
||||
* mode. Laser and fan are switched off to keep power consumption low.
|
||||
*
|
||||
* After starting the measurement, it takes some time (~1s) until the first
|
||||
* measurement results are available. You could poll with the command
|
||||
* 0x0202 \"Read Data Ready\" to check when the results are ready to read.
|
||||
*
|
||||
* This command is only available in idle mode. If the device is already
|
||||
* in any measure mode, this command has no effect.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_start_measurement_without_pm(void);
|
||||
|
||||
/**
|
||||
* sen5x_stop_measurement() - Stops the measurement and returns to idle mode.
|
||||
*
|
||||
* If the device is already in idle mode, this command has no effect.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_stop_measurement(void);
|
||||
|
||||
/**
|
||||
* sen5x_read_data_ready() - This command can be used to check if new
|
||||
* measurement results are ready to read. The data ready flag is automatically
|
||||
* reset after reading the measurement values with the 0x03.. \"Read Measured
|
||||
* Values\" commands.
|
||||
*
|
||||
* @note During fan (auto-)cleaning, no measurement data is available for
|
||||
* several seconds and thus this flag will not be set until cleaning has
|
||||
* finished. So please expect gaps of several seconds at any time if fan
|
||||
* auto-cleaning is enabled.
|
||||
*
|
||||
* @param padding Padding byte, always 0x00.
|
||||
*
|
||||
* @param data_ready True (0x01) if data is ready, False (0x00) if not. When no
|
||||
* measurement is running, False will be returned.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_data_ready(bool* data_ready);
|
||||
|
||||
/**
|
||||
* sen5x_read_measured_values() - Returns the measured values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data is
|
||||
* available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be at their upper limit (0xFFFF for `uint16`,
|
||||
* 0x7FFF for `int16`).
|
||||
*
|
||||
* @param mass_concentration_pm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param ambient_humidity Value is scaled with factor 100: RH [%] = value / 100
|
||||
* @note If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param ambient_temperature Value is scaled with factor 200:
|
||||
* T [°C] = value / 200
|
||||
* @note If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param voc_index Value is scaled with factor 10: VOC Index = value / 10
|
||||
* @note If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param nox_index Value is scaled with factor 10: NOx Index = value / 10
|
||||
* @note If this value is unknown, 0x7FFF is returned. During
|
||||
* the first 10..11 seconds after power-on or device reset, this
|
||||
* value will be 0x7FFF as well.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_measured_values(uint16_t* mass_concentration_pm1p0,
|
||||
uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0,
|
||||
uint16_t* mass_concentration_pm10p0,
|
||||
int16_t* ambient_humidity,
|
||||
int16_t* ambient_temperature,
|
||||
int16_t* voc_index, int16_t* nox_index);
|
||||
|
||||
/**
|
||||
* sen5x_read_measured_raw_values() - Returns the measured raw values.
|
||||
|
||||
The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
data is available since the last read operation. If no new data is
|
||||
available, the previous values will be returned again. If no data
|
||||
is available at all (e.g. measurement not running for at least one
|
||||
second), all values will be at their upper limit (0xFFFF for `uint16`,
|
||||
0x7FFF for `int16`).
|
||||
*
|
||||
* @param raw_humidity Value is scaled with factor 100: RH [%] = value / 100
|
||||
* @note If this value is unknown, 0x7FFF is returned.
|
||||
*
|
||||
* @param raw_temperature Value is scaled with factor 200: T [°C] = value / 200
|
||||
* @note If this value is unknown, 0x7FFF is returned.
|
||||
*
|
||||
* @param raw_voc Raw measured VOC ticks without scale factor.
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param raw_nox Raw measured NOx ticks without scale factor.
|
||||
* @note If this value is unknown, 0xFFFF is returned. During
|
||||
* the first 10..11 seconds after power-on or device reset, this
|
||||
* value will be 0xFFFF as well.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_measured_raw_values(int16_t* raw_humidity,
|
||||
int16_t* raw_temperature,
|
||||
uint16_t* raw_voc, uint16_t* raw_nox);
|
||||
|
||||
/**
|
||||
* sen5x_read_measured_values_sen50() - Returns the measured values for SEN50.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data is
|
||||
* available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be at their upper limit (0xFFFF).
|
||||
*
|
||||
* @param mass_concentration_pm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_measured_values_sen50(uint16_t* mass_concentration_pm1p0,
|
||||
uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0,
|
||||
uint16_t* mass_concentration_pm10p0);
|
||||
|
||||
/**
|
||||
* sen5x_read_measured_pm_values() - Returns the measured particulate matter
|
||||
* values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data
|
||||
* is available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be 0xFFFF.
|
||||
*
|
||||
* @param mass_concentration_pm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param mass_concentration_pm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [µg/m³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param number_concentration_pm0p5 Value is scaled with factor 10:
|
||||
* PM0.5 [#/cm³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param number_concentration_pm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [#/cm³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param number_concentration_pm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [#/cm³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param number_concentration_pm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [#/cm³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param number_concentration_pm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [#/cm³] = value / 10
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @param typical_particle_size Value is scaled with factor 1000:
|
||||
* Size [µm] = value / 1000
|
||||
* @note If this value is unknown, 0xFFFF is returned.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_measured_pm_values(
|
||||
uint16_t* mass_concentration_pm1p0, uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0, uint16_t* mass_concentration_pm10p0,
|
||||
uint16_t* number_concentration_pm0p5, uint16_t* number_concentration_pm1p0,
|
||||
uint16_t* number_concentration_pm2p5, uint16_t* number_concentration_pm4p0,
|
||||
uint16_t* number_concentration_pm10p0, uint16_t* typical_particle_size);
|
||||
|
||||
/**
|
||||
* sen5x_start_fan_cleaning() - Starts the fan cleaning manually. The \"data
|
||||
* ready\"-flag will be cleared immediately and during the next few seconds, no
|
||||
* new measurement results will be available (old values will be returned). Once
|
||||
* the cleaning is finished, the \"data ready\"-flag will be set and new
|
||||
* measurement results will be available.
|
||||
*
|
||||
* When executing this command while cleaning is already active, the
|
||||
* command does nothing.
|
||||
*
|
||||
* If you stop the measurement while fan cleaning is active, the cleaning
|
||||
* will be aborted immediately.
|
||||
*
|
||||
* @note This command is only available in measure mode with PM measurement
|
||||
* enabled, i.e. only if the fan is already running. In any other state, this
|
||||
* command does nothing.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_start_fan_cleaning(void);
|
||||
|
||||
/**
|
||||
* sen5x_set_temperature_offset_parameters() - Sets the temperature offset
|
||||
* parameters for the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param temp_offset Constant temperature offset scaled with factor 200 (T [°C]
|
||||
* = value / 200). The default value is 0.
|
||||
*
|
||||
* @param slope Normalized temperature offset slope scaled with factor 10000
|
||||
* (applied factor = value / 10000). The default value is 0.
|
||||
*
|
||||
* @param time_constant Time constant [s] how fast the new slope and offset will
|
||||
* be applied. After the specified value in seconds, 63% of the new slope and
|
||||
* offset are applied. A time constant of zero means the new values will be
|
||||
* applied immediately (within the next measure interval of 1 second).
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_temperature_offset_parameters(int16_t temp_offset,
|
||||
int16_t slope,
|
||||
uint16_t time_constant);
|
||||
|
||||
/**
|
||||
* sen5x_get_temperature_offset_parameters() - Gets the temperature offset
|
||||
* parameters from the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param temp_offset Constant temperature offset scaled with factor 200 (T [°C]
|
||||
* = value / 200).
|
||||
*
|
||||
* @param slope Normalized temperature offset slope scaled with factor 10000
|
||||
* (applied factor = value / 10000).
|
||||
*
|
||||
* @param time_constant Time constant [s] how fast the slope and offset are
|
||||
* applied. After the specified value in seconds, 63% of the new slope and
|
||||
* offset are applied.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_temperature_offset_parameters(int16_t* temp_offset,
|
||||
int16_t* slope,
|
||||
uint16_t* time_constant);
|
||||
|
||||
/**
|
||||
* sen5x_set_warm_start_parameter() - Sets the warm start parameter for the
|
||||
* device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This parameter can be changed in any state of the device (and the
|
||||
* getter immediately returns the new value), but it is applied only the next
|
||||
* time starting a measurement, i.e. when sending a \"Start Measurement\"
|
||||
* command! So the parameter needs to be set *before* a warm-start measurement
|
||||
* is started.
|
||||
*
|
||||
* @param warm_start Warm start behavior as a value in the range from 0 (cold
|
||||
* start) to 65535 (warm start). The default value is 0.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_warm_start_parameter(uint16_t warm_start);
|
||||
|
||||
/**
|
||||
* sen5x_get_warm_start_parameter() - Gets the warm start parameter from the
|
||||
* device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param warm_start Warm start behavior as a value in the range from 0 (cold
|
||||
* start) to 65535 (warm start).
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_warm_start_parameter(uint16_t* warm_start);
|
||||
|
||||
/**
|
||||
* sen5x_set_voc_algorithm_tuning_parameters() - Sets the tuning parameters of
|
||||
* the VOC algorithm.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This command is available only in idle mode. In measure mode, this
|
||||
* command has no effect. In addition, it has no effect if at least one
|
||||
* parameter is outside the specified range.
|
||||
*
|
||||
* @param index_offset VOC index representing typical (average) conditions.
|
||||
* Allowed values are in range 1..250. The default value is 100.
|
||||
*
|
||||
* @param learning_time_offset_hours Time constant to estimate the VOC algorithm
|
||||
* offset from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time. Allowed values are in range 1..1000. The default
|
||||
* value is 12 hours.
|
||||
*
|
||||
* @param learning_time_gain_hours Time constant to estimate the VOC algorithm
|
||||
* gain from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time. Allowed values are in range 1..1000. The default
|
||||
* value is 12 hours.
|
||||
*
|
||||
* @param gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high VOC index signal). Set to zero to disable
|
||||
* the gating. Allowed values are in range 0..3000. The default value is 180
|
||||
* minutes.
|
||||
*
|
||||
* @param std_initial Initial estimate for standard deviation. Lower value
|
||||
* boosts events during initial learning period, but may result in larger
|
||||
* device-to-device variations. Allowed values are in range 10..5000. The
|
||||
* default value is 50.
|
||||
*
|
||||
* @param gain_factor Gain factor to amplify or to attenuate the VOC index
|
||||
* output. Allowed values are in range 1..1000. The default value is 230.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_voc_algorithm_tuning_parameters(
|
||||
int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor);
|
||||
|
||||
/**
|
||||
* sen5x_get_voc_algorithm_tuning_parameters() - Gets the currently set tuning
|
||||
* parameters of the VOC algorithm.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param index_offset VOC index representing typical (average) conditions.
|
||||
*
|
||||
* @param learning_time_offset_hours Time constant to estimate the VOC algorithm
|
||||
* offset from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time.
|
||||
*
|
||||
* @param learning_time_gain_hours Time constant to estimate the VOC algorithm
|
||||
* gain from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time.
|
||||
*
|
||||
* @param gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high VOC index signal). Zero disables the gating.
|
||||
*
|
||||
* @param std_initial Initial estimate for standard deviation. Lower value
|
||||
* boosts events during initial learning period, but may result in larger
|
||||
* device-to-device variations.
|
||||
*
|
||||
* @param gain_factor Gain factor to amplify or to attenuate the VOC index
|
||||
* output.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_voc_algorithm_tuning_parameters(
|
||||
int16_t* index_offset, int16_t* learning_time_offset_hours,
|
||||
int16_t* learning_time_gain_hours, int16_t* gating_max_duration_minutes,
|
||||
int16_t* std_initial, int16_t* gain_factor);
|
||||
|
||||
/**
|
||||
* sen5x_set_nox_algorithm_tuning_parameters() - Sets the tuning parameters of
|
||||
* the NOx algorithm.
|
||||
*
|
||||
* Supported sensors: SEN55
|
||||
*
|
||||
* @note This command is available only in idle mode. In measure mode, this
|
||||
* command has no effect. In addition, it has no effect if at least one
|
||||
* parameter is outside the specified range.
|
||||
*
|
||||
* @param index_offset NOx index representing typical (average) conditions.
|
||||
* Allowed values are in range 1..250. The default value is 1.
|
||||
*
|
||||
* @param learning_time_offset_hours Time constant to estimate the NOx algorithm
|
||||
* offset from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time. Allowed values are in range 1..1000. The default
|
||||
* value is 12 hours.
|
||||
*
|
||||
* @param learning_time_gain_hours The time constant to estimate the NOx
|
||||
* algorithm gain from the history has no impact for NOx. This parameter is
|
||||
* still in place for consistency reasons with the VOC tuning parameters
|
||||
* command. This parameter must always be set to 12 hours.
|
||||
*
|
||||
* @param gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high NOx index signal). Set to zero to disable
|
||||
* the gating. Allowed values are in range 0..3000. The default value is 720
|
||||
* minutes.
|
||||
*
|
||||
* @param std_initial The initial estimate for standard deviation parameter has
|
||||
* no impact for NOx. This parameter is still in place for consistency reasons
|
||||
* with the VOC tuning parameters command. This parameter must always be set
|
||||
* to 50.
|
||||
*
|
||||
* @param gain_factor Gain factor to amplify or to attenuate the NOx index
|
||||
* output. Allowed values are in range 1..1000. The default value is 230.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_nox_algorithm_tuning_parameters(
|
||||
int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor);
|
||||
|
||||
/**
|
||||
* sen5x_get_nox_algorithm_tuning_parameters() - Gets the currently set tuning
|
||||
* parameters of the NOx algorithm.
|
||||
*
|
||||
* Supported sensors: SEN55
|
||||
*
|
||||
* @param index_offset NOx index representing typical (average) conditions.
|
||||
*
|
||||
* @param learning_time_offset_hours Time constant to estimate the NOx algorithm
|
||||
* offset from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time.
|
||||
*
|
||||
* @param learning_time_gain_hours The time constant to estimate the NOx
|
||||
* algorithm gain from the history has no impact for NOx. This parameter is
|
||||
* still in place for consistency reasons with the VOC tuning parameters
|
||||
* command.
|
||||
*
|
||||
* @param gating_max_duration_minutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high NOx index signal). Zero disables the gating.
|
||||
*
|
||||
* @param std_initial The initial estimate for standard deviation has no impact
|
||||
* for NOx. This parameter is still in place for consistency reasons with the
|
||||
* VOC tuning parameters command.
|
||||
*
|
||||
* @param gain_factor Gain factor to amplify or to attenuate the NOx index
|
||||
* output.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_nox_algorithm_tuning_parameters(
|
||||
int16_t* index_offset, int16_t* learning_time_offset_hours,
|
||||
int16_t* learning_time_gain_hours, int16_t* gating_max_duration_minutes,
|
||||
int16_t* std_initial, int16_t* gain_factor);
|
||||
|
||||
/**
|
||||
* sen5x_set_rht_acceleration_mode() - Sets the RH/T acceleration mode.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This parameter can be changed in any state of the device (and the
|
||||
* getter immediately returns the new value), but it is applied only the next
|
||||
* time starting a measurement, i.e. when sending a \"Start Measurement\"
|
||||
* command. So the parameter needs to be set *before* a new measurement is
|
||||
* started.
|
||||
*
|
||||
* @param mode The new RH/T acceleration mode.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_rht_acceleration_mode(uint16_t mode);
|
||||
|
||||
/**
|
||||
* sen5x_get_rht_acceleration_mode() - Gets the RH/T acceleration mode.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param mode The current RH/T acceleration mode.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_rht_acceleration_mode(uint16_t* mode);
|
||||
|
||||
/**
|
||||
* sen5x_set_voc_algorithm_state() - Sets the VOC algorithm state previously
|
||||
* received with the \"Get VOC Algorithm State\" command.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This command is only available in idle mode and the state will be
|
||||
* applied only once when starting the next measurement. Any further
|
||||
* measurements (i.e. when stopping and restarting the measure mode) will reset
|
||||
* the state to initial values. In measure mode, this command has no effect.
|
||||
*
|
||||
* @param state VOC algorithm state to restore.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_voc_algorithm_state(const uint8_t* state, uint8_t state_size);
|
||||
|
||||
/**
|
||||
* sen5x_get_voc_algorithm_state() - Gets the current VOC algorithm state. This
|
||||
* data can be used to restore the state with the \"Set VOC Algorithm State\"
|
||||
* command after a short power cycle or device reset.
|
||||
*
|
||||
* This command can be used either in measure mode or in idle mode
|
||||
* (which will then return the state at the time when the measurement
|
||||
* was stopped). In measure mode, the state can be read each measure
|
||||
* interval to always have the latest state available, even in case of
|
||||
* a sudden power loss.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param state Current VOC algorithm state.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_voc_algorithm_state(uint8_t* state, uint8_t state_size);
|
||||
|
||||
/**
|
||||
* sen5x_set_fan_auto_cleaning_interval() - Sets the fan auto cleaning interval
|
||||
* for the device.
|
||||
*
|
||||
* @param interval Fan auto cleaning interval [s]. Set to zero to disable auto
|
||||
* cleaning.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_set_fan_auto_cleaning_interval(uint32_t interval);
|
||||
|
||||
/**
|
||||
* sen5x_get_fan_auto_cleaning_interval() - Gets the fan auto cleaning interval
|
||||
* from the device.
|
||||
*
|
||||
* @param interval Fan auto cleaning interval [s]. Zero means auto cleaning is
|
||||
* disabled.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_fan_auto_cleaning_interval(uint32_t* interval);
|
||||
|
||||
/**
|
||||
* sen5x_get_product_name() - Gets the product name from the device.
|
||||
*
|
||||
* @param product_name Null-terminated ASCII string containing the product name.
|
||||
* Up to 32 characters can be read from the device.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_product_name(unsigned char* product_name,
|
||||
uint8_t product_name_size);
|
||||
|
||||
/**
|
||||
* sen5x_get_serial_number() - Gets the serial number from the device.
|
||||
*
|
||||
* @param serial_number Null-terminated ASCII string containing the serial
|
||||
* number. Up to 32 characters can be read from the device.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_serial_number(unsigned char* serial_number,
|
||||
uint8_t serial_number_size);
|
||||
|
||||
/**
|
||||
* sen5x_get_version() - Gets the version information for the hardware, firmware
|
||||
* and communication protocol.
|
||||
*
|
||||
* @param firmware_major Firmware major version number.
|
||||
*
|
||||
* @param firmware_minor Firmware minor version number.
|
||||
*
|
||||
* @param firmware_debug Firmware debug state. If the debug state is set, the
|
||||
* firmware is in development.
|
||||
*
|
||||
* @param hardware_major Hardware major version number.
|
||||
*
|
||||
* @param hardware_minor Hardware minor version number.
|
||||
*
|
||||
* @param protocol_major Protocol major version number.
|
||||
*
|
||||
* @param protocol_minor Protocol minor version number.
|
||||
*
|
||||
* @param padding Padding byte, ignore this.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_get_version(uint8_t* firmware_major, uint8_t* firmware_minor,
|
||||
bool* firmware_debug, uint8_t* hardware_major,
|
||||
uint8_t* hardware_minor, uint8_t* protocol_major,
|
||||
uint8_t* protocol_minor);
|
||||
|
||||
/**
|
||||
* sen5x_read_device_status() - Reads the current device status.
|
||||
|
||||
* Use this command to get detailed information about the device status.
|
||||
* The device status is encoded in flags. Each device status flag
|
||||
* represents a single bit in a 32-bit integer value. If more than one
|
||||
* error is present, the device status register value is the sum of the
|
||||
* corresponding flag values. For details about the available flags,
|
||||
* refer to the device status flags documentation.
|
||||
*
|
||||
* @note The status flags of type \"Error\" are sticky, i.e. they are not
|
||||
* cleared automatically even if the error condition no longer exists. So they
|
||||
* can only be cleared manually with the command 0xD210 \"Read And Clear Device
|
||||
* Status\" or with a device reset. All other flags are not sticky, i.e. they
|
||||
* are cleared automatically if the trigger condition disappears.
|
||||
*
|
||||
* @param device_status Device status (32 flags as an integer value). For
|
||||
* details, please refer to the device status flags documentation.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_device_status(uint32_t* device_status);
|
||||
|
||||
/**
|
||||
* sen5x_read_and_clear_device_status() - Reads the current device status (like
|
||||
* command 0xD206 \"Read Device Status\") and afterwards clears all flags.
|
||||
*
|
||||
* @param device_status Device status (32 flags as an integer value) **before**
|
||||
* clearing it. For details, please refer to the device status flags
|
||||
* documentation.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_read_and_clear_device_status(uint32_t* device_status);
|
||||
|
||||
/**
|
||||
* sen5x_device_reset() - Executes a reset on the device. This has the same
|
||||
* effect as a power cycle.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
int16_t sen5x_device_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEN5X_I2C_H */
|
||||
76
drivers/sen5x/include/sen5x_params.h
Normal file
76
drivers/sen5x/include/sen5x_params.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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_sen5x
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Default configuration
|
||||
*
|
||||
* @author Daniel Prigoshij <d.prigoshij@tu-braunschweig.de>
|
||||
*/
|
||||
|
||||
#ifndef SEN5X_PARAMS_H
|
||||
#define SEN5X_PARAMS_H
|
||||
|
||||
#include "board.h"
|
||||
#include "sen5x.h"
|
||||
#include "sen5x_constants.h"
|
||||
#include "periph/i2c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Set default configuration parameters for SEN5x sensors
|
||||
* @{
|
||||
*/
|
||||
#ifndef SEN5X_PARAM_I2C_DEV
|
||||
#define SEN5X_PARAM_I2C_DEV I2C_DEV(0)
|
||||
#endif
|
||||
#ifndef SEN5X_PARAM_ADDR
|
||||
#define SEN5X_PARAM_ADDR SEN5X_I2C_ADDRESS
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SEN5X_PARAMS
|
||||
#define SEN5X_PARAMS { .i2c_dev = SEN5X_PARAM_I2C_DEV, \
|
||||
.i2c_addr = SEN5X_PARAM_ADDR }
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @brief Configure SEN55/54
|
||||
*/
|
||||
static const sen5x_params_t sen5x_params[] =
|
||||
{
|
||||
SEN5X_PARAMS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Configure SAUL registry entries
|
||||
*/
|
||||
static const saul_reg_info_t sen5x_saul_info[] =
|
||||
{
|
||||
SEN5X_SAUL_INFO
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the number of configured SCD30 devices
|
||||
*/
|
||||
|
||||
#define SEN5X_NUM ARRAY_SIZE(sen5x_params)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEN5X_PARAMS_H */
|
||||
/** @} */
|
||||
181
drivers/sen5x/include/sensirion_common.h
Normal file
181
drivers/sen5x/include/sensirion_common.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SENSIRION_COMMON_H
|
||||
#define SENSIRION_COMMON_H
|
||||
|
||||
#include "sensirion_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NO_ERROR 0
|
||||
#define NOT_IMPLEMENTED_ERROR 31
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
#endif
|
||||
|
||||
#define SENSIRION_COMMAND_SIZE 2
|
||||
#define SENSIRION_WORD_SIZE 2
|
||||
#define SENSIRION_NUM_WORDS(x) (sizeof(x) / SENSIRION_WORD_SIZE)
|
||||
#define SENSIRION_MAX_BUFFER_WORDS 32
|
||||
|
||||
/**
|
||||
* sensirion_common_bytes_to_int16_t() - Convert an array of bytes to an int16_t
|
||||
*
|
||||
* Convert an array of bytes received from the sensor in big-endian/MSB-first
|
||||
* format to an int16_t value in the correct system-endianness.
|
||||
*
|
||||
* @param bytes An array of at least two bytes (MSB first)
|
||||
* @return The byte array represented as int16_t
|
||||
*/
|
||||
int16_t sensirion_common_bytes_to_int16_t(const uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_bytes_to_int32_t() - Convert an array of bytes to an int32_t
|
||||
*
|
||||
* Convert an array of bytes received from the sensor in big-endian/MSB-first
|
||||
* format to an int32_t value in the correct system-endianness.
|
||||
*
|
||||
* @param bytes An array of at least four bytes (MSB first)
|
||||
* @return The byte array represented as int32_t
|
||||
*/
|
||||
int32_t sensirion_common_bytes_to_int32_t(const uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_bytes_to_uint16_t() - Convert an array of bytes to an
|
||||
* uint16_t
|
||||
*
|
||||
* Convert an array of bytes received from the sensor in big-endian/MSB-first
|
||||
* format to an uint16_t value in the correct system-endianness.
|
||||
*
|
||||
* @param bytes An array of at least two bytes (MSB first)
|
||||
* @return The byte array represented as uint16_t
|
||||
*/
|
||||
uint16_t sensirion_common_bytes_to_uint16_t(const uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_bytes_to_uint32_t() - Convert an array of bytes to an
|
||||
* uint32_t
|
||||
*
|
||||
* Convert an array of bytes received from the sensor in big-endian/MSB-first
|
||||
* format to an uint32_t value in the correct system-endianness.
|
||||
*
|
||||
* @param bytes An array of at least four bytes (MSB first)
|
||||
* @return The byte array represented as uint32_t
|
||||
*/
|
||||
uint32_t sensirion_common_bytes_to_uint32_t(const uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_bytes_to_float() - Convert an array of bytes to a float
|
||||
*
|
||||
* Convert an array of bytes received from the sensor in big-endian/MSB-first
|
||||
* format to an float value in the correct system-endianness.
|
||||
*
|
||||
* @param bytes An array of at least four bytes (MSB first)
|
||||
* @return The byte array represented as float
|
||||
*/
|
||||
float sensirion_common_bytes_to_float(const uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_uint32_t_to_bytes() - Convert an uint32_t to an array of
|
||||
* bytes
|
||||
*
|
||||
* Convert an uint32_t value in system-endianness to big-endian/MBS-first
|
||||
* format to send to the sensor.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @param bytes An array of at least four bytes
|
||||
*/
|
||||
void sensirion_common_uint32_t_to_bytes(const uint32_t value, uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_uint16_t_to_bytes() - Convert an uint16_t to an array of
|
||||
* bytes
|
||||
*
|
||||
* Convert an uint16_t value in system-endianness to big-endian/MBS-first
|
||||
* format to send to the sensor.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @param bytes An array of at least two bytes
|
||||
*/
|
||||
void sensirion_common_uint16_t_to_bytes(const uint16_t value, uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_int32_t_to_bytes() - Convert an int32_t to an array of bytes
|
||||
*
|
||||
* Convert an int32_t value in system-endianness to big-endian/MBS-first
|
||||
* format to send to the sensor.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @param bytes An array of at least four bytes
|
||||
*/
|
||||
void sensirion_common_int32_t_to_bytes(const int32_t value, uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_int16_t_to_bytes() - Convert an int16_t to an array of bytes
|
||||
*
|
||||
* Convert an int16_t value in system-endianness to big-endian/MBS-first
|
||||
* format to send to the sensor.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @param bytes An array of at least two bytes
|
||||
*/
|
||||
void sensirion_common_int16_t_to_bytes(const int16_t value, uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_float_to_bytes() - Convert an float to an array of bytes
|
||||
*
|
||||
* Convert an float value in system-endianness to big-endian/MBS-first
|
||||
* format to send to the sensor.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @param bytes An array of at least four bytes
|
||||
*/
|
||||
void sensirion_common_float_to_bytes(const float value, uint8_t* bytes);
|
||||
|
||||
/**
|
||||
* sensirion_common_copy_bytes() - Copy bytes from one array to the other.
|
||||
*
|
||||
* @param source Array of bytes to be copied.
|
||||
* @param destination Array of bytes to be copied to.
|
||||
* @param data_length Number of bytes to copy.
|
||||
*/
|
||||
void sensirion_common_copy_bytes(const uint8_t* source, uint8_t* destination,
|
||||
uint16_t data_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SENSIRION_COMMON_H */
|
||||
88
drivers/sen5x/include/sensirion_config.h
Normal file
88
drivers/sen5x/include/sensirion_config.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SENSIRION_CONFIG_H
|
||||
#define SENSIRION_CONFIG_H
|
||||
|
||||
/**
|
||||
* If your platform does not provide the library stdlib.h you have to remove the
|
||||
* include and define NULL yourself (see below).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* #ifndef NULL
|
||||
* #define NULL ((void *)0)
|
||||
* #endif
|
||||
*/
|
||||
|
||||
/**
|
||||
* If your platform does not provide the library stdint.h you have to
|
||||
* define the integral types yourself (see below).
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Typedef section for types commonly defined in <stdint.h>
|
||||
* If your system does not provide stdint headers, please define them
|
||||
* accordingly. Please make sure to define int64_t and uint64_t.
|
||||
*/
|
||||
/* typedef unsigned long long int uint64_t;
|
||||
* typedef long long int int64_t;
|
||||
* typedef long int32_t;
|
||||
* typedef unsigned long uint32_t;
|
||||
* typedef short int16_t;
|
||||
* typedef unsigned short uint16_t;
|
||||
* typedef char int8_t;
|
||||
* typedef unsigned char uint8_t;
|
||||
*/
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
/**
|
||||
* If your platform doesn't define the bool type we define it as int. Depending
|
||||
* on your system update the definition below.
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
|
||||
#ifndef bool
|
||||
#define bool int
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif /* bool */
|
||||
|
||||
#endif /* __STDC_VERSION__ */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* SENSIRION_CONFIG_H */
|
||||
315
drivers/sen5x/include/sensirion_i2c.h
Normal file
315
drivers/sen5x/include/sensirion_i2c.h
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SENSIRION_I2C_H
|
||||
#define SENSIRION_I2C_H
|
||||
|
||||
#include "sensirion_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CRC_ERROR 1
|
||||
#define I2C_BUS_ERROR 2
|
||||
#define I2C_NACK_ERROR 3
|
||||
#define BYTE_NUM_ERROR 4
|
||||
|
||||
#define CRC8_POLYNOMIAL 0x31
|
||||
#define CRC8_INIT 0xFF
|
||||
#define CRC8_LEN 1
|
||||
|
||||
#define SENSIRION_COMMAND_SIZE 2
|
||||
#define SENSIRION_WORD_SIZE 2
|
||||
#define SENSIRION_NUM_WORDS(x) (sizeof(x) / SENSIRION_WORD_SIZE)
|
||||
#define SENSIRION_MAX_BUFFER_WORDS 32
|
||||
|
||||
uint8_t sensirion_i2c_generate_crc(const uint8_t* data, uint16_t count);
|
||||
|
||||
int8_t sensirion_i2c_check_crc(const uint8_t* data, uint16_t count,
|
||||
uint8_t checksum);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_general_call_reset() - Send a general call reset.
|
||||
*
|
||||
* @warning This will reset all attached I2C devices on the bus which support
|
||||
* general call reset.
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_general_call_reset(void);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_fill_cmd_send_buf() - create the i2c send buffer for a command
|
||||
* and a set of argument words. The output buffer interleaves argument words
|
||||
* with their checksums.
|
||||
* @buf: The generated buffer to send over i2c. Then buffer length must
|
||||
* be at least SENSIRION_COMMAND_LEN + num_args *
|
||||
* (SENSIRION_WORD_SIZE + CRC8_LEN).
|
||||
* @cmd: The i2c command to send. It already includes a checksum.
|
||||
* @args: The arguments to the command. Can be NULL if none.
|
||||
* @num_args: The number of word arguments in args.
|
||||
*
|
||||
* @return The number of bytes written to buf
|
||||
*/
|
||||
uint16_t sensirion_i2c_fill_cmd_send_buf(uint8_t* buf, uint16_t cmd,
|
||||
const uint16_t* args,
|
||||
uint8_t num_args);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_read_words() - read data words from sensor
|
||||
*
|
||||
* @address: Sensor i2c address
|
||||
* @data_words: Allocated buffer to store the read words.
|
||||
* The buffer may also have been modified in case of an error.
|
||||
* @num_words: Number of data words to read (without CRC bytes)
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_read_words(uint8_t address, uint16_t* data_words,
|
||||
uint16_t num_words);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_read_words_as_bytes() - read data words as byte-stream from
|
||||
* sensor
|
||||
*
|
||||
* Read bytes without adjusting values to the uP's word-order.
|
||||
*
|
||||
* @address: Sensor i2c address
|
||||
* @data: Allocated buffer to store the read bytes.
|
||||
* The buffer may also have been modified in case of an error.
|
||||
* @num_words: Number of data words(!) to read (without CRC bytes)
|
||||
* Since only word-chunks can be read from the sensor the size
|
||||
* is still specified in sensor-words (num_words = num_bytes *
|
||||
* SENSIRION_WORD_SIZE)
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_read_words_as_bytes(uint8_t address, uint8_t* data,
|
||||
uint16_t num_words);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_write_cmd() - writes a command to the sensor
|
||||
* @address: Sensor i2c address
|
||||
* @command: Sensor command
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_write_cmd(uint8_t address, uint16_t command);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_write_cmd_with_args() - writes a command with arguments to the
|
||||
* sensor
|
||||
* @address: Sensor i2c address
|
||||
* @command: Sensor command
|
||||
* @data: Argument buffer with words to send
|
||||
* @num_words: Number of data words to send (without CRC bytes)
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_write_cmd_with_args(uint8_t address, uint16_t command,
|
||||
const uint16_t* data_words,
|
||||
uint16_t num_words);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_delayed_read_cmd() - send a command, wait for the sensor to
|
||||
* process and read data back
|
||||
* @address: Sensor i2c address
|
||||
* @cmd: Command
|
||||
* @delay: Time in microseconds to delay sending the read request
|
||||
* @data_words: Allocated buffer to store the read data
|
||||
* @num_words: Data words to read (without CRC bytes)
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_delayed_read_cmd(uint8_t address, uint16_t cmd,
|
||||
uint32_t delay_us, uint16_t* data_words,
|
||||
uint16_t num_words);
|
||||
/**
|
||||
* sensirion_i2c_read_cmd() - reads data words from the sensor after a command
|
||||
* is issued
|
||||
* @address: Sensor i2c address
|
||||
* @cmd: Command
|
||||
* @data_words: Allocated buffer to store the read data
|
||||
* @num_words: Data words to read (without CRC bytes)
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_read_cmd(uint8_t address, uint16_t cmd,
|
||||
uint16_t* data_words, uint16_t num_words);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_command_to_buffer() - Add a command to the buffer at
|
||||
* offset. Adds 2 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param command Command to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_command_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint16_t command);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_uint32_t_to_buffer() - Add a uint32_t to the buffer at
|
||||
* offset. Adds 6 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data uint32_t to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_uint32_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint32_t data);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_int32_t_to_buffer() - Add a int32_t to the buffer at
|
||||
* offset. Adds 6 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data int32_t to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_int32_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
int32_t data);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_uint16_t_to_buffer() - Add a uint16_t to the buffer at
|
||||
* offset. Adds 3 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data uint16_t to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_uint16_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint16_t data);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_int16_t_to_buffer() - Add a int16_t to the buffer at
|
||||
* offset. Adds 3 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data int16_t to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_int16_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
int16_t data);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_float_to_buffer() - Add a float to the buffer at offset.
|
||||
* Adds 6 bytes to the buffer.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be prepared.
|
||||
* Caller needs to make sure that there is enough space after
|
||||
* offset left to write the data into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data float to be written into the buffer.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_float_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
float data);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_add_bytes_to_buffer() - Add a byte array to the buffer at
|
||||
* offset.
|
||||
*
|
||||
* @param buffer Pointer to buffer in which the write frame will be
|
||||
* prepared. Caller needs to make sure that there is
|
||||
* enough space after offset left to write the data
|
||||
* into the buffer.
|
||||
* @param offset Offset of the next free byte in the buffer.
|
||||
* @param data Pointer to data to be written into the buffer.
|
||||
* @param data_length Number of bytes to be written into the buffer. Needs to
|
||||
* be a multiple of SENSIRION_WORD_SIZE otherwise the
|
||||
* function returns BYTE_NUM_ERROR.
|
||||
*
|
||||
* @return Offset of next free byte in the buffer after writing the
|
||||
* data.
|
||||
*/
|
||||
uint16_t sensirion_i2c_add_bytes_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
const uint8_t* data,
|
||||
uint16_t data_length);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_write_data() - Writes data to the Sensor.
|
||||
*
|
||||
* @note This is just a wrapper for sensirion_i2c_hal_write() to
|
||||
* not need to include the HAL in the drivers.
|
||||
*
|
||||
* @param address I2C address to write to.
|
||||
* @param data Pointer to the buffer containing the data to write.
|
||||
* @param data_length Number of bytes to send to the Sensor.
|
||||
*
|
||||
* @return NO_ERROR on success, error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_write_data(uint8_t address, const uint8_t* data,
|
||||
uint16_t data_length);
|
||||
|
||||
/**
|
||||
* sensirion_i2c_read_data_inplace() - Reads data from the Sensor.
|
||||
*
|
||||
* @param address Sensor I2C address
|
||||
* @param buffer Allocated buffer to store data as bytes. Needs
|
||||
* to be big enough to store the data including
|
||||
* CRC. Twice the size of data should always
|
||||
* suffice.
|
||||
* @param expected_data_length Number of bytes to read (without CRC). Needs
|
||||
* to be a multiple of SENSIRION_WORD_SIZE,
|
||||
* otherwise the function returns BYTE_NUM_ERROR.
|
||||
*
|
||||
* @return NO_ERROR on success, an error code otherwise
|
||||
*/
|
||||
int16_t sensirion_i2c_read_data_inplace(uint8_t address, uint8_t* buffer,
|
||||
uint16_t expected_data_length);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SENSIRION_I2C_H */
|
||||
103
drivers/sen5x/include/sensirion_i2c_hal.h
Normal file
103
drivers/sen5x/include/sensirion_i2c_hal.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SENSIRION_I2C_HAL_H
|
||||
#define SENSIRION_I2C_HAL_H
|
||||
|
||||
#include "sensirion_config.h"
|
||||
#include "sen5x_params.h"
|
||||
#include "xtimer.h"
|
||||
#include "periph/i2c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Initialize all hard- and software components that are needed for the I2C
|
||||
* communication.
|
||||
*/
|
||||
void sensirion_i2c_hal_init(void);
|
||||
|
||||
/**
|
||||
* Release all resources initialized by sensirion_i2c_hal_init().
|
||||
*/
|
||||
void sensirion_i2c_hal_free(void);
|
||||
|
||||
/**
|
||||
* Execute one read transaction on the I2C bus, reading a given number of bytes.
|
||||
* If the device does not acknowledge the read command, an error shall be
|
||||
* returned.
|
||||
*
|
||||
* @param address 7-bit I2C address to read from
|
||||
* @param data pointer to the buffer where the data is to be stored
|
||||
* @param count number of bytes to read from I2C and store in the buffer
|
||||
* @returns 0 on success, error code otherwise
|
||||
*/
|
||||
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count);
|
||||
|
||||
/**
|
||||
* Execute one write transaction on the I2C bus, sending a given number of
|
||||
* bytes. The bytes in the supplied buffer must be sent to the given address. If
|
||||
* the slave device does not acknowledge any of the bytes, an error shall be
|
||||
* returned.
|
||||
*
|
||||
* @param address 7-bit I2C address to write to
|
||||
* @param data pointer to the buffer containing the data to write
|
||||
* @param count number of bytes to read from the buffer and send over I2C
|
||||
* @returns 0 on success, error code otherwise
|
||||
*/
|
||||
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
|
||||
uint16_t count);
|
||||
|
||||
/**
|
||||
* Sleep for a given number of microseconds. The function should delay the
|
||||
* execution approximately, but no less than, the given time.
|
||||
*
|
||||
* When using hardware i2c:
|
||||
* Despite the unit, a <10 millisecond precision is sufficient.
|
||||
*
|
||||
* When using software i2c:
|
||||
* The precision needed depends on the desired i2c frequency, i.e. should be
|
||||
* exact to about half a clock cycle (defined in
|
||||
* `SENSIRION_I2C_CLOCK_PERIOD_USEC` in `sensirion_sw_i2c_gpio.h`).
|
||||
*
|
||||
* Example with 400kHz requires a precision of 1 / (2 * 400kHz) == 1.25usec.
|
||||
*
|
||||
* @param useconds the sleep time in microseconds
|
||||
*/
|
||||
void sensirion_i2c_hal_sleep_usec(uint32_t useconds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* SENSIRION_I2C_HAL_H */
|
||||
263
drivers/sen5x/sen5x.c
Normal file
263
drivers/sen5x/sen5x.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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_sen5x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Device driver implementation for the Sensirion Embedded I2C SEN5x Driver
|
||||
*
|
||||
* @author Daniel Prigoshij <d.prigoshij@tu-braunschweig.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "sen5x.h"
|
||||
#include "sen5x_constants.h"
|
||||
#include "sen5x_params.h"
|
||||
#include "sensirion_i2c_hal.h"
|
||||
#include "sen5x_i2c.h"
|
||||
|
||||
void sen5x_init(sen5x_t *dev, const sen5x_params_t *params)
|
||||
{
|
||||
/* check parameters */
|
||||
assert(dev && params);
|
||||
|
||||
dev->params = *params;
|
||||
|
||||
i2c_init(dev->params.i2c_dev);
|
||||
sen5x_reset(dev);
|
||||
}
|
||||
|
||||
void sen5x_reset(const sen5x_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_device_reset();
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_wake(const sen5x_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_start_measurement();
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_sleep(const sen5x_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_stop_measurement();
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_clean_fan(const sen5x_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_start_fan_cleaning();
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
bool sen5x_data_ready_flag(const sen5x_t *dev)
|
||||
{
|
||||
assert(dev && status);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
bool* status;
|
||||
sen5x_read_data_ready(&status);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
void sen5x_read_values(sen5x_t *dev ,sen5x_measurement_t *values)
|
||||
{
|
||||
assert(dev && values);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_read_measured_values(
|
||||
&values->mass_concentration_pm1p0, &values->mass_concentration_pm2p5,
|
||||
&values->mass_concentration_pm4p0, &values->mass_concentration_pm10p0,
|
||||
&values->ambient_humidity, &values->ambient_temperature, &values->voc_index,
|
||||
&values->nox_index);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_read_pm_values(const sen5x_t *dev, sen5x_measurement_t *values)
|
||||
{
|
||||
assert(dev && values);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_read_measured_pm_values(
|
||||
&values->mass_concentration_pm1p0, &values->mass_concentration_pm2p5,
|
||||
&values->mass_concentration_pm4p0, &values->mass_concentration_pm10p0,
|
||||
&values->number_concentration_pm0p5, &values->number_concentration_pm1p0,
|
||||
&values->number_concentration_pm2p5, &values->number_concentration_pm4p0,
|
||||
&values->number_concentration_pm10p0, &values->typical_particle_size);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_temperature_offset(const sen5x_t *dev, int16_t temp_offset, int16_t slope, uint16_t time_constant)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_temperature_offset_parameters(temp_offset, slope, time_constant);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_temperature_offset(const sen5x_t *dev, int16_t *temp_offset, int16_t *slope, uint16_t *time_constant)
|
||||
{
|
||||
assert(dev && temp_offset && slope && time_constant);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_temperature_offset_parameters(temp_offset, slope, time_constant);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_warm_start(const sen5x_t *dev, uint16_t warm_start)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_warm_start_parameter(warm_start);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_warm_start(const sen5x_t *dev, uint16_t *warm_start)
|
||||
{
|
||||
assert(dev && warm_start);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_warm_start_parameter(warm_start);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_voc_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_voc_algorithm_tuning_parameters(
|
||||
index_offset, learning_time_offset_hours,
|
||||
learning_time_gain_hours, gating_max_duration_minutes,
|
||||
std_initial, gain_factor);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_voc_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t *index_offset, int16_t *learning_time_offset_hours,
|
||||
int16_t *learning_time_gain_hours, int16_t *gating_max_duration_minutes,
|
||||
int16_t *std_initial, int16_t *gain_factor)
|
||||
{
|
||||
assert(dev && index_offset && learning_time_offset_hours && learning_time_gain_hours
|
||||
&& gating_max_duration_minutes && std_initial && gain_factor);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_voc_algorithm_tuning_parameters(
|
||||
index_offset, learning_time_offset_hours,
|
||||
learning_time_gain_hours, gating_max_duration_minutes,
|
||||
std_initial, gain_factor);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_nox_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_nox_algorithm_tuning_parameters(
|
||||
index_offset, learning_time_offset_hours,
|
||||
learning_time_gain_hours, gating_max_duration_minutes,
|
||||
std_initial, gain_factor);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_nox_algorithm_tuning(
|
||||
const sen5x_t *dev, int16_t *index_offset, int16_t *learning_time_offset_hours,
|
||||
int16_t *learning_time_gain_hours, int16_t *gating_max_duration_minutes,
|
||||
int16_t *std_initial, int16_t *gain_factor)
|
||||
{
|
||||
assert(dev && index_offset && learning_time_offset_hours && learning_time_gain_hours
|
||||
&& gating_max_duration_minutes && std_initial && gain_factor);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_nox_algorithm_tuning_parameters(
|
||||
index_offset, learning_time_offset_hours,
|
||||
learning_time_gain_hours, gating_max_duration_minutes,
|
||||
std_initial, gain_factor);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_rht_acceleration(const sen5x_t *dev, uint16_t mode)
|
||||
{
|
||||
assert(dev);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_rht_acceleration_mode(mode);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_rht_acceleration(const sen5x_t *dev, uint16_t *mode)
|
||||
{
|
||||
assert(dev && mode);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_rht_acceleration_mode(mode);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_set_voc_state(const sen5x_t *dev, const uint8_t *state, uint8_t state_size)
|
||||
{
|
||||
assert(dev && state);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_set_voc_algorithm_state(state, state_size);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
|
||||
void sen5x_get_voc_state(const sen5x_t *dev, uint8_t *state, uint8_t state_size)
|
||||
{
|
||||
assert(dev && state);
|
||||
i2c_acquire(dev->params.i2c_dev);
|
||||
|
||||
sen5x_get_voc_algorithm_state(state, state_size);
|
||||
|
||||
i2c_release(dev->params.i2c_dev);
|
||||
}
|
||||
690
drivers/sen5x/sen5x_i2c.c
Normal file
690
drivers/sen5x/sen5x_i2c.c
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED
|
||||
*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-109-gb259776
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "sen5x_i2c.h"
|
||||
#include "sensirion_common.h"
|
||||
#include "sensirion_i2c.h"
|
||||
#include "sensirion_i2c_hal.h"
|
||||
|
||||
#define SEN5X_I2C_ADDRESS 0x69
|
||||
|
||||
int16_t sen5x_start_measurement(void) {
|
||||
int16_t error;
|
||||
uint8_t buffer[2];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x21);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(50000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_start_measurement_without_pm(void) {
|
||||
int16_t error;
|
||||
uint8_t buffer[2];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x37);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(50000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_stop_measurement(void) {
|
||||
int16_t error;
|
||||
uint8_t buffer[2];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x104);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(200000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_data_ready(bool* data_ready) {
|
||||
int16_t error;
|
||||
uint8_t buffer[3];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x202);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 2);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*data_ready = buffer[1];
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_measured_values(uint16_t* mass_concentration_pm1p0,
|
||||
uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0,
|
||||
uint16_t* mass_concentration_pm10p0,
|
||||
int16_t* ambient_humidity,
|
||||
int16_t* ambient_temperature,
|
||||
int16_t* voc_index, int16_t* nox_index) {
|
||||
int16_t error;
|
||||
uint8_t buffer[24];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3C4);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 16);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*mass_concentration_pm1p0 = sensirion_common_bytes_to_uint16_t(&buffer[0]);
|
||||
*mass_concentration_pm2p5 = sensirion_common_bytes_to_uint16_t(&buffer[2]);
|
||||
*mass_concentration_pm4p0 = sensirion_common_bytes_to_uint16_t(&buffer[4]);
|
||||
*mass_concentration_pm10p0 = sensirion_common_bytes_to_uint16_t(&buffer[6]);
|
||||
*ambient_humidity = sensirion_common_bytes_to_int16_t(&buffer[8]);
|
||||
*ambient_temperature = sensirion_common_bytes_to_int16_t(&buffer[10]);
|
||||
*voc_index = sensirion_common_bytes_to_int16_t(&buffer[12]);
|
||||
*nox_index = sensirion_common_bytes_to_int16_t(&buffer[14]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_measured_raw_values(int16_t* raw_humidity,
|
||||
int16_t* raw_temperature,
|
||||
uint16_t* raw_voc, uint16_t* raw_nox) {
|
||||
int16_t error;
|
||||
uint8_t buffer[12];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3D2);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 8);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*raw_humidity = sensirion_common_bytes_to_int16_t(&buffer[0]);
|
||||
*raw_temperature = sensirion_common_bytes_to_int16_t(&buffer[2]);
|
||||
*raw_voc = sensirion_common_bytes_to_uint16_t(&buffer[4]);
|
||||
*raw_nox = sensirion_common_bytes_to_uint16_t(&buffer[6]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_measured_values_sen50(uint16_t* mass_concentration_pm1p0,
|
||||
uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0,
|
||||
uint16_t* mass_concentration_pm10p0) {
|
||||
int16_t error;
|
||||
|
||||
int16_t ambient_humidity_dummy;
|
||||
int16_t ambient_temperature_dummy;
|
||||
int16_t voc_index_dummy;
|
||||
int16_t nox_index_dummy;
|
||||
|
||||
error = sen5x_read_measured_values(
|
||||
mass_concentration_pm1p0, mass_concentration_pm2p5,
|
||||
mass_concentration_pm4p0, mass_concentration_pm10p0,
|
||||
&ambient_humidity_dummy, &ambient_temperature_dummy, &voc_index_dummy,
|
||||
&nox_index_dummy);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_measured_pm_values(
|
||||
uint16_t* mass_concentration_pm1p0, uint16_t* mass_concentration_pm2p5,
|
||||
uint16_t* mass_concentration_pm4p0, uint16_t* mass_concentration_pm10p0,
|
||||
uint16_t* number_concentration_pm0p5, uint16_t* number_concentration_pm1p0,
|
||||
uint16_t* number_concentration_pm2p5, uint16_t* number_concentration_pm4p0,
|
||||
uint16_t* number_concentration_pm10p0, uint16_t* typical_particle_size) {
|
||||
int16_t error;
|
||||
uint8_t buffer[30];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x413);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 20);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*mass_concentration_pm1p0 = sensirion_common_bytes_to_uint16_t(&buffer[0]);
|
||||
*mass_concentration_pm2p5 = sensirion_common_bytes_to_uint16_t(&buffer[2]);
|
||||
*mass_concentration_pm4p0 = sensirion_common_bytes_to_uint16_t(&buffer[4]);
|
||||
*mass_concentration_pm10p0 = sensirion_common_bytes_to_uint16_t(&buffer[6]);
|
||||
*number_concentration_pm0p5 =
|
||||
sensirion_common_bytes_to_uint16_t(&buffer[8]);
|
||||
*number_concentration_pm1p0 =
|
||||
sensirion_common_bytes_to_uint16_t(&buffer[10]);
|
||||
*number_concentration_pm2p5 =
|
||||
sensirion_common_bytes_to_uint16_t(&buffer[12]);
|
||||
*number_concentration_pm4p0 =
|
||||
sensirion_common_bytes_to_uint16_t(&buffer[14]);
|
||||
*number_concentration_pm10p0 =
|
||||
sensirion_common_bytes_to_uint16_t(&buffer[16]);
|
||||
*typical_particle_size = sensirion_common_bytes_to_uint16_t(&buffer[18]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_start_fan_cleaning(void) {
|
||||
int16_t error;
|
||||
uint8_t buffer[2];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x5607);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_temperature_offset_parameters(int16_t temp_offset,
|
||||
int16_t slope,
|
||||
uint16_t time_constant) {
|
||||
int16_t error;
|
||||
uint8_t buffer[11];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60B2);
|
||||
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, temp_offset);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, slope);
|
||||
offset =
|
||||
sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset, time_constant);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_temperature_offset_parameters(int16_t* temp_offset,
|
||||
int16_t* slope,
|
||||
uint16_t* time_constant) {
|
||||
int16_t error;
|
||||
uint8_t buffer[9];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60B2);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 6);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*temp_offset = sensirion_common_bytes_to_int16_t(&buffer[0]);
|
||||
*slope = sensirion_common_bytes_to_int16_t(&buffer[2]);
|
||||
*time_constant = sensirion_common_bytes_to_uint16_t(&buffer[4]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_warm_start_parameter(uint16_t warm_start) {
|
||||
int16_t error;
|
||||
uint8_t buffer[5];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60C6);
|
||||
|
||||
offset =
|
||||
sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset, warm_start);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_warm_start_parameter(uint16_t* warm_start) {
|
||||
int16_t error;
|
||||
uint8_t buffer[3];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60C6);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 2);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*warm_start = sensirion_common_bytes_to_uint16_t(&buffer[0]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_voc_algorithm_tuning_parameters(
|
||||
int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor) {
|
||||
int16_t error;
|
||||
uint8_t buffer[20];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60D0);
|
||||
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, index_offset);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
learning_time_offset_hours);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
learning_time_gain_hours);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
gating_max_duration_minutes);
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, std_initial);
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, gain_factor);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_voc_algorithm_tuning_parameters(
|
||||
int16_t* index_offset, int16_t* learning_time_offset_hours,
|
||||
int16_t* learning_time_gain_hours, int16_t* gating_max_duration_minutes,
|
||||
int16_t* std_initial, int16_t* gain_factor) {
|
||||
int16_t error;
|
||||
uint8_t buffer[18];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60D0);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 12);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*index_offset = sensirion_common_bytes_to_int16_t(&buffer[0]);
|
||||
*learning_time_offset_hours = sensirion_common_bytes_to_int16_t(&buffer[2]);
|
||||
*learning_time_gain_hours = sensirion_common_bytes_to_int16_t(&buffer[4]);
|
||||
*gating_max_duration_minutes =
|
||||
sensirion_common_bytes_to_int16_t(&buffer[6]);
|
||||
*std_initial = sensirion_common_bytes_to_int16_t(&buffer[8]);
|
||||
*gain_factor = sensirion_common_bytes_to_int16_t(&buffer[10]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_nox_algorithm_tuning_parameters(
|
||||
int16_t index_offset, int16_t learning_time_offset_hours,
|
||||
int16_t learning_time_gain_hours, int16_t gating_max_duration_minutes,
|
||||
int16_t std_initial, int16_t gain_factor) {
|
||||
int16_t error;
|
||||
uint8_t buffer[20];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60E1);
|
||||
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, index_offset);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
learning_time_offset_hours);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
learning_time_gain_hours);
|
||||
offset = sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset,
|
||||
gating_max_duration_minutes);
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, std_initial);
|
||||
offset =
|
||||
sensirion_i2c_add_int16_t_to_buffer(&buffer[0], offset, gain_factor);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_nox_algorithm_tuning_parameters(
|
||||
int16_t* index_offset, int16_t* learning_time_offset_hours,
|
||||
int16_t* learning_time_gain_hours, int16_t* gating_max_duration_minutes,
|
||||
int16_t* std_initial, int16_t* gain_factor) {
|
||||
int16_t error;
|
||||
uint8_t buffer[18];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60E1);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 12);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*index_offset = sensirion_common_bytes_to_int16_t(&buffer[0]);
|
||||
*learning_time_offset_hours = sensirion_common_bytes_to_int16_t(&buffer[2]);
|
||||
*learning_time_gain_hours = sensirion_common_bytes_to_int16_t(&buffer[4]);
|
||||
*gating_max_duration_minutes =
|
||||
sensirion_common_bytes_to_int16_t(&buffer[6]);
|
||||
*std_initial = sensirion_common_bytes_to_int16_t(&buffer[8]);
|
||||
*gain_factor = sensirion_common_bytes_to_int16_t(&buffer[10]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_rht_acceleration_mode(uint16_t mode) {
|
||||
int16_t error;
|
||||
uint8_t buffer[5];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60F7);
|
||||
|
||||
offset = sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset, mode);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_rht_acceleration_mode(uint16_t* mode) {
|
||||
int16_t error;
|
||||
uint8_t buffer[3];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x60F7);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 2);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*mode = sensirion_common_bytes_to_uint16_t(&buffer[0]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_voc_algorithm_state(const uint8_t* state,
|
||||
uint8_t state_size) {
|
||||
int16_t error;
|
||||
uint8_t buffer[14];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x6181);
|
||||
|
||||
offset = sensirion_i2c_add_bytes_to_buffer(&buffer[0], offset, state,
|
||||
state_size);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_voc_algorithm_state(uint8_t* state, uint8_t state_size) {
|
||||
int16_t error;
|
||||
uint8_t buffer[12];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x6181);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 8);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_common_copy_bytes(&buffer[0], state, state_size);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_set_fan_auto_cleaning_interval(uint32_t interval) {
|
||||
int16_t error;
|
||||
uint8_t buffer[8];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x8004);
|
||||
|
||||
offset = sensirion_i2c_add_uint32_t_to_buffer(&buffer[0], offset, interval);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_fan_auto_cleaning_interval(uint32_t* interval) {
|
||||
int16_t error;
|
||||
uint8_t buffer[6];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x8004);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 4);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*interval = sensirion_common_bytes_to_uint32_t(&buffer[0]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_product_name(unsigned char* product_name,
|
||||
uint8_t product_name_size) {
|
||||
int16_t error;
|
||||
uint8_t buffer[48];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD014);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(50000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 32);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_common_copy_bytes(&buffer[0], product_name, product_name_size);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_serial_number(unsigned char* serial_number,
|
||||
uint8_t serial_number_size) {
|
||||
int16_t error;
|
||||
uint8_t buffer[48];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD033);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(50000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 32);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_common_copy_bytes(&buffer[0], serial_number, serial_number_size);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_get_version(uint8_t* firmware_major, uint8_t* firmware_minor,
|
||||
bool* firmware_debug, uint8_t* hardware_major,
|
||||
uint8_t* hardware_minor, uint8_t* protocol_major,
|
||||
uint8_t* protocol_minor) {
|
||||
int16_t error;
|
||||
uint8_t buffer[12];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD100);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 8);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*firmware_major = buffer[0];
|
||||
*firmware_minor = buffer[1];
|
||||
*firmware_debug = buffer[2];
|
||||
*hardware_major = buffer[3];
|
||||
*hardware_minor = buffer[4];
|
||||
*protocol_major = buffer[5];
|
||||
*protocol_minor = buffer[6];
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_device_status(uint32_t* device_status) {
|
||||
int16_t error;
|
||||
uint8_t buffer[6];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD206);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 4);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*device_status = sensirion_common_bytes_to_uint32_t(&buffer[0]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_read_and_clear_device_status(uint32_t* device_status) {
|
||||
int16_t error;
|
||||
uint8_t buffer[6];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD210);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sensirion_i2c_hal_sleep_usec(20000);
|
||||
|
||||
error = sensirion_i2c_read_data_inplace(SEN5X_I2C_ADDRESS, &buffer[0], 4);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
*device_status = sensirion_common_bytes_to_uint32_t(&buffer[0]);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sen5x_device_reset(void) {
|
||||
int16_t error;
|
||||
uint8_t buffer[2];
|
||||
uint16_t offset = 0;
|
||||
offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xD304);
|
||||
|
||||
error = sensirion_i2c_write_data(SEN5X_I2C_ADDRESS, &buffer[0], offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
sensirion_i2c_hal_sleep_usec(200000);
|
||||
return NO_ERROR;
|
||||
}
|
||||
237
drivers/sen5x/sen5x_saul.c
Normal file
237
drivers/sen5x/sen5x_saul.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2023 TU Braunschweig Institut für Betriebssysteme und Rechnerverbund
|
||||
*
|
||||
* 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_sen5x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief SAUL adaptation for SEN50/54/55 devices.
|
||||
*
|
||||
* @author Daniel Prigoshij <prigoshi@ibr.cs.tu-bs.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "saul.h"
|
||||
#include "sen5x.h"
|
||||
#include "sen5x_params.h"
|
||||
|
||||
static int read_mass_concentration_pm1p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.mass_concentration_pm1p0;
|
||||
res->unit = UNIT_GPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_mass_concentration_pm2p5(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.mass_concentration_pm2p5;
|
||||
res->unit = UNIT_GPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_mass_concentration_pm4p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.mass_concentration_pm4p0;
|
||||
res->unit = UNIT_GPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_mass_concentration_pm10p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.mass_concentration_pm10p0;
|
||||
res->unit = UNIT_GPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_number_concentration_pm0p5(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.number_concentration_pm0p5;
|
||||
res->unit = UNIT_CPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_number_concentration_pm1p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.number_concentration_pm1p0;
|
||||
res->unit = UNIT_CPM3;
|
||||
res->scale = -5;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_number_concentration_pm2p5(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.number_concentration_pm2p5;
|
||||
res->unit = UNIT_CPM3;
|
||||
res->scale = -5;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_number_concentration_pm4p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.number_concentration_pm4p0;
|
||||
res->unit = UNIT_CPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_number_concentration_pm10p0(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.number_concentration_pm10p0;
|
||||
res->unit = UNIT_CPM3;
|
||||
res->scale = -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_typical_particle_size(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.typical_particle_size;
|
||||
res->unit = UNIT_M;
|
||||
res->scale = -3;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_ambient_humidity(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = (int16_t)d->values.ambient_humidity;
|
||||
res->unit = UNIT_PERCENT;
|
||||
res->scale = 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_ambient_temperature(const void *dev, phydat_t *res) {
|
||||
sen5x_t *d = (sen5x_t *)dev;
|
||||
|
||||
sen5x_read_pm_values(d, &d->values);
|
||||
|
||||
res->val[0] = ((int16_t)d->values.ambient_temperature) / 2;
|
||||
res->unit = UNIT_TEMP_C;
|
||||
res->scale = 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
const saul_driver_t sen5x_mass_concentration_pm1p0_driver = {
|
||||
.read = read_mass_concentration_pm1p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_PM
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_mass_concentration_pm2p5_driver = {
|
||||
.read = read_mass_concentration_pm2p5,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_PM
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_mass_concentration_pm4p0_driver = {
|
||||
.read = read_mass_concentration_pm4p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_PM
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_mass_concentration_pm10p0_driver = {
|
||||
.read = read_mass_concentration_pm10p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_PM
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_number_concentration_pm0p5_driver = {
|
||||
.read = read_number_concentration_pm0p5,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_COUNT
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_number_concentration_pm1p0_driver = {
|
||||
.read = read_number_concentration_pm1p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_COUNT
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_number_concentration_pm2p5_driver = {
|
||||
.read = read_number_concentration_pm2p5,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_COUNT
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_number_concentration_pm4p0_driver = {
|
||||
.read = read_number_concentration_pm4p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_COUNT
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_number_concentration_pm10p0_driver = {
|
||||
.read = read_number_concentration_pm10p0,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_COUNT
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_typical_particle_size_driver = {
|
||||
.read = read_typical_particle_size,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_SIZE
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_ambient_humidity_driver = {
|
||||
.read = read_ambient_humidity,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_HUM
|
||||
};
|
||||
|
||||
const saul_driver_t sen5x_ambient_temperature_driver = {
|
||||
.read = read_ambient_temperature,
|
||||
.write = saul_write_notsup,
|
||||
.type = SAUL_SENSE_TEMP
|
||||
};
|
||||
101
drivers/sen5x/sensirion_common.c
Normal file
101
drivers/sen5x/sensirion_common.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "sensirion_common.h"
|
||||
#include "sensirion_config.h"
|
||||
|
||||
uint16_t sensirion_common_bytes_to_uint16_t(const uint8_t* bytes) {
|
||||
return (uint16_t)bytes[0] << 8 | (uint16_t)bytes[1];
|
||||
}
|
||||
|
||||
uint32_t sensirion_common_bytes_to_uint32_t(const uint8_t* bytes) {
|
||||
return (uint32_t)bytes[0] << 24 | (uint32_t)bytes[1] << 16 |
|
||||
(uint32_t)bytes[2] << 8 | (uint32_t)bytes[3];
|
||||
}
|
||||
|
||||
int16_t sensirion_common_bytes_to_int16_t(const uint8_t* bytes) {
|
||||
return (int16_t)sensirion_common_bytes_to_uint16_t(bytes);
|
||||
}
|
||||
|
||||
int32_t sensirion_common_bytes_to_int32_t(const uint8_t* bytes) {
|
||||
return (int32_t)sensirion_common_bytes_to_uint32_t(bytes);
|
||||
}
|
||||
|
||||
float sensirion_common_bytes_to_float(const uint8_t* bytes) {
|
||||
union {
|
||||
uint32_t u32_value;
|
||||
float float32;
|
||||
} tmp;
|
||||
|
||||
tmp.u32_value = sensirion_common_bytes_to_uint32_t(bytes);
|
||||
return tmp.float32;
|
||||
}
|
||||
|
||||
void sensirion_common_uint32_t_to_bytes(const uint32_t value, uint8_t* bytes) {
|
||||
bytes[0] = value >> 24;
|
||||
bytes[1] = value >> 16;
|
||||
bytes[2] = value >> 8;
|
||||
bytes[3] = value;
|
||||
}
|
||||
|
||||
void sensirion_common_uint16_t_to_bytes(const uint16_t value, uint8_t* bytes) {
|
||||
bytes[0] = value >> 8;
|
||||
bytes[1] = value;
|
||||
}
|
||||
|
||||
void sensirion_common_int32_t_to_bytes(const int32_t value, uint8_t* bytes) {
|
||||
bytes[0] = value >> 24;
|
||||
bytes[1] = value >> 16;
|
||||
bytes[2] = value >> 8;
|
||||
bytes[3] = value;
|
||||
}
|
||||
|
||||
void sensirion_common_int16_t_to_bytes(const int16_t value, uint8_t* bytes) {
|
||||
bytes[0] = value >> 8;
|
||||
bytes[1] = value;
|
||||
}
|
||||
|
||||
void sensirion_common_float_to_bytes(const float value, uint8_t* bytes) {
|
||||
union {
|
||||
uint32_t u32_value;
|
||||
float float32;
|
||||
} tmp;
|
||||
tmp.float32 = value;
|
||||
sensirion_common_uint32_t_to_bytes(tmp.u32_value, bytes);
|
||||
}
|
||||
|
||||
void sensirion_common_copy_bytes(const uint8_t* source, uint8_t* destination,
|
||||
uint16_t data_length) {
|
||||
uint16_t i;
|
||||
for (i = 0; i < data_length; i++) {
|
||||
destination[i] = source[i];
|
||||
}
|
||||
}
|
||||
294
drivers/sen5x/sensirion_i2c.c
Normal file
294
drivers/sen5x/sensirion_i2c.c
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "sensirion_i2c.h"
|
||||
#include "sensirion_common.h"
|
||||
#include "sensirion_config.h"
|
||||
#include "sensirion_i2c_hal.h"
|
||||
|
||||
uint8_t sensirion_i2c_generate_crc(const uint8_t* data, uint16_t count) {
|
||||
uint16_t current_byte;
|
||||
uint8_t crc = CRC8_INIT;
|
||||
uint8_t crc_bit;
|
||||
|
||||
/* calculates 8-Bit checksum with given polynomial */
|
||||
for (current_byte = 0; current_byte < count; ++current_byte) {
|
||||
crc ^= (data[current_byte]);
|
||||
for (crc_bit = 8; crc_bit > 0; --crc_bit) {
|
||||
if (crc & 0x80)
|
||||
crc = (crc << 1) ^ CRC8_POLYNOMIAL;
|
||||
else
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int8_t sensirion_i2c_check_crc(const uint8_t* data, uint16_t count,
|
||||
uint8_t checksum) {
|
||||
if (sensirion_i2c_generate_crc(data, count) != checksum)
|
||||
return CRC_ERROR;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_general_call_reset(void) {
|
||||
const uint8_t data = 0x06;
|
||||
return sensirion_i2c_hal_write(0, &data, (uint16_t)sizeof(data));
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_fill_cmd_send_buf(uint8_t* buf, uint16_t cmd,
|
||||
const uint16_t* args,
|
||||
uint8_t num_args) {
|
||||
uint8_t i;
|
||||
uint16_t idx = 0;
|
||||
|
||||
buf[idx++] = (uint8_t)((cmd & 0xFF00) >> 8);
|
||||
buf[idx++] = (uint8_t)((cmd & 0x00FF) >> 0);
|
||||
|
||||
for (i = 0; i < num_args; ++i) {
|
||||
buf[idx++] = (uint8_t)((args[i] & 0xFF00) >> 8);
|
||||
buf[idx++] = (uint8_t)((args[i] & 0x00FF) >> 0);
|
||||
|
||||
uint8_t crc = sensirion_i2c_generate_crc((uint8_t*)&buf[idx - 2],
|
||||
SENSIRION_WORD_SIZE);
|
||||
buf[idx++] = crc;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_read_words_as_bytes(uint8_t address, uint8_t* data,
|
||||
uint16_t num_words) {
|
||||
int16_t ret;
|
||||
uint16_t i, j;
|
||||
uint16_t size = num_words * (SENSIRION_WORD_SIZE + CRC8_LEN);
|
||||
uint16_t word_buf[SENSIRION_MAX_BUFFER_WORDS];
|
||||
uint8_t* const buf8 = (uint8_t*)word_buf;
|
||||
|
||||
ret = sensirion_i2c_hal_read(address, buf8, size);
|
||||
if (ret != NO_ERROR)
|
||||
return ret;
|
||||
|
||||
/* check the CRC for each word */
|
||||
for (i = 0, j = 0; i < size; i += SENSIRION_WORD_SIZE + CRC8_LEN) {
|
||||
|
||||
ret = sensirion_i2c_check_crc(&buf8[i], SENSIRION_WORD_SIZE,
|
||||
buf8[i + SENSIRION_WORD_SIZE]);
|
||||
if (ret != NO_ERROR)
|
||||
return ret;
|
||||
|
||||
data[j++] = buf8[i];
|
||||
data[j++] = buf8[i + 1];
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_read_words(uint8_t address, uint16_t* data_words,
|
||||
uint16_t num_words) {
|
||||
int16_t ret;
|
||||
uint8_t i;
|
||||
|
||||
ret = sensirion_i2c_read_words_as_bytes(address, (uint8_t*)data_words,
|
||||
num_words);
|
||||
if (ret != NO_ERROR)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
const uint8_t* word_bytes = (uint8_t*)&data_words[i];
|
||||
data_words[i] = ((uint16_t)word_bytes[0] << 8) | word_bytes[1];
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_write_cmd(uint8_t address, uint16_t command) {
|
||||
uint8_t buf[SENSIRION_COMMAND_SIZE];
|
||||
|
||||
sensirion_i2c_fill_cmd_send_buf(buf, command, NULL, 0);
|
||||
return sensirion_i2c_hal_write(address, buf, SENSIRION_COMMAND_SIZE);
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_write_cmd_with_args(uint8_t address, uint16_t command,
|
||||
const uint16_t* data_words,
|
||||
uint16_t num_words) {
|
||||
uint8_t buf[SENSIRION_MAX_BUFFER_WORDS];
|
||||
uint16_t buf_size;
|
||||
|
||||
buf_size =
|
||||
sensirion_i2c_fill_cmd_send_buf(buf, command, data_words, num_words);
|
||||
return sensirion_i2c_hal_write(address, buf, buf_size);
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_delayed_read_cmd(uint8_t address, uint16_t cmd,
|
||||
uint32_t delay_us, uint16_t* data_words,
|
||||
uint16_t num_words) {
|
||||
int16_t ret;
|
||||
uint8_t buf[SENSIRION_COMMAND_SIZE];
|
||||
|
||||
sensirion_i2c_fill_cmd_send_buf(buf, cmd, NULL, 0);
|
||||
ret = sensirion_i2c_hal_write(address, buf, SENSIRION_COMMAND_SIZE);
|
||||
if (ret != NO_ERROR)
|
||||
return ret;
|
||||
|
||||
if (delay_us)
|
||||
sensirion_i2c_hal_sleep_usec(delay_us);
|
||||
|
||||
return sensirion_i2c_read_words(address, data_words, num_words);
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_read_cmd(uint8_t address, uint16_t cmd,
|
||||
uint16_t* data_words, uint16_t num_words) {
|
||||
return sensirion_i2c_delayed_read_cmd(address, cmd, 0, data_words,
|
||||
num_words);
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_command_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint16_t command) {
|
||||
buffer[offset++] = (uint8_t)((command & 0xFF00) >> 8);
|
||||
buffer[offset++] = (uint8_t)((command & 0x00FF) >> 0);
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_uint32_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint32_t data) {
|
||||
buffer[offset++] = (uint8_t)((data & 0xFF000000) >> 24);
|
||||
buffer[offset++] = (uint8_t)((data & 0x00FF0000) >> 16);
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
buffer[offset++] = (uint8_t)((data & 0x0000FF00) >> 8);
|
||||
buffer[offset++] = (uint8_t)((data & 0x000000FF) >> 0);
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_int32_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
int32_t data) {
|
||||
return sensirion_i2c_add_uint32_t_to_buffer(buffer, offset, (uint32_t)data);
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_uint16_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
uint16_t data) {
|
||||
buffer[offset++] = (uint8_t)((data & 0xFF00) >> 8);
|
||||
buffer[offset++] = (uint8_t)((data & 0x00FF) >> 0);
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_int16_t_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
int16_t data) {
|
||||
return sensirion_i2c_add_uint16_t_to_buffer(buffer, offset, (uint16_t)data);
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_float_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
float data) {
|
||||
union {
|
||||
uint32_t uint32_data;
|
||||
float float_data;
|
||||
} convert;
|
||||
|
||||
convert.float_data = data;
|
||||
|
||||
buffer[offset++] = (uint8_t)((convert.uint32_data & 0xFF000000) >> 24);
|
||||
buffer[offset++] = (uint8_t)((convert.uint32_data & 0x00FF0000) >> 16);
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
buffer[offset++] = (uint8_t)((convert.uint32_data & 0x0000FF00) >> 8);
|
||||
buffer[offset++] = (uint8_t)((convert.uint32_data & 0x000000FF) >> 0);
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint16_t sensirion_i2c_add_bytes_to_buffer(uint8_t* buffer, uint16_t offset,
|
||||
const uint8_t* data,
|
||||
uint16_t data_length) {
|
||||
uint16_t i;
|
||||
|
||||
if (data_length % SENSIRION_WORD_SIZE != 0) {
|
||||
return BYTE_NUM_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < data_length; i += 2) {
|
||||
buffer[offset++] = data[i];
|
||||
buffer[offset++] = data[i + 1];
|
||||
|
||||
buffer[offset] = sensirion_i2c_generate_crc(
|
||||
&buffer[offset - SENSIRION_WORD_SIZE], SENSIRION_WORD_SIZE);
|
||||
offset++;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_write_data(uint8_t address, const uint8_t* data,
|
||||
uint16_t data_length) {
|
||||
return sensirion_i2c_hal_write(address, data, data_length);
|
||||
}
|
||||
|
||||
int16_t sensirion_i2c_read_data_inplace(uint8_t address, uint8_t* buffer,
|
||||
uint16_t expected_data_length) {
|
||||
int16_t error;
|
||||
uint16_t i, j;
|
||||
uint16_t size = (expected_data_length / SENSIRION_WORD_SIZE) *
|
||||
(SENSIRION_WORD_SIZE + CRC8_LEN);
|
||||
|
||||
if (expected_data_length % SENSIRION_WORD_SIZE != 0) {
|
||||
return BYTE_NUM_ERROR;
|
||||
}
|
||||
|
||||
error = sensirion_i2c_hal_read(address, buffer, size);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < size; i += SENSIRION_WORD_SIZE + CRC8_LEN) {
|
||||
|
||||
error = sensirion_i2c_check_crc(&buffer[i], SENSIRION_WORD_SIZE,
|
||||
buffer[i + SENSIRION_WORD_SIZE]);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
buffer[j++] = buffer[i];
|
||||
buffer[j++] = buffer[i + 1];
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
95
drivers/sen5x/sensirion_i2c_hal.c
Normal file
95
drivers/sen5x/sensirion_i2c_hal.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "sensirion_i2c_hal.h"
|
||||
#include "sensirion_common.h"
|
||||
#include "sensirion_config.h"
|
||||
|
||||
/**
|
||||
* Initialize all hard- and software components that are needed for the I2C
|
||||
* communication.
|
||||
*/
|
||||
void sensirion_i2c_hal_init(void) {
|
||||
|
||||
// initialize the bus
|
||||
i2c_init(I2C_DEVICE);
|
||||
|
||||
// first, acquire the shared bus again
|
||||
i2c_acquire(I2C_DEVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources initialized by sensirion_i2c_hal_init().
|
||||
*/
|
||||
void sensirion_i2c_hal_free(void) {
|
||||
i2c_release(I2C_DEVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute one read transaction on the I2C bus, reading a given number of bytes.
|
||||
* If the device does not acknowledge the read command, an error shall be
|
||||
* returned.
|
||||
*
|
||||
* @param address 7-bit I2C address to read from
|
||||
* @param data pointer to the buffer where the data is to be stored
|
||||
* @param count number of bytes to read from I2C and store in the buffer
|
||||
* @returns 0 on success, error code otherwise
|
||||
*/
|
||||
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
|
||||
return i2c_read_bytes(I2C_DEVICE, address, data, count, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute one write transaction on the I2C bus, sending a given number of
|
||||
* bytes. The bytes in the supplied buffer must be sent to the given address. If
|
||||
* the slave device does not acknowledge any of the bytes, an error shall be
|
||||
* returned.
|
||||
*
|
||||
* @param address 7-bit I2C address to write to
|
||||
* @param data pointer to the buffer containing the data to write
|
||||
* @param count number of bytes to read from the buffer and send over I2C
|
||||
* @returns 0 on success, error code otherwise
|
||||
*/
|
||||
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data, uint16_t count) {
|
||||
return i2c_write_bytes(I2C_DEVICE, address, data, count, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for a given number of microseconds. The function should delay the
|
||||
* execution for at least the given time, but may also sleep longer.
|
||||
*
|
||||
* Despite the unit, a <10 millisecond precision is sufficient.
|
||||
*
|
||||
* @param useconds the sleep time in microseconds
|
||||
*/
|
||||
void sensirion_i2c_hal_sleep_usec(uint32_t useconds) {
|
||||
xtimer_usleep(useconds);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user