Skip to content

Commit

Permalink
Merge pull request #47 from Sensirion/start-manual-fan-cleaning
Browse files Browse the repository at this point in the history
Support manually triggering the fan cleaning
  • Loading branch information
abrauchli authored Nov 5, 2019
2 parents dec9ade + 31aef25 commit 0bd4227
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 94 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [`changed`] Split out `default_config.inc` from Makefile to configure paths
and CFLAGS
* [`fixed`] Fix strict-aliasing ans sign-conversion compiler warnings
* [`added`] instantly start manual fan cleaning with
`sps30_start_manual_fan_cleaning()`
* [`changed`] rename `SPS_*` constants to `SPS30_`

## [2.0.0] - 2019-05-14

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include "sensirion_uart.h"
#include "sensirion_arch_config.h"
#include "sensirion_uart.h"
#include <fcntl.h>
#include <stdio.h>
#include <termios.h>
Expand Down
2 changes: 1 addition & 1 deletion embedded-uart-common/sensirion_uart_implementation.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include "sensirion_uart.h"
#include "sensirion_arch_config.h"
#include "sensirion_uart.h"

/*
* INSTRUCTIONS
Expand Down
92 changes: 42 additions & 50 deletions sps30-uart/sps30.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,63 +33,64 @@
#include "sensirion_shdlc.h"
#include "sps_git_version.h"

#define SPS_ADDR 0x00
#define SPS_CMD_START_MEASUREMENT 0x00
#define SPS_CMD_STOP_MEASUREMENT 0x01
#define SPS_SUBCMD_MEASUREMENT_START \
#define SPS30_ADDR 0x00
#define SPS30_CMD_START_MEASUREMENT 0x00
#define SPS30_CMD_STOP_MEASUREMENT 0x01
#define SPS30_SUBCMD_MEASUREMENT_START \
{ 0x01, 0x03 }
#define SPS_CMD_READ_MEASUREMENT 0x03
#define SPS_CMD_READ_FAN_SPEED 0x40
#define SPS_CMD_FAN_CLEAN_INTV 0x80
#define SPS_SUBCMD_READ_FAN_CLEAN_INTV 0x00
#define SPS_CMD_DEV_INFO 0xd0
#define SPS_CMD_DEV_INFO_SUBCMD_GET_SERIAL \
#define SPS30_CMD_READ_MEASUREMENT 0x03
#define SPS30_CMD_READ_FAN_SPEED 0x40
#define SPS30_CMD_FAN_CLEAN_INTV 0x80
#define SPS30_CMD_FAN_CLEAN_INTV_LEN 5
#define SPS30_SUBCMD_READ_FAN_CLEAN_INTV 0x00
#define SPS30_CMD_START_FAN_CLEANING 0x56
#define SPS30_CMD_DEV_INFO 0xd0
#define SPS30_CMD_DEV_INFO_SUBCMD_GET_SERIAL \
{ 0x03 }
#define SPS_CMD_RESET 0xd3
#define SPS_ERR_STATE(state) (SPS_ERR_STATE_MASK | (state))
#define SPS_CMD_FAN_CLEAN_LENGTH 5
#define SPS30_CMD_RESET 0xd3
#define SPS30_ERR_STATE(state) (SPS30_ERR_STATE_MASK | (state))

const char *sps_get_driver_version() {
return SPS_DRV_VERSION_STR;
}

int16_t sps30_probe() {
char serial[SPS_MAX_SERIAL_LEN];
char serial[SPS30_MAX_SERIAL_LEN];
int16_t ret = sps30_get_serial(serial);

return ret;
}

int16_t sps30_get_serial(char *serial) {
struct sensirion_shdlc_rx_header header;
uint8_t param_buf[] = SPS_CMD_DEV_INFO_SUBCMD_GET_SERIAL;
uint8_t param_buf[] = SPS30_CMD_DEV_INFO_SUBCMD_GET_SERIAL;
int16_t ret;

ret = sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_DEV_INFO, sizeof(param_buf),
param_buf, SPS_MAX_SERIAL_LEN, &header,
ret = sensirion_shdlc_xcv(SPS30_ADDR, SPS30_CMD_DEV_INFO, sizeof(param_buf),
param_buf, SPS30_MAX_SERIAL_LEN, &header,
(uint8_t *)serial);
if (ret < 0)
return ret;

if (header.state)
return SPS_ERR_STATE(header.state);
return SPS30_ERR_STATE(header.state);

return 0;
}

int16_t sps30_start_measurement() {
struct sensirion_shdlc_rx_header header;
uint8_t param_buf[] = SPS_SUBCMD_MEASUREMENT_START;
uint8_t param_buf[] = SPS30_SUBCMD_MEASUREMENT_START;

return sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_START_MEASUREMENT,
return sensirion_shdlc_xcv(SPS30_ADDR, SPS30_CMD_START_MEASUREMENT,
sizeof(param_buf), param_buf, 0, &header, NULL);
}

int16_t sps30_stop_measurement() {
struct sensirion_shdlc_rx_header header;

return sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_STOP_MEASUREMENT, 0, NULL, 0,
&header, NULL);
return sensirion_shdlc_xcv(SPS30_ADDR, SPS30_CMD_STOP_MEASUREMENT, 0, NULL,
0, &header, NULL);
}

int16_t sps30_read_measurement(struct sps30_measurement *measurement) {
Expand All @@ -102,13 +103,13 @@ int16_t sps30_read_measurement(struct sps30_measurement *measurement) {
float32_t f32_value;
} val, data[10];

ret = sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_READ_MEASUREMENT, 0, NULL,
ret = sensirion_shdlc_xcv(SPS30_ADDR, SPS30_CMD_READ_MEASUREMENT, 0, NULL,
sizeof(data), &header, (uint8_t *)data);
if (ret)
return ret;

if (header.data_len != sizeof(data))
return SPS_ERR_NOT_ENOUGH_DATA;
return SPS30_ERR_NOT_ENOUGH_DATA;

idx = 0;
val.u32_value = be32_to_cpu(data[idx].u32_value);
Expand Down Expand Up @@ -142,57 +143,41 @@ int16_t sps30_read_measurement(struct sps30_measurement *measurement) {
measurement->typical_particle_size = val.f32_value;

if (header.state)
return SPS_ERR_STATE(header.state);

return 0;
}

int16_t sps30_read_fan_speed(uint16_t *fan_rpm) {
struct sensirion_shdlc_rx_header header;
int16_t ret;

ret = sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_READ_FAN_SPEED, 0, NULL,
sizeof(*fan_rpm), &header, (uint8_t *)fan_rpm);
if (ret < 0)
return ret;

*fan_rpm = be16_to_cpu(*fan_rpm);
if (header.state)
return SPS_ERR_STATE(header.state);
return SPS30_ERR_STATE(header.state);

return 0;
}

int16_t sps30_get_fan_auto_cleaning_interval(uint32_t *interval_seconds) {
struct sensirion_shdlc_rx_header header;
uint8_t tx_data[] = {SPS_SUBCMD_READ_FAN_CLEAN_INTV};
uint8_t tx_data[] = {SPS30_SUBCMD_READ_FAN_CLEAN_INTV};
int16_t ret;

ret = sensirion_shdlc_xcv(SPS_ADDR, SPS_CMD_FAN_CLEAN_INTV, sizeof(tx_data),
tx_data, sizeof(*interval_seconds), &header,
(uint8_t *)interval_seconds);
ret = sensirion_shdlc_xcv(
SPS30_ADDR, SPS30_CMD_FAN_CLEAN_INTV, sizeof(tx_data), tx_data,
sizeof(*interval_seconds), &header, (uint8_t *)interval_seconds);
if (ret < 0)
return ret;

*interval_seconds = be32_to_cpu(*interval_seconds);

if (header.state)
return SPS_ERR_STATE(header.state);
return SPS30_ERR_STATE(header.state);

return 0;
}

int16_t sps30_set_fan_auto_cleaning_interval(uint32_t interval_seconds) {
struct sensirion_shdlc_rx_header header;
uint8_t ix;
uint8_t cleaning_command[SPS_CMD_FAN_CLEAN_LENGTH];
uint8_t cleaning_command[SPS30_CMD_FAN_CLEAN_INTV_LEN];
uint32_t value = be32_to_cpu(interval_seconds);

cleaning_command[0] = SPS_SUBCMD_READ_FAN_CLEAN_INTV;
cleaning_command[0] = SPS30_SUBCMD_READ_FAN_CLEAN_INTV;
for (ix = 0; ix < sizeof(uint32_t); ix++)
cleaning_command[ix + 1] = (uint8_t)(value >> (8 * ix));
return sensirion_shdlc_xcv(
SPS_ADDR, SPS_CMD_FAN_CLEAN_INTV, sizeof(cleaning_command),
SPS30_ADDR, SPS30_CMD_FAN_CLEAN_INTV, sizeof(cleaning_command),
(const uint8_t *)cleaning_command, sizeof(interval_seconds), &header,
(uint8_t *)&interval_seconds);
}
Expand All @@ -214,6 +199,13 @@ int16_t sps30_set_fan_auto_cleaning_interval_days(uint8_t interval_days) {
60 * 60);
}

int16_t sps30_start_manual_fan_cleaning() {
struct sensirion_shdlc_rx_header header;

return sensirion_shdlc_xcv(SPS30_ADDR, SPS30_CMD_START_FAN_CLEANING, 0,
NULL, 0, &header, NULL);
}

int16_t sps30_reset() {
return sensirion_shdlc_tx(SPS_ADDR, SPS_CMD_RESET, 0, NULL);
return sensirion_shdlc_tx(SPS30_ADDR, SPS30_CMD_RESET, 0, NULL);
}
31 changes: 16 additions & 15 deletions sps30-uart/sps30.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ extern "C" {

#include "sensirion_arch_config.h"

#define SPS_MAX_SERIAL_LEN 32
#define SPS_ERR_NOT_ENOUGH_DATA (-1)
#define SPS_ERR_STATE_MASK (0x100)
#define SPS_IS_ERR_STATE(err_code) (((err_code) | 0xff) == 0x1ff)
#define SPS_GET_ERR_STATE(err_code) ((err_code)&0xff)
#define SPS30_MAX_SERIAL_LEN 32
#define SPS30_ERR_NOT_ENOUGH_DATA (-1)
#define SPS30_ERR_STATE_MASK (0x100)
#define SPS30_IS_ERR_STATE(err_code) (((err_code) | 0xff) == 0x1ff)
#define SPS30_GET_ERR_STATE(err_code) ((err_code)&0xff)

struct sps30_measurement {
float32_t mc_1p0;
Expand Down Expand Up @@ -107,16 +107,6 @@ int16_t sps30_stop_measurement();
*/
int16_t sps30_read_measurement(struct sps30_measurement *measurement);

/**
* sps30_read_fan_speed() - read the current fan speed
*
* Note that fan_rpm must be discarded when the return code is non-zero.
*
* @fan_rpm: Memory where the fan speed in rpm is stored
* Return: 0 on success, an error code otherwise
*/
int16_t sps30_read_fan_speed(uint16_t *fan_rpm);

/**
* sps30_get_fan_auto_cleaning_interval() - read the current auto-cleaning
* interval
Expand Down Expand Up @@ -163,6 +153,17 @@ int16_t sps30_get_fan_auto_cleaning_interval_days(uint8_t *interval_days);
*/
int16_t sps30_set_fan_auto_cleaning_interval_days(uint8_t interval_days);

/**
* sps30_start_manual_fan_cleaning() - Immediately trigger the fan cleaning
*
* Note that this command can only be run when the sensor is in measurement
* mode, i.e. after sps30_start_measurement() without subsequent
* sps30_stop_measurement().
*
* Return: 0 on success, an error code otherwise
*/
int16_t sps30_start_manual_fan_cleaning();

/**
* sps30_reset() - reset the SGP30
*
Expand Down
39 changes: 12 additions & 27 deletions sps30-uart/sps30_example_usage.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h> // printf
#include <unistd.h> // sleep
#include <stdio.h> // printf

#include "sensirion_uart.h"
#include "sps30.h"
Expand All @@ -40,51 +39,37 @@
* PLATFORM
*/
//#define printf(...)
//#define sleep(...)

int main(void) {
struct sps30_measurement m;
char serial[SPS_MAX_SERIAL_LEN];
uint8_t auto_clean_days = 4;
uint32_t auto_clean;
char serial[SPS30_MAX_SERIAL_LEN];
const uint8_t AUTO_CLEAN_DAYS = 4;
int16_t ret;

while (sensirion_uart_open() != 0) {
printf("UART init failed\n");
sleep(1);
sensirion_sleep_usec(1000000); /* sleep for 1s */
}

/* Busy loop for initialization, because the main loop does not work without
* a sensor.
*/
while (sps30_probe() != 0) {
printf("SPS sensor probing failed\n");
sleep(1);
printf("SPS30 sensor probing failed\n");
sensirion_sleep_usec(1000000); /* sleep for 1s */
}
printf("SPS sensor probing successful\n");
printf("SPS30 sensor probing successful\n");

ret = sps30_get_serial(serial);
if (ret)
printf("error %d reading serial\n", ret);
else
printf("SPS Serial: %s\n", serial);
printf("SPS30 Serial: %s\n", serial);

ret = sps30_get_fan_auto_cleaning_interval(&auto_clean);
if (ret)
printf("error %d retrieving the auto-clean interval\n", ret);
else
printf("auto-cleaning interval is %d seconds\n", auto_clean);

ret = sps30_set_fan_auto_cleaning_interval_days(auto_clean_days);
ret = sps30_set_fan_auto_cleaning_interval_days(AUTO_CLEAN_DAYS);
if (ret)
printf("error %d setting the auto-clean interval\n", ret);

ret = sps30_get_fan_auto_cleaning_interval_days(&auto_clean_days);
if (ret)
printf("error retrieving the auto-clean interval\n");
else
printf("auto-cleaning interval set to %u days\n", auto_clean_days);

ret = sps30_start_measurement();
if (ret < 0)
printf("error starting measurement\n");
Expand All @@ -96,9 +81,9 @@ int main(void) {
printf("error reading measurement\n");

} else {
if (SPS_IS_ERR_STATE(ret)) {
if (SPS30_IS_ERR_STATE(ret)) {
printf("Chip state: %u - measurements may not be accurate\n",
SPS_GET_ERR_STATE(ret));
SPS30_GET_ERR_STATE(ret));
}

printf("measured values:\n"
Expand All @@ -116,7 +101,7 @@ int main(void) {
m.nc_2p5, m.nc_4p0, m.nc_10p0, m.typical_particle_size);
}

sleep(1);
sensirion_sleep_usec(1000000); /* sleep for 1s */
} while (1);

if (sensirion_uart_close() != 0)
Expand Down

0 comments on commit 0bd4227

Please sign in to comment.