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

drivers: add driver for SDS011 active laser dust sensor

This commit is contained in:
Michel Rottleuthner 2018-11-22 18:50:29 +01:00
parent 782b181b63
commit f5dc2524d0
7 changed files with 888 additions and 0 deletions

View File

@ -394,6 +394,10 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter sds011,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
ifneq (,$(filter servo,$(USEMODULE)))
FEATURES_REQUIRED += periph_pwm
endif

View File

@ -285,3 +285,7 @@ endif
ifneq (,$(filter xbee,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/xbee/include
endif
ifneq (,$(filter sds011,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sds011/include
endif

317
drivers/include/sds011.h Normal file
View File

@ -0,0 +1,317 @@
/*
* Copyright (C) 2018 HAW-Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_sds011 SDS011 Laser Dust Sensor
* @ingroup drivers_sensors
* @brief Driver SDS011 Laser Dust Sensor
* @{
*
* @file
* @brief Interface for controlling SDS011 Laser Dust Sensor
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef SDS011_H
#define SDS011_H
#include <stdbool.h>
#include "periph/gpio.h"
#include "periph/uart.h"
#include "mutex.h"
#include "sds011_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SDS011 wildcard address to address all devices
*/
#define SDS011_DEVID_WILDCARD (0xFFFF)
/**
* @brief Named return values
*/
enum {
SDS011_OK, /**< all good */
SDS011_INVALID_RESPONSE, /**< invalid response */
SDS011_INVALID_CHKSUM, /**< invalid checksum */
SDS011_ERROR, /**< internal error */
};
/**
* @brief Report mode of the SDS011 sensor
*/
typedef enum sds011_reporting_mode {
SDS011_RMODE_ACTIVE = 0, /**< continuously reporting values */
SDS011_RMODE_QUERY = 1, /**< sensor needs to be queried */
} sds011_reporting_mode_t;
/**
* @brief Work/sleep mode of the SDS011 sensor
*/
typedef enum sds011_working_mode {
SDS011_WMODE_SLEEP = 0, /**< laser & fan are disabled */
SDS011_WMODE_WORK = 1, /**< laser & fan are enabled */
} sds011_working_mode_t;
/**
* @brief Configuration parameters for SDS011 Laser Dust Sensor
*/
typedef struct {
uart_t uart; /**< UART device the sensor is connected to */
gpio_t pwr_pin; /**< GPIO pin for disabling supply voltage for the sensor */
uint16_t dev_id; /**< Unique sensor device ID */
bool pwr_ah; /**< Logic level of the power pin (true for active high) */
} sds011_params_t;
/**
* @brief Data type for storing SDS011 sensor readings
*/
typedef struct {
uint16_t pm_2_5; /**< Particulate Matter 2.5 concentration [0.1µg/m^3] */
uint16_t pm_10; /**< Particulate Matter 10 concentration [0.1µg/m^3] */
} sds011_data_t;
/**
* @brief callback for measurements actively reported by the SDS011 sensor
*/
typedef void (*sds011_callback_t)(sds011_data_t *data, void *ctx);
/**
* @brief Device descriptor definition for SDS011 Laser Dust Sensor
*/
typedef struct {
sds011_params_t params; /**< parameters for SDS011 device */
mutex_t dev_lock; /**< mutex to synchronize device access */
mutex_t cb_lock; /**< mutex to synchronize callbacks */
sds011_callback_t cb; /**< callback deliver values async */
void *cbctx; /**< user context for the callback */
uint16_t checksum; /**< iteratively calculated checksum */
uint8_t rx_mem[SDS011_FRAME_RECV_LEN]; /**< receive buffer */
uint8_t pos; /**< receive buffer position counter */
} sds011_t;
/**
* @brief Initialize SDS011 Laser Dust Sensor
*
* @param[out] dev device descriptor
* @param[in] params device configuration
*
* @pre @p dev != NULL
* @pre @p params != NULL
*
* @return SDS011_OK on success
* @return SDS011_ERROR on error
*/
int sds011_init(sds011_t *dev, const sds011_params_t *params);
/**
* @brief Enable power supply of SDS011 laser dust sensor
*
* @param[in] dev device descriptor
*
* @pre @p dev != NULL
*/
void sds011_power_on(const sds011_t *dev);
/**
* @brief Disable power supply of SDS011 laser dust sensor
*
* @param[in] dev device descriptor
*
* @pre @p dev != NULL
*/
void sds011_power_off(const sds011_t *dev);
/**
* @brief Read measurement values from SDS011 laser dust sensor
*
* @param[in] dev device descriptor
* @param[out] data pointer for storing the values
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
* @pre @p data != NULL
*/
int sds011_read(sds011_t *dev, sds011_data_t *data);
/**
* @brief Register measurement callback
*
* The registered callback is executed when new measurements were
* received by the sensor. This function should be used together with
* active reporting mode of the sensor that automatically sends new
* measurements periodically (factory default setting of the sensor).
*
* @param[in] dev device descriptor
* @param[in] cb function to be called for new values (NULL for disable)
* @param[in] ctx context pointer that will be handed to the callback
*
* @return SDS011_OK on success
* @return SDS011_ERROR when error occured
*
* @pre @p dev != NULL
*/
int sds011_register_callback(sds011_t *dev, sds011_callback_t cb, void *ctx);
/**
* @brief Get the current reporting mode of the sensor
*
* @param[in] dev device descriptor
* @param[out] mode SDS011_RMODE_ACTIVE: continuously report new values
* SDS011_RMODE_QUERY: new values need to be requested
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_get_reporting_mode(sds011_t *dev, sds011_reporting_mode_t *mode);
/**
* @brief Set the reporting mode of the sensor
*
* @param[in] dev device descriptor
* @param[in] mode SDS011_RMODE_ACTIVE: continuously report new values
* SDS011_RMODE_QUERY: new values need to be requested
*
* @note This setting is persistent even after a full power-cycle!
* Factory default is SDS011_RMODE_ACTIVE
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_set_reporting_mode(sds011_t *dev, sds011_reporting_mode_t mode);
/**
* @brief Get current working mode of the sensor
*
* @param[in] dev device descriptor
* @param[out] mode SDS011_WMODE_SLEEP: sensor is in sleep mode (~3 mA)
* SDS011_WMODE_WORK: sensor is in working mode (~65 mA)
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_get_working_mode(sds011_t *dev, sds011_working_mode_t *mode);
/**
* @brief Set working mode of the sensor
*
* @param[in] dev device descriptor
* @param[in] mode SDS011_WMODE_SLEEP: put to sleep mode (~3 mA)
* SDS011_WMODE_WORK: put to working mode (~65 mA)
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_set_working_mode(sds011_t *dev, sds011_working_mode_t mode);
/**
* @brief Get current working period of the sensor
*
* @param[in] dev device descriptor
* @param[out] minutes working period of the sensor in minutes
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_get_working_period(sds011_t *dev, uint8_t *minutes);
/**
* @brief Set working period of the sensor
*
* @param[in] dev device descriptor
* @param[in] minutes 0 - 30 new working period of the sensor in minutes
* 0 for coninuous reporting mode
* 1 - 30 for a period of @p minutes
*
* @note For values greater than 0, the active duration (fan, laser enabled)
* is always fixed to 30 seconds, while the sleep duration is adjusted
* to give an overall period of @p minutes.
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_set_working_period(sds011_t *dev, uint8_t minutes);
/**
* @brief Get firmware version of the sensor
*
* @param[in] dev device descriptor
* @param[out] year year of the firmware version
* @param[out] mon month of the firmware version
* @param[out] day day of the firmware version
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
* @pre @p year != NULL
* @pre @p mon != NULL
* @pre @p day != NULL
*/
int sds011_get_fw_version(sds011_t *dev, uint8_t *year, uint8_t *mon, uint8_t *day);
/**
* @brief Set device ID of the sensor
*
* @param[in] dev device descriptor
* @param[in] sens_dev_id ID as one number (ID byte 1 MSB, ID byte 2 LSB)
*
* @note This setting is persistent even after a full power-cycle!
* Factory default is an individual ID which is printed next to the
* serial number barcode. For the number xxxx-abab the ID is 0xabab.
*
* @return SDS011_OK on success
* @return SDS011_INVALID_RESPONSE when response doesn't match the request
* @return SDS011_INVALID_CHKSUM when response checksum is invalid
* @return SDS011_ERROR when other error occured
*
* @pre @p dev != NULL
*/
int sds011_set_dev_id(sds011_t *dev, uint16_t sens_dev_id);
#ifdef __cplusplus
}
#endif
#endif /* SDS011_H */
/** @} */

1
drivers/sds011/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2018 HAW-Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sds011
* @{
*
* @file
* @brief Internal constants etc. for the SDS011 laser dust sensor
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
* @}
*/
#ifndef SDS011_INTERNAL_H
#define SDS011_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SDS011 baud rate
*/
#define SDS011_UART_BAUDRATE (9600U)
/**
* @name SDS011 frame lengths
* @{
*/
#define SDS011_FRAME_SEND_LEN (19U)
#define SDS011_FRAME_RECV_LEN (10U)
/** @} */
/**
* @name SDS011 command values
* @{
*/
#define SDS011_CMD_DB1_SET_DR_MODE (2U)
#define SDS011_CMD_DB1_QUERY_DATA (4U)
#define SDS011_CMD_DB1_SET_DEV_ID (5U)
#define SDS011_CMD_DB1_SET_SLEEP_WORK (6U)
#define SDS011_CMD_DB1_CHECK_FIRMWARE (7U)
#define SDS011_CMD_DB1_SET_WORK_PERIOD (8U)
/** @} */
/**
* @name SDS011 command option values
* @{
*/
#define SDS011_CMD_OPT_QUERY (0U)
#define SDS011_CMD_OPT_SET (1U)
#define SDS011_CMD_OPT_REPORT_ACTIVE (0U)
#define SDS011_CMD_OPT_REPORT_QUERY (1U)
#define SDS011_CMD_OPT_SLEEP (0U)
#define SDS011_CMD_OPT_WORK (1U)
/** @} */
/**
* @name SDS011 frame constants
* @{
*/
#define SDS011_CMDID_QUERY (0xB4)
#define SDS011_RCMDID_REPLY (0xC5)
#define SDS011_RCMDID_DATA (0xC0)
#define SDS011_FRAME_TAIL (0xAB)
#define SDS011_FRAME_HEAD (0xAA)
#define SDS011_FRAME_CSUM_MSK (0xFF)
/** @} */
/**
* @name SDS011 frame value indexes
* @{
*/
#define SDS011_FRAME_HEAD_IDX (0U)
#define SDS011_CMDID_IDX (1U)
#define SDS011_DB1_IDX (2U)
#define SDS011_DB2_IDX (3U)
#define SDS011_DB3_IDX (4U)
#define SDS011_DB4_IDX (5U)
#define SDS011_DB5_IDX (6U)
#define SDS011_DB6_IDX (7U)
#define SDS011_DEVID1_IDX (15U)
#define SDS011_DEVID2_IDX (16U)
#define SDS011_FRAME_SEND_TAIL_IDX (SDS011_FRAME_SEND_LEN - 1)
#define SDS011_FRAME_RECV_TAIL_IDX (SDS011_FRAME_RECV_LEN - 1)
#define SDS011_FRAME_SEND_CSUM_IDX (SDS011_FRAME_SEND_LEN - 2)
#define SDS011_FRAME_RECV_CSUM_IDX (SDS011_FRAME_RECV_LEN - 2)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* SDS011_INTERNAL_H */
/** @} */

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2018 HAW-Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sds011
* @{
*
* @file
* @brief SDS011 sensor specific configuration
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef SDS011_PARAMS_H
#define SDS011_PARAMS_H
#include "board.h"
#include "periph/uart.h"
#include "saul_reg.h"
#include "sds011.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the SDS011 driver
* @{
*/
#ifndef SDS011_PARAM_UART_DEV
#define SDS011_PARAM_UART_DEV (UART_DEV(1))
#endif
#ifndef SDS011_PARAM_PWR_PIN
#define SDS011_PARAM_PWR_PIN (GPIO_PIN(0, 0))
#endif
#ifndef SDS011_PARAM_PWR_PIN_AH
#define SDS011_PARAM_PWR_PIN_AH (true)
#endif
#ifndef SDS011_PARAMS
#define SDS011_PARAMS { .uart = SDS011_PARAM_UART_DEV, \
.pwr_pin = SDS011_PARAM_PWR_PIN, \
.pwr_ah = SDS011_PARAM_PWR_PIN_AH, \
.dev_id = SDS011_DEVID_WILDCARD }
#endif
#ifndef SDS011_SAUL_INFO
#define SDS011_SAUL_INFO { .name = "SDS011" }
#endif
/** @} */
/**
* @brief SDS011 configuration
*/
static const sds011_params_t sds011_params[] =
{
SDS011_PARAMS
};
/**
* @brief Allocate and configure entries to the SAUL registry
*/
saul_reg_info_t sds011_saul_info[] =
{
SDS011_SAUL_INFO
};
#ifdef __cplusplus
}
#endif
#endif /* SDS011_PARAMS_H */
/** @} */

384
drivers/sds011/sds011.c Normal file
View File

@ -0,0 +1,384 @@
/*
* Copyright (C) 2018 HAW-Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sds011
* @{
*
* @file
* @brief SDS011 Laser Dust Sensor driver implementation
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#include <string.h>
#include "assert.h"
#include "sds011.h"
#include "periph/uart.h"
/**
* @brief UART receive callback
*
* @param[in] arg Context value previously handed to the uart_init call
* @param[in] data single byte received over UART
*/
static void _rx_cb(void *arg, uint8_t data)
{
sds011_t *dev = (sds011_t*)arg;
/* frame MUST start with HEAD byte and the buffer must be cleared
before writing to it again */
if (((dev->pos == 0) && (data != SDS011_FRAME_HEAD)) ||
(dev->pos == SDS011_FRAME_RECV_LEN)) {
return;
}
dev->rx_mem[dev->pos] = data;
if ((dev->pos >= SDS011_DB1_IDX) &&
(dev->pos < SDS011_FRAME_RECV_CSUM_IDX)) {
dev->checksum += data;
}
else if ((dev->pos == SDS011_FRAME_RECV_LEN - 1) &&
(dev->rx_mem[SDS011_FRAME_HEAD_IDX] == SDS011_FRAME_HEAD) &&
(dev->rx_mem[SDS011_FRAME_RECV_TAIL_IDX] == SDS011_FRAME_TAIL)) {
dev->checksum &= SDS011_FRAME_CSUM_MSK;
if (dev->rx_mem[SDS011_FRAME_RECV_CSUM_IDX] == dev->checksum) {
if ((dev->cb != NULL) &&
(dev->rx_mem[SDS011_CMDID_IDX] == SDS011_RCMDID_DATA)) {
sds011_data_t measure;
measure.pm_2_5 = dev->rx_mem[SDS011_DB1_IDX] |
(dev->rx_mem[SDS011_DB2_IDX] << 8);
measure.pm_10 = dev->rx_mem[SDS011_DB3_IDX] |
(dev->rx_mem[SDS011_DB4_IDX] << 8);
dev->cb(&measure, dev->cbctx);
dev->pos = -1;
}
}
else {
dev->pos = -1;
}
dev->checksum = 0;
/* unlock the mutex for the calling function */
mutex_unlock(&dev->cb_lock);
}
dev->pos++;
}
/**
* @brief send command and wait for first replied message
*
* @param[in] dev SDS011 device the command is sent to
* @param[in] data_bytes data bytes to send within the command
* @param[in] len number of data bytes
* @param[out] recv_frm pointer where the received frame will be stored
* must at least provide SDS011_FRAME_RECV_LEN bytes
*/
int _send_recv_cmd(sds011_t *dev, uint8_t *data_bytes, size_t len, uint8_t *recv_frm)
{
uint8_t cmd[SDS011_FRAME_SEND_LEN] = {0};
int checksum = 0;
int res = SDS011_ERROR;
cmd[SDS011_FRAME_HEAD_IDX] = SDS011_FRAME_HEAD;
cmd[SDS011_CMDID_IDX] = SDS011_CMDID_QUERY;
for (unsigned i = 0; i < len; i++) {
cmd[SDS011_DB1_IDX + i] = data_bytes[i];
checksum += data_bytes[i];
}
cmd[SDS011_DEVID1_IDX] = (dev->params.dev_id >> 8) & 0xFF;
checksum += cmd[SDS011_DEVID1_IDX];
cmd[SDS011_DEVID2_IDX] = dev->params.dev_id & 0xFF;
checksum += cmd[SDS011_DEVID2_IDX];
cmd[SDS011_FRAME_SEND_LEN - 2] = checksum & SDS011_FRAME_CSUM_MSK;
cmd[SDS011_FRAME_SEND_TAIL_IDX] = SDS011_FRAME_TAIL;
mutex_lock(&dev->dev_lock);
dev->pos = 0;
dev->checksum = 0;
mutex_lock(&dev->cb_lock);
/* if no active reporting callback is registered, UART must be enabled first */
if((dev->cb == NULL) &&
(uart_init(dev->params.uart, SDS011_UART_BAUDRATE, _rx_cb, dev) != 0)) {
mutex_unlock(&dev->cb_lock);
mutex_unlock(&dev->dev_lock);
return SDS011_ERROR;
}
uart_write(dev->params.uart, cmd, SDS011_FRAME_SEND_LEN);
/* wait for the isr callback to unlock the mutex */
mutex_lock(&dev->cb_lock);
/* only copy data when checksum was valid */
if (dev->pos != 0) {
memcpy(recv_frm, dev->rx_mem, SDS011_FRAME_RECV_LEN);
/* mark the recv buffer as free */
dev->pos = 0;
dev->checksum = 0;
/* check if we received a valid response for the cmd sent*/
if(((recv_frm[SDS011_CMDID_IDX] == SDS011_RCMDID_REPLY) &&
(cmd[SDS011_DB1_IDX] == recv_frm[SDS011_DB1_IDX]))
|| ((recv_frm[SDS011_CMDID_IDX] == SDS011_RCMDID_DATA)
&& (cmd[SDS011_DB1_IDX] == SDS011_CMD_DB1_QUERY_DATA))) {
res = SDS011_OK;
}
else {
res = SDS011_INVALID_RESPONSE;
}
}
else {
res = SDS011_INVALID_CHKSUM;
}
/* reset mutex state */
mutex_unlock(&dev->cb_lock);
/* if no active reporting callback is registered, UART can be disabled */
if((dev->cb == NULL) &&
(uart_init(dev->params.uart, SDS011_UART_BAUDRATE, NULL, NULL) != 0)) {
res = SDS011_ERROR;
}
/* release device */
mutex_unlock(&dev->dev_lock);
return res;
}
/**
* @brief shorthand to get a single byte property with _send_recv_cmd
*
* @param[in] dev SDS011 device the command is sent to
* @param[in] data_bytes data bytes to send within the command
* @param[in] len number of data bytes
* @param[out] p pointer for storing single data byte of the reply
* @param[out] p_idx index of data byte we want to read
*/
static int _get_property(sds011_t *dev, uint8_t *data_bytes, size_t len,
uint8_t *p, uint8_t p_idx)
{
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, data_bytes, len, recv);
if (res == SDS011_OK) {
*p = recv[p_idx];
}
return res;
}
int sds011_init(sds011_t *dev, const sds011_params_t *params)
{
assert((dev != NULL) && (params != NULL) && (params->uart < UART_NUMOF));
if ((params->pwr_pin != GPIO_UNDEF) &&
(gpio_init(params->pwr_pin, GPIO_OUT) != 0)) {
return SDS011_ERROR;
}
memcpy(&dev->params, params, sizeof(sds011_params_t));
mutex_init(&dev->dev_lock);
mutex_init(&dev->cb_lock);
dev->cb = NULL;
sds011_power_on(dev);
return SDS011_OK;
}
int sds011_register_callback(sds011_t *dev, sds011_callback_t cb, void *ctx)
{
assert(dev != NULL);
mutex_lock(&dev->dev_lock);
dev->cbctx = ctx;
dev->cb = cb;
/* either register un unregister the uart callback */
if (uart_init(dev->params.uart, SDS011_UART_BAUDRATE,
cb == NULL ? NULL : _rx_cb,
cb == NULL ? NULL : dev) != 0) {
mutex_unlock(&dev->dev_lock);
return SDS011_ERROR;
}
mutex_unlock(&dev->dev_lock);
return SDS011_OK;
}
void sds011_power_on(const sds011_t *dev)
{
assert(dev != NULL);
if(dev->params.pwr_pin != GPIO_UNDEF) {
gpio_write(dev->params.pwr_pin, dev->params.pwr_ah);
}
}
void sds011_power_off(const sds011_t *dev)
{
assert(dev != NULL);
if(dev->params.pwr_pin != GPIO_UNDEF) {
gpio_write(dev->params.pwr_pin, !dev->params.pwr_ah);
}
}
int sds011_get_reporting_mode(sds011_t *dev, sds011_reporting_mode_t *mode)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_DR_MODE, SDS011_CMD_OPT_QUERY};
uint8_t prop = 0;
int res = _get_property(dev, cmd, sizeof(cmd), &prop, SDS011_DB3_IDX);
*mode = ((prop == 0) ? SDS011_RMODE_ACTIVE : SDS011_RMODE_QUERY);
return res;
}
int sds011_set_reporting_mode(sds011_t *dev, sds011_reporting_mode_t mode)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_DR_MODE, SDS011_CMD_OPT_SET, mode};
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if (res == SDS011_OK) {
if ((recv[SDS011_DB2_IDX] == SDS011_CMD_OPT_SET) &&
(recv[SDS011_DB3_IDX] == mode)) {
return SDS011_OK;
}
return SDS011_ERROR;
}
return res;
}
int sds011_read(sds011_t *dev, sds011_data_t *data)
{
assert((dev != NULL) && (data != NULL));
uint8_t cmd[] = {SDS011_CMD_DB1_QUERY_DATA};
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if (res == SDS011_OK) {
data->pm_2_5 = recv[SDS011_DB1_IDX] | (recv[SDS011_DB2_IDX] << 8);
data->pm_10 = recv[SDS011_DB3_IDX] | (recv[SDS011_DB4_IDX] << 8);
}
return res;
}
int sds011_set_dev_id(sds011_t *dev, uint16_t sens_dev_id)
{
assert(dev != NULL);
uint8_t cmd[13] = {0};
cmd[0] = SDS011_CMD_DB1_SET_DEV_ID;
cmd[11] = (sens_dev_id >> 8) & 0xFF;
cmd[12] = sens_dev_id & 0xFF;
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if ((res == SDS011_OK) &&
(recv[SDS011_DB5_IDX] == cmd[11]) &&
(recv[SDS011_DB6_IDX] == cmd[12])) {
return SDS011_OK;
}
return SDS011_ERROR;
}
int sds011_get_working_mode(sds011_t *dev, sds011_working_mode_t *mode)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_SLEEP_WORK, SDS011_CMD_OPT_QUERY};
uint8_t prop = 0;
int res = _get_property(dev, cmd, sizeof(cmd), &prop, SDS011_DB3_IDX);
*mode = ((prop == 0) ? SDS011_WMODE_SLEEP : SDS011_WMODE_WORK);
return res;
}
int sds011_set_working_mode(sds011_t *dev, sds011_working_mode_t mode)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_SLEEP_WORK, SDS011_CMD_OPT_SET, mode};
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if (res == SDS011_OK) {
if ((recv[SDS011_DB2_IDX] == SDS011_CMD_OPT_SET) &&
(recv[SDS011_DB3_IDX] == mode)) {
return SDS011_OK;
}
return SDS011_ERROR;
}
return res;
}
int sds011_get_working_period(sds011_t *dev, uint8_t *minutes)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_WORK_PERIOD, SDS011_CMD_OPT_QUERY};
return _get_property(dev, cmd, sizeof(cmd), minutes, SDS011_DB3_IDX);
}
int sds011_set_working_period(sds011_t *dev, uint8_t minutes)
{
assert(dev != NULL);
uint8_t cmd[] = {SDS011_CMD_DB1_SET_WORK_PERIOD, SDS011_CMD_OPT_SET, minutes};
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if (res == SDS011_OK) {
if ((recv[SDS011_DB2_IDX] == SDS011_CMD_OPT_SET) &&
(recv[SDS011_DB3_IDX] == minutes)) {
return SDS011_OK;
}
return SDS011_ERROR;
}
return res;
}
int sds011_get_fw_version(sds011_t *dev, uint8_t *year, uint8_t *mon, uint8_t *day)
{
assert((dev != NULL) && (year != NULL) && (mon != NULL) && (day != NULL));
uint8_t cmd[] = {SDS011_CMD_DB1_CHECK_FIRMWARE};
uint8_t recv[SDS011_FRAME_RECV_LEN];
int res = _send_recv_cmd(dev, cmd, sizeof(cmd), recv);
if (res == SDS011_OK) {
*year = recv[SDS011_DB2_IDX];
*mon = recv[SDS011_DB3_IDX];
*day = recv[SDS011_DB4_IDX];
}
return res;
}