Refactor in files. Add BMP180 and SHT4x sensor, monitor VDD voltage, scheduling with timer
parent
82c0bcc836
commit
8eea54771b
|
@ -1,8 +0,0 @@
|
||||||
/ {
|
|
||||||
vbatt {
|
|
||||||
compatible = "voltage-divider";
|
|
||||||
io-channels = <&adc 4>;
|
|
||||||
output-ohms = <4600>;
|
|
||||||
full-ohms = <(4600 + 3230)>;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
|
||||||
|
[platformio]
|
||||||
|
default_envs = nrf52beacon
|
||||||
|
|
||||||
|
[env:nrf52beacon]
|
||||||
|
platform = nordicnrf52
|
||||||
|
framework = zephyr
|
||||||
|
platform_packages =
|
||||||
|
platformio/framework-zephyr@^2.30400.230705
|
||||||
|
platformio/toolchain-gccarmnoneeabi@^1.120201.221222
|
||||||
|
board = nrf52_dk
|
||||||
|
#build_flags = -DNRF51_S130
|
||||||
|
#board_build.variant = CJMCU_LIS3DH
|
||||||
|
monitor_speed = 115200
|
||||||
|
extra_scripts = pre:extra_script.py
|
||||||
|
upload_protocol = custom
|
||||||
|
upload_command = echo "rtt stop; halt; program $PROJECT_DIR/$SOURCE verify reset; rtt start" | ncat localhost 4444
|
||||||
|
monitor_port = socket://localhost:9090
|
||||||
|
monitor_filters =
|
||||||
|
direct
|
||||||
|
; time ; Add timestamp with milliseconds for each new line
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Peter Bigot Consulting, LLC
|
||||||
|
* Copyright (c) 2019-2020 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/init.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/adc.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "battery.h"
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(BATTERYVDD, CONFIG_ADC_LOG_LEVEL);
|
||||||
|
|
||||||
|
#define ZEPHYR_USER DT_PATH(zephyr_user)
|
||||||
|
|
||||||
|
/* Other boards may use dividers that only reduce battery voltage to
|
||||||
|
* the maximum supported by the hardware (3.6 V)
|
||||||
|
*/
|
||||||
|
#define BATTERY_ADC_GAIN ADC_GAIN_1_6
|
||||||
|
|
||||||
|
struct io_channel_config {
|
||||||
|
uint8_t channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct divider_config {
|
||||||
|
struct io_channel_config io_channel;
|
||||||
|
struct gpio_dt_spec power_gpios;
|
||||||
|
/* output_ohm is used as a flag value: if it is nonzero then
|
||||||
|
* the battery is measured through a voltage divider;
|
||||||
|
* otherwise it is assumed to be directly connected to Vdd.
|
||||||
|
*/
|
||||||
|
uint32_t output_ohm;
|
||||||
|
uint32_t full_ohm;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct divider_config dividervdd_config = {
|
||||||
|
.io_channel = {
|
||||||
|
DT_IO_CHANNELS_INPUT(ZEPHYR_USER),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct divider_data {
|
||||||
|
const struct device *adc;
|
||||||
|
struct adc_channel_cfg adc_cfg;
|
||||||
|
struct adc_sequence adc_seq;
|
||||||
|
int16_t raw;
|
||||||
|
};
|
||||||
|
static struct divider_data dividervdd_data = {
|
||||||
|
.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(ZEPHYR_USER)),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dividervdd_setup(void)
|
||||||
|
{
|
||||||
|
const struct divider_config *cfg = ÷rvdd_config;
|
||||||
|
const struct io_channel_config *iocp = &cfg->io_channel;
|
||||||
|
const struct gpio_dt_spec *gcp = &cfg->power_gpios;
|
||||||
|
struct divider_data *ddp = ÷rvdd_data;
|
||||||
|
struct adc_sequence *asp = &ddp->adc_seq;
|
||||||
|
struct adc_channel_cfg *accp = &ddp->adc_cfg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!device_is_ready(ddp->adc)) {
|
||||||
|
LOG_ERR("ADC device is not ready %s", ddp->adc->name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gcp->port) {
|
||||||
|
if (!device_is_ready(gcp->port)) {
|
||||||
|
LOG_ERR("%s: device not ready", gcp->port->name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
rc = gpio_pin_configure_dt(gcp, GPIO_OUTPUT_INACTIVE);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_ERR("Failed to control feed %s.%u: %d",
|
||||||
|
gcp->port->name, gcp->pin, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*asp = (struct adc_sequence){
|
||||||
|
.channels = BIT(0),
|
||||||
|
.buffer = &ddp->raw,
|
||||||
|
.buffer_size = sizeof(ddp->raw),
|
||||||
|
.oversampling = 4,
|
||||||
|
.calibrate = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ADC_NRFX_SAADC
|
||||||
|
*accp = (struct adc_channel_cfg){
|
||||||
|
.gain = BATTERY_ADC_GAIN,
|
||||||
|
.reference = ADC_REF_INTERNAL,
|
||||||
|
.acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40),
|
||||||
|
};
|
||||||
|
|
||||||
|
accp->input_positive = SAADC_CH_PSELP_PSELP_VDD;
|
||||||
|
|
||||||
|
asp->resolution = 14;
|
||||||
|
#else /* CONFIG_ADC_var */
|
||||||
|
#error Unsupported ADC
|
||||||
|
#endif /* CONFIG_ADC_var */
|
||||||
|
|
||||||
|
rc = adc_channel_setup(ddp->adc, accp);
|
||||||
|
LOG_INF("Setup VDD AIN%u got %d", iocp->channel, rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool battery_ok;
|
||||||
|
|
||||||
|
int batteryvdd_setup()
|
||||||
|
{
|
||||||
|
int rc = dividervdd_setup();
|
||||||
|
|
||||||
|
battery_ok = (rc == 0);
|
||||||
|
LOG_INF("Battery VDD setup: %d %d", rc, battery_ok);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SYS_INIT(batteryvdd_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||||
|
|
||||||
|
int16_t batteryvdd_sample(void)
|
||||||
|
{
|
||||||
|
int16_t rc = -ENOENT;
|
||||||
|
|
||||||
|
if (battery_ok) {
|
||||||
|
struct divider_data *ddp = ÷rvdd_data;
|
||||||
|
//const struct divider_config *dcp = ÷rvdd_config;
|
||||||
|
struct adc_sequence *sp = &ddp->adc_seq;
|
||||||
|
|
||||||
|
rc = adc_read(ddp->adc, sp);
|
||||||
|
sp->calibrate = false;
|
||||||
|
if (rc == 0) {
|
||||||
|
int32_t val = ddp->raw;
|
||||||
|
|
||||||
|
adc_raw_to_millivolts(adc_ref_internal(ddp->adc),
|
||||||
|
ddp->adc_cfg.gain,
|
||||||
|
sp->resolution,
|
||||||
|
&val);
|
||||||
|
rc = val;
|
||||||
|
LOG_INF("raw %u ~ %u mV\n", ddp->raw, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
|
@ -142,7 +142,7 @@ static int divider_setup(void)
|
||||||
|
|
||||||
static bool battery_ok;
|
static bool battery_ok;
|
||||||
|
|
||||||
static int battery_setup(const struct device *arg)
|
int battery_setup()
|
||||||
{
|
{
|
||||||
int rc = divider_setup();
|
int rc = divider_setup();
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ static int battery_setup(const struct device *arg)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_INIT(battery_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
//SYS_INIT(battery_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||||
|
|
||||||
int battery_measure_enable(bool enable)
|
int battery_measure_enable(bool enable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,12 +15,17 @@
|
||||||
*/
|
*/
|
||||||
int battery_measure_enable(bool enable);
|
int battery_measure_enable(bool enable);
|
||||||
|
|
||||||
|
|
||||||
|
int battery_setup();
|
||||||
|
int batteryvdd_setup();
|
||||||
|
|
||||||
/** Measure the battery voltage.
|
/** Measure the battery voltage.
|
||||||
*
|
*
|
||||||
* @return the battery voltage in millivolts, or a negative error
|
* @return the battery voltage in millivolts, or a negative error
|
||||||
* code.
|
* code.
|
||||||
*/
|
*/
|
||||||
int16_t battery_sample(void);
|
int16_t battery_sample(void);
|
||||||
|
int16_t batteryvdd_sample(void);
|
||||||
|
|
||||||
/** A point in a battery discharge curve sequence.
|
/** A point in a battery discharge curve sequence.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(bmp180);
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/i2c.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "bmp180.h"
|
||||||
|
#include "sds011.h"
|
||||||
|
|
||||||
|
#define BMP180_I2CADDR 0x77 //!< BMP180 I2C address
|
||||||
|
|
||||||
|
#define BMP180_ULTRALOWPOWER 0 //!< Ultra low power mode
|
||||||
|
#define BMP180_STANDARD 1 //!< Standard mode
|
||||||
|
#define BMP180_HIGHRES 2 //!< High-res mode
|
||||||
|
#define BMP180_ULTRAHIGHRES 3 //!< Ultra high-res mode
|
||||||
|
|
||||||
|
#define OVERSAMPLING BMP180_ULTRALOWPOWER
|
||||||
|
|
||||||
|
#define BMP180_CAL_AC1 0xAA //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_AC2 0xAC //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_AC3 0xAE //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_AC4 0xB0 //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_AC5 0xB2 //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_AC6 0xB4 //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_B1 0xB6 //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_B2 0xB8 //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_MB 0xBA //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_MC 0xBC //!< R Calibration data (16 bits)
|
||||||
|
#define BMP180_CAL_MD 0xBE //!< R Calibration data (16 bits)
|
||||||
|
|
||||||
|
#define BMP180_CONTROL 0xF4 //!< Control register
|
||||||
|
#define BMP180_TEMPDATA 0xF6 //!< Temperature data register
|
||||||
|
#define BMP180_PRESSUREDATA 0xF6 //!< Pressure data register
|
||||||
|
#define BMP180_READTEMPCMD 0x2E //!< Read temperature control register value
|
||||||
|
#define BMP180_READPRESSURECMD 0x34 //!< Read pressure control register value
|
||||||
|
|
||||||
|
#define I2C_PORT DT_NODELABEL(i2c0)
|
||||||
|
|
||||||
|
int16_t ac1, ac2, ac3, b1, b2, mb, mc, md;
|
||||||
|
uint16_t ac4, ac5, ac6;
|
||||||
|
|
||||||
|
const struct device *devi2c;
|
||||||
|
|
||||||
|
uint8_t read_reg_8(const struct device *devi2c, uint8_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bufin[1];
|
||||||
|
uint8_t bufout[1];
|
||||||
|
int ret;
|
||||||
|
bufin[0]=reg;
|
||||||
|
ret = i2c_write_read(devi2c, 0x77, bufin, 1, bufout, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Failed to read from devi2cice\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return bufout[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t read_reg_16(const struct device *devi2c, uint8_t reg)
|
||||||
|
{
|
||||||
|
uint16_t bufout;
|
||||||
|
int ret;
|
||||||
|
ret = i2c_write_read(devi2c, BMP180_I2CADDR, ®, 1, &bufout, 2);
|
||||||
|
// ret = i2c_burst_read(devi2c, BMP180_I2CADDR, reg,
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Failed to read from devi2cice\n");
|
||||||
|
return ret;
|
||||||
|
//} else {
|
||||||
|
// printk("Reg %d Value %d\n", reg, sys_be16_to_cpu(bufout));
|
||||||
|
}
|
||||||
|
return sys_be16_to_cpu(bufout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_reg_8(const struct device *devi2c, uint8_t reg, uint8_t data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = i2c_reg_write_byte(devi2c, BMP180_I2CADDR, reg, data);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Failed to write to device\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t computeB5(int32_t UT) {
|
||||||
|
int32_t X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) >> 15;
|
||||||
|
int32_t X2 = ((int32_t)mc << 11) / (X1 + (int32_t)md);
|
||||||
|
return X1 + X2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t readRawTemperature(const struct device *devi2c)
|
||||||
|
{
|
||||||
|
write_reg_8(devi2c, BMP180_CONTROL, BMP180_READTEMPCMD);
|
||||||
|
k_msleep(10);
|
||||||
|
return read_reg_16(devi2c, BMP180_TEMPDATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t readRawPressure(const struct device *devi2c)
|
||||||
|
{
|
||||||
|
uint32_t raw;
|
||||||
|
/*uint8_t raw1;
|
||||||
|
uint8_t raw2;
|
||||||
|
uint8_t raw3;*/
|
||||||
|
|
||||||
|
write_reg_8(devi2c, BMP180_CONTROL, BMP180_READPRESSURECMD + (OVERSAMPLING << 6));
|
||||||
|
|
||||||
|
if (OVERSAMPLING == BMP180_ULTRALOWPOWER) {
|
||||||
|
k_msleep(5);
|
||||||
|
} else if (OVERSAMPLING == BMP180_STANDARD) {
|
||||||
|
k_msleep(8);
|
||||||
|
} else if (OVERSAMPLING == BMP180_HIGHRES) {
|
||||||
|
k_msleep(14);
|
||||||
|
} else {
|
||||||
|
k_msleep(26);
|
||||||
|
}
|
||||||
|
raw = read_reg_16(devi2c, BMP180_PRESSUREDATA);
|
||||||
|
|
||||||
|
raw <<= 8;
|
||||||
|
raw |= read_reg_8(devi2c, BMP180_PRESSUREDATA + 2);
|
||||||
|
|
||||||
|
|
||||||
|
/* raw1 = read_reg_8(devi2c, BMP180_PRESSUREDATA);
|
||||||
|
raw2 = read_reg_8(devi2c, BMP180_PRESSUREDATA + 1);
|
||||||
|
raw3 = read_reg_8(devi2c, BMP180_PRESSUREDATA + 2);
|
||||||
|
|
||||||
|
raw = raw1 << 16 | raw2 << 8 | raw3;
|
||||||
|
|
||||||
|
*/
|
||||||
|
raw >>= (8 - OVERSAMPLING);
|
||||||
|
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t readPressure(const struct device *devi2c) {
|
||||||
|
int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
|
||||||
|
uint32_t B4, B7;
|
||||||
|
|
||||||
|
UT = readRawTemperature(devi2c);
|
||||||
|
UP = readRawPressure(devi2c);
|
||||||
|
|
||||||
|
B5 = computeB5(UT);
|
||||||
|
/*
|
||||||
|
// do pressure calcs
|
||||||
|
B6 = B5 - 4000;
|
||||||
|
X1 = ((int32_t)b2 * ((B6 * B6) >> 12)) >> 11;
|
||||||
|
X2 = ((int32_t)ac2 * B6) >> 11;
|
||||||
|
X3 = X1 + X2;
|
||||||
|
B3 = ((((int32_t)ac1 * 4 + X3) << OVERSAMPLING) + 2) / 4;
|
||||||
|
|
||||||
|
X1 = ((int32_t)ac3 * B6) >> 13;
|
||||||
|
X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
|
||||||
|
X3 = ((X1 + X2) + 2) >> 2;
|
||||||
|
B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
|
||||||
|
B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> OVERSAMPLING);
|
||||||
|
|
||||||
|
if (B7 < 0x80000000) {
|
||||||
|
p = (B7 * 2) / B4;
|
||||||
|
} else {
|
||||||
|
p = (B7 / B4) * 2;
|
||||||
|
}
|
||||||
|
X1 = (p >> 8) * (p >> 8);
|
||||||
|
X1 = (X1 * 3038) >> 16;
|
||||||
|
X2 = (-7357 * p) >> 16;
|
||||||
|
|
||||||
|
p = p + ((X1 + X2 + (int32_t)3791) >> 4);
|
||||||
|
*/
|
||||||
|
B6= B5 - 4000;
|
||||||
|
X1 = (b2 * ((B6 * B6) >> 12)) >> 11;
|
||||||
|
X2 = (ac2 * B6) >> 11;
|
||||||
|
X3 = X1 + X2;
|
||||||
|
B3 = (((ac1 * 4 + X3) << OVERSAMPLING) + 2) >> 2;
|
||||||
|
|
||||||
|
X1 = (ac3 * B6) >> 13;
|
||||||
|
X2 = (b1 * ((B6 * B6) >> 12)) >> 16;
|
||||||
|
X3 = ((X1 + X2) + 2) >> 2;
|
||||||
|
B4 = (ac4 * (unsigned long)(X3 + 32768UL)) >> 15;
|
||||||
|
B7 = ((unsigned long)UP - B3) * (50000UL >> OVERSAMPLING);
|
||||||
|
|
||||||
|
if(B7 < 0x80000000)
|
||||||
|
p = (B7 * 2) / B4;
|
||||||
|
else
|
||||||
|
p = (B7 / B4) * 2;
|
||||||
|
|
||||||
|
X1 = (p >> 8) * (p >> 8);
|
||||||
|
X1 = (X1 * 3038) >> 16;
|
||||||
|
X2 = (-7357 * p) >> 16;
|
||||||
|
|
||||||
|
p = p + ((X1 + X2 + 3791) >> 4);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t readSealevelPressure(const struct device *devi2c, float altitude_meters) {
|
||||||
|
float pressure = readPressure(devi2c);
|
||||||
|
return (uint32_t)(pressure / pow(1.0 - altitude_meters / 44330, 5.255));
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t bmp180_readPressure() {
|
||||||
|
return readSealevelPressure(devi2c, 146.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
int bmp180_setup()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
devi2c = DEVICE_DT_GET(I2C_PORT);
|
||||||
|
|
||||||
|
if (!devi2c) {
|
||||||
|
printk("I2C: device driver not found.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = write_reg_8(devi2c, 0xe0, 0xb6);
|
||||||
|
if(ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
k_msleep(500);
|
||||||
|
|
||||||
|
ac1 = read_reg_16(devi2c, BMP180_CAL_AC1);
|
||||||
|
ac2 = read_reg_16(devi2c, BMP180_CAL_AC2);
|
||||||
|
ac3 = read_reg_16(devi2c, BMP180_CAL_AC3);
|
||||||
|
ac4 = read_reg_16(devi2c, BMP180_CAL_AC4);
|
||||||
|
ac5 = read_reg_16(devi2c, BMP180_CAL_AC5);
|
||||||
|
ac6 = read_reg_16(devi2c, BMP180_CAL_AC6);
|
||||||
|
|
||||||
|
b1 = read_reg_16(devi2c, BMP180_CAL_B1);
|
||||||
|
b2 = read_reg_16(devi2c, BMP180_CAL_B2);
|
||||||
|
|
||||||
|
mb = read_reg_16(devi2c, BMP180_CAL_MB);
|
||||||
|
mc = read_reg_16(devi2c, BMP180_CAL_MC);
|
||||||
|
md = read_reg_16(devi2c, BMP180_CAL_MD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
int bmp180_setup();
|
||||||
|
uint32_t bmp180_readPressure();
|
470
src/main.c
470
src/main.c
|
@ -27,39 +27,45 @@
|
||||||
#include <zephyr/devicetree.h>
|
#include <zephyr/devicetree.h>
|
||||||
#include <zephyr/drivers/sensor.h>
|
#include <zephyr/drivers/sensor.h>
|
||||||
#include <zephyr/drivers/gpio.h>
|
#include <zephyr/drivers/gpio.h>
|
||||||
#include <zephyr/drivers/uart.h>
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(main);
|
||||||
|
|
||||||
#include "battery.h"
|
#include "battery.h"
|
||||||
|
#include "sht4x.h"
|
||||||
|
#include "bmp180.h"
|
||||||
|
#include "sds011.h"
|
||||||
#include "hal/nrf_gpiote.h"
|
#include "hal/nrf_gpiote.h"
|
||||||
|
|
||||||
static K_SEM_DEFINE(ble_init_ok, 0, 1);
|
|
||||||
static K_FIFO_DEFINE(fifo_adv_data);
|
static K_FIFO_DEFINE(fifo_adv_data);
|
||||||
|
|
||||||
|
static K_SEM_DEFINE(ble_init_ok, 0, 1);
|
||||||
|
static K_SEM_DEFINE(adv_send_ok, 0, 1);
|
||||||
|
|
||||||
|
#define BTHOME_MAXELT 9
|
||||||
|
enum captor_type { BATTERY, BATTERYVDD, TEMPERATURE, PRESSURE, VOLTAGE, VOLTAGEVDD, PM25, PM10, HUMIDITY };
|
||||||
|
uint8_t eltid[BTHOME_MAXELT] = { 0x01, 0x01, 0x02, 0x04, 0x0c, 0x0c, 0x0d, 0x0e, 0x2e };
|
||||||
|
uint8_t eltsize[BTHOME_MAXELT] = { 1, 1, 2, 3, 2, 2, 2, 2, 1};
|
||||||
|
uint8_t eltenabled[BTHOME_MAXELT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
struct bthome_adv_t {
|
struct bthome_adv_t {
|
||||||
void *fifo_reserved;
|
void *fifo_reserved;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
int16_t data_s16;
|
int16_t data_s16;
|
||||||
uint16_t data_u16;
|
uint16_t data_u16;
|
||||||
uint8_t data_u8;
|
uint8_t data_u8;
|
||||||
|
uint32_t data_u32;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint8_t mfg_bthome_data[28];
|
||||||
|
uint8_t mfg_bthome_sizetosend = 0;
|
||||||
|
uint8_t mfg_bthome_numelt = 0;
|
||||||
|
uint8_t bthome_datapos[BTHOME_MAXELT];
|
||||||
|
//uint8_t bthome_datapos[] = { 4, 6, 9, 12, 14, 18, 21 };
|
||||||
|
|
||||||
#define UPDATE_MIN(MIN, SAMPLE) if (SAMPLE < MIN) { MIN = SAMPLE; }
|
|
||||||
#define UPDATE_MAX(MAX, SAMPLE) if (SAMPLE > MAX) { MAX = SAMPLE; }
|
|
||||||
#define UPDATE_MIN_MAX(MIN, MAX, SAMPLE) { UPDATE_MIN(MIN, SAMPLE); UPDATE_MAX(MAX, SAMPLE); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
0x01: Battery
|
|
||||||
0x02: Temperature
|
|
||||||
0x0c: Voltage
|
|
||||||
0x0d: PM2.5
|
|
||||||
0x0e: PM10
|
|
||||||
*/
|
|
||||||
static uint8_t mfg_bthome_data[] = { 0xd2, 0xfc, 0x40, 0x01, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x0e, 0x00, 0x00 };
|
|
||||||
uint8_t bthome_datapos[] = { 4, 6, 9, 12, 15 };
|
|
||||||
|
|
||||||
enum captor_type { BATTERY, TEMPERATURE, VOLTAGE, PM25, PM10 };
|
|
||||||
|
|
||||||
struct captor_wait {
|
struct captor_wait {
|
||||||
enum captor_type captor;
|
enum captor_type captor;
|
||||||
|
@ -69,16 +75,22 @@ struct bthome_adv_t {
|
||||||
struct captor_wait params[] = { {BATTERY, 120 }, {TEMPERATURE, 60}, {PM25, 60} };
|
struct captor_wait params[] = { {BATTERY, 120 }, {TEMPERATURE, 60}, {PM25, 60} };
|
||||||
|
|
||||||
|
|
||||||
static const struct bt_data ad[] = {
|
/*static const struct bt_data ad[] = {
|
||||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||||
BT_DATA(BT_DATA_SVC_DATA16, mfg_bthome_data, 17),
|
BT_DATA(BT_DATA_SVC_DATA16, mfg_bthome_data, 23),
|
||||||
};
|
};*/
|
||||||
|
|
||||||
#define GPIO_PORT DT_NODELABEL(gpio0)
|
#define GPIO_PORT DT_NODELABEL(gpio0)
|
||||||
|
|
||||||
#define STACKSIZE 2048
|
#define STACKSIZE 2048
|
||||||
#define PRIORITY 7
|
#define PRIORITY 7
|
||||||
|
|
||||||
|
K_THREAD_STACK_DEFINE(stack_wq_pms, STACKSIZE);
|
||||||
|
K_THREAD_STACK_DEFINE(stack_wq_i2c, STACKSIZE);
|
||||||
|
|
||||||
|
struct k_work_q workqueue_pms;
|
||||||
|
struct k_work_q workqueue_i2c;
|
||||||
|
|
||||||
static const struct battery_level_point battery_levels[] = {
|
static const struct battery_level_point battery_levels[] = {
|
||||||
/* "Curve" here eyeballed from captured data for the [Adafruit
|
/* "Curve" here eyeballed from captured data for the [Adafruit
|
||||||
* 3.7v 2000 mAh](https://www.adafruit.com/product/2011) LIPO
|
* 3.7v 2000 mAh](https://www.adafruit.com/product/2011) LIPO
|
||||||
|
@ -96,23 +108,26 @@ struct bthome_adv_t {
|
||||||
{ 625, 3550 },
|
{ 625, 3550 },
|
||||||
{ 0, 3100 },
|
{ 0, 3100 },
|
||||||
};
|
};
|
||||||
|
static const struct battery_level_point battery_nimh_levels[] = {
|
||||||
|
/* "Curve" here eyeballed from captured data for the [Adafruit
|
||||||
|
* 3.7v 2000 mAh](https://www.adafruit.com/product/2011) LIPO
|
||||||
|
* under full load that started with a charge of 3.96 V and
|
||||||
|
* dropped about linearly to 3.58 V over 15 hours. It then
|
||||||
|
* dropped rapidly to 3.10 V over one hour, at which point it
|
||||||
|
* stopped transmitting.
|
||||||
|
*
|
||||||
|
* Based on eyeball comparisons we'll say that 15/16 of life
|
||||||
|
* goes between 3.95 and 3.55 V, and 1/16 goes between 3.55 V
|
||||||
|
* and 3.1 V.
|
||||||
|
*/
|
||||||
|
|
||||||
#define UART_PORT DT_NODELABEL(uart0)
|
{ 10000, 2800 },
|
||||||
static const struct device *const uart_dev = DEVICE_DT_GET(UART_PORT);
|
{ 90, 2600 },
|
||||||
|
{ 50, 2440 },
|
||||||
uint8_t SDS_SLEEPCMD[19] = {
|
{ 0, 2300 },
|
||||||
0xAA, 0xB4, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB
|
|
||||||
};
|
|
||||||
uint8_t SDS_WAKEUPCMD[19] = {
|
|
||||||
0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static K_FIFO_DEFINE(fifo_pms);
|
|
||||||
struct pms_data_t {
|
|
||||||
void *fifo_reserved;
|
|
||||||
uint32_t ts;
|
|
||||||
char data[10];
|
|
||||||
};
|
|
||||||
|
|
||||||
//#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
|
//#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
|
||||||
|
|
||||||
|
@ -131,8 +146,8 @@ struct bthome_adv_t {
|
||||||
printk("Disconnected (reason 0x%02x)\n", reason);
|
printk("Disconnected (reason 0x%02x)\n", reason);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
uint32_t getTs()
|
/* uint32_t getTs()
|
||||||
{
|
{e
|
||||||
uint32_t ts = (k_uptime_get_32()/1000);
|
uint32_t ts = (k_uptime_get_32()/1000);
|
||||||
// LOG_INF("getTs: %d", ts);
|
// LOG_INF("getTs: %d", ts);
|
||||||
return ts;
|
return ts;
|
||||||
|
@ -166,7 +181,7 @@ struct bthome_adv_t {
|
||||||
return UINT16_MAX;
|
return UINT16_MAX;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static void bt_ready(void)
|
static void bt_ready(void)
|
||||||
{
|
{
|
||||||
|
@ -179,7 +194,11 @@ struct bthome_adv_t {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
struct bt_data ad[] = {
|
||||||
|
//BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||||
|
BT_DATA(BT_DATA_SVC_DATA16, mfg_bthome_data, mfg_bthome_sizetosend),
|
||||||
|
};
|
||||||
|
err = bt_le_adv_start(BT_LE_ADV_PARAM(BT_LE_ADV_OPT_USE_IDENTITY | BT_LE_ADV_OPT_USE_NAME, BT_GAP_ADV_SLOW_INT_MIN,BT_GAP_ADV_SLOW_INT_MAX, NULL), ad, ARRAY_SIZE(ad), NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk("Advertising failed to start (err %d)\n", err);
|
printk("Advertising failed to start (err %d)\n", err);
|
||||||
return;
|
return;
|
||||||
|
@ -212,7 +231,7 @@ struct bthome_adv_t {
|
||||||
.cancel = auth_cancel,
|
.cancel = auth_cancel,
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
bool test_bthome_data_set()
|
/*bool test_bthome_data_set()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < sizeof(bthome_datapos); i++)
|
for(int i = 0; i < sizeof(bthome_datapos); i++)
|
||||||
{
|
{
|
||||||
|
@ -223,49 +242,143 @@ struct bthome_adv_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*void shift_bthome_datapos(uint8_t value)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < BTHOME_MAXELT; i++)
|
||||||
|
{
|
||||||
|
if(bthome_datapos[i] == 255)
|
||||||
|
{
|
||||||
|
bthome_datapos[i] = bthome_datapos[i] + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
uint8_t mfg_bthome_addelt(uint8_t eltid, uint8_t eltsize)
|
||||||
|
{
|
||||||
|
if(mfg_bthome_numelt == 0)
|
||||||
|
{
|
||||||
|
mfg_bthome_numelt++;
|
||||||
|
mfg_bthome_data[3] = eltid;
|
||||||
|
mfg_bthome_sizetosend = mfg_bthome_sizetosend + eltsize +1;
|
||||||
|
return 3;
|
||||||
|
} else {
|
||||||
|
if(eltid < mfg_bthome_data[3])
|
||||||
|
{
|
||||||
|
mfg_bthome_sizetosend = mfg_bthome_sizetosend + eltsize +1;
|
||||||
|
for(int i = 0; i < eltsize+1; i++)
|
||||||
|
{
|
||||||
|
for(int j = mfg_bthome_sizetosend; j > 2; j--)
|
||||||
|
{
|
||||||
|
mfg_bthome_data[j] = mfg_bthome_data[j-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shift_bthome_datapos(eltsize+1);
|
||||||
|
mfg_bthome_data[3] = eltid;
|
||||||
|
return 3;
|
||||||
|
} else {
|
||||||
|
mfg_bthome_data[mfg_bthome_sizetosend] = eltid;
|
||||||
|
mfg_bthome_sizetosend = mfg_bthome_sizetosend + eltsize +1;
|
||||||
|
return mfg_bthome_sizetosend - eltsize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mfg_bthome_build()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < BTHOME_MAXELT; i++)
|
||||||
|
{
|
||||||
|
if(eltenabled[i] == 1)
|
||||||
|
{
|
||||||
|
mfg_bthome_numelt++;
|
||||||
|
mfg_bthome_data[mfg_bthome_sizetosend] = eltid[i];
|
||||||
|
bthome_datapos[i] = mfg_bthome_sizetosend;
|
||||||
|
mfg_bthome_sizetosend = mfg_bthome_sizetosend + eltsize[i] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publish_adv_thread()
|
void publish_adv_thread()
|
||||||
{
|
{
|
||||||
bool adv_activate = false;
|
bool adv_activate = false;
|
||||||
|
uint8_t numeltreceived = 0;
|
||||||
|
uint8_t eltreceived[BTHOME_MAXELT] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
//static uint8_t mfg_bthome_data[] = { 0xd2, 0xfc, 0x40, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x2e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x0e, 0x00, 0x00 };
|
||||||
|
//uint8_t bthome_datapos[] = { 4, 6, 9, 12, 14, 18, 21 };
|
||||||
|
|
||||||
k_sem_take(&ble_init_ok, K_FOREVER);
|
k_sem_take(&ble_init_ok, K_FOREVER);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct bthome_adv_t *request = k_fifo_get(&fifo_adv_data, K_FOREVER);
|
k_sem_take(&adv_send_ok, K_FOREVER);
|
||||||
|
while(k_fifo_is_empty(&fifo_adv_data) == 0)
|
||||||
|
{
|
||||||
|
struct bthome_adv_t *request = k_fifo_get(&fifo_adv_data, K_NO_WAIT);
|
||||||
|
/* if(bthome_datapos[request->type] == 255)
|
||||||
|
{
|
||||||
|
bthome_datapos[request->type] = mfg_bthome_addelt(eltid[request->type], eltsize[request->type]);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if(eltreceived[request->type] == 0) {
|
||||||
|
numeltreceived++;
|
||||||
|
eltreceived[request->type] = 1;
|
||||||
|
}
|
||||||
if(request->type == VOLTAGE)
|
if(request->type == VOLTAGE)
|
||||||
{
|
{
|
||||||
mfg_bthome_data[10] = request->data_u16 >> 8;
|
mfg_bthome_data[bthome_datapos[VOLTAGE]+2] = request->data_u16 >> 8;
|
||||||
mfg_bthome_data[9] = request->data_u16;
|
mfg_bthome_data[bthome_datapos[VOLTAGE]+1] = request->data_u16;
|
||||||
} else if(request->type == BATTERY)
|
} else if(request->type == BATTERY)
|
||||||
{
|
{
|
||||||
mfg_bthome_data[4] = request->data_u8;
|
mfg_bthome_data[bthome_datapos[BATTERY]+1] = request->data_u8;
|
||||||
|
} else if(request->type == VOLTAGEVDD)
|
||||||
|
{
|
||||||
|
mfg_bthome_data[bthome_datapos[VOLTAGEVDD]+2] = request->data_u16 >> 8;
|
||||||
|
mfg_bthome_data[bthome_datapos[VOLTAGEVDD]+1] = request->data_u16;
|
||||||
|
} else if(request->type == BATTERYVDD)
|
||||||
|
{
|
||||||
|
mfg_bthome_data[bthome_datapos[BATTERYVDD]+1] = request->data_u8;
|
||||||
} else if(request->type == TEMPERATURE)
|
} else if(request->type == TEMPERATURE)
|
||||||
{
|
{
|
||||||
mfg_bthome_data[7] = request->data_s16 >> 8;
|
mfg_bthome_data[bthome_datapos[TEMPERATURE]+2] = request->data_s16 >> 8;
|
||||||
mfg_bthome_data[6] = request->data_s16;
|
mfg_bthome_data[bthome_datapos[TEMPERATURE]+1] = request->data_s16;
|
||||||
|
} else if(request->type == HUMIDITY)
|
||||||
|
{
|
||||||
|
mfg_bthome_data[bthome_datapos[HUMIDITY]+1] = request->data_u8;
|
||||||
|
} else if(request->type == PRESSURE)
|
||||||
|
{
|
||||||
|
mfg_bthome_data[bthome_datapos[PRESSURE]+3] = request->data_u32 >> 16;
|
||||||
|
mfg_bthome_data[bthome_datapos[PRESSURE]+2] = request->data_u32 >> 8;
|
||||||
|
mfg_bthome_data[bthome_datapos[PRESSURE]+1] = request->data_u32;
|
||||||
} else if(request->type == PM25)
|
} else if(request->type == PM25)
|
||||||
{
|
{
|
||||||
mfg_bthome_data[13] = request->data_u16 >> 8;
|
mfg_bthome_data[bthome_datapos[PM25]+2] = request->data_u16 >> 8;
|
||||||
mfg_bthome_data[12] = request->data_u16;
|
mfg_bthome_data[bthome_datapos[PM25]+1] = request->data_u16;
|
||||||
} else if(request->type == PM10)
|
} else if(request->type == PM10)
|
||||||
{
|
{
|
||||||
mfg_bthome_data[16] = request->data_u16 >> 8;
|
mfg_bthome_data[bthome_datapos[PM10]+2] = request->data_u16 >> 8;
|
||||||
mfg_bthome_data[15] = request->data_u16;
|
mfg_bthome_data[bthome_datapos[PM10]+1] = request->data_u16;
|
||||||
}
|
}
|
||||||
if(test_bthome_data_set() == true)
|
|
||||||
{
|
k_free(request);
|
||||||
|
}
|
||||||
|
if(numeltreceived == mfg_bthome_numelt) {
|
||||||
|
//LOG_HEXDUMP_INF(mfg_bthome_data, mfg_bthome_sizetosend, "mfg_bthome_data");
|
||||||
|
//printk("Send ADV Size %d\n", mfg_bthome_sizetosend);
|
||||||
if(adv_activate == false)
|
if(adv_activate == false)
|
||||||
{
|
{
|
||||||
bt_ready();
|
bt_ready();
|
||||||
adv_activate = true;
|
adv_activate = true;
|
||||||
} else {
|
} else {
|
||||||
|
struct bt_data ad[] = {
|
||||||
|
//BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||||
|
BT_DATA(BT_DATA_SVC_DATA16, mfg_bthome_data, mfg_bthome_sizetosend),
|
||||||
|
};
|
||||||
bt_le_adv_update_data(ad, ARRAY_SIZE(ad), NULL, 0);
|
bt_le_adv_update_data(ad, ARRAY_SIZE(ad), NULL, 0);
|
||||||
printk("Update ADV\n");
|
printk("Update ADV\n");
|
||||||
//k_msleep(50);
|
//k_msleep(50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
k_free(request);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K_THREAD_DEFINE(publish_adv_thread_id, STACKSIZE, publish_adv_thread, NULL, NULL, NULL, PRIORITY, 0, 0);
|
K_THREAD_DEFINE(publish_adv_thread_id, STACKSIZE, publish_adv_thread, NULL, NULL, NULL, PRIORITY, 0, 0);
|
||||||
|
@ -273,9 +386,10 @@ struct bthome_adv_t {
|
||||||
static void work_battery_handler(struct k_work *work)
|
static void work_battery_handler(struct k_work *work)
|
||||||
{
|
{
|
||||||
struct bthome_adv_t bthome_adv;
|
struct bthome_adv_t bthome_adv;
|
||||||
bthome_adv.type = VOLTAGE;
|
|
||||||
bthome_adv.data_u16 = (uint16_t) battery_sample();
|
|
||||||
size_t size = sizeof(struct bthome_adv_t);
|
size_t size = sizeof(struct bthome_adv_t);
|
||||||
|
bthome_adv.type = VOLTAGE;
|
||||||
|
battery_setup();
|
||||||
|
bthome_adv.data_u16 = (uint16_t) battery_sample();
|
||||||
char *mem_ptr = k_malloc(size);
|
char *mem_ptr = k_malloc(size);
|
||||||
memcpy(mem_ptr, &bthome_adv, size);
|
memcpy(mem_ptr, &bthome_adv, size);
|
||||||
k_fifo_put(&fifo_adv_data, mem_ptr);
|
k_fifo_put(&fifo_adv_data, mem_ptr);
|
||||||
|
@ -285,160 +399,107 @@ struct bthome_adv_t {
|
||||||
char *mem_ptr2 = k_malloc(size);
|
char *mem_ptr2 = k_malloc(size);
|
||||||
memcpy(mem_ptr2, &bthome_adv, size);
|
memcpy(mem_ptr2, &bthome_adv, size);
|
||||||
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
||||||
|
k_sem_give(&adv_send_ok);
|
||||||
printk("Battery: %d mV (%d%%)\n",bthome_adv.data_u16, bthome_adv.data_u8);
|
printk("Battery: %d mV (%d%%)\n",bthome_adv.data_u16, bthome_adv.data_u8);
|
||||||
|
|
||||||
|
bthome_adv.type = VOLTAGEVDD;
|
||||||
|
batteryvdd_setup();
|
||||||
|
bthome_adv.data_u16 = (uint16_t) batteryvdd_sample();
|
||||||
|
char *mem_ptr3 = k_malloc(size);
|
||||||
|
memcpy(mem_ptr3, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr3);
|
||||||
|
|
||||||
|
bthome_adv.type = BATTERYVDD;
|
||||||
|
bthome_adv.data_u8 = round(battery_level_pptt(bthome_adv.data_u16, battery_nimh_levels)/100);
|
||||||
|
char *mem_ptr4 = k_malloc(size);
|
||||||
|
memcpy(mem_ptr4, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr4);
|
||||||
|
k_sem_give(&adv_send_ok);
|
||||||
|
printk("Battery VDD: %d mV (%d%%)\n",bthome_adv.data_u16, bthome_adv.data_u8);
|
||||||
|
|
||||||
}
|
}
|
||||||
K_WORK_DEFINE(work_battery, work_battery_handler);
|
K_WORK_DEFINE(work_battery, work_battery_handler);
|
||||||
|
void timer_battery_handler(struct k_timer *stm)
|
||||||
|
{
|
||||||
|
k_work_submit(&work_battery);
|
||||||
|
}
|
||||||
|
K_TIMER_DEFINE(timer_battery, timer_battery_handler, NULL);
|
||||||
|
|
||||||
static void work_temperature_handler(struct k_work *work)
|
static void work_temperature_handler(struct k_work *work)
|
||||||
{
|
{
|
||||||
struct bthome_adv_t bthome_adv;
|
struct bthome_adv_t bthome_adv;
|
||||||
|
sht4x_probe();
|
||||||
bthome_adv.type = TEMPERATURE;
|
bthome_adv.type = TEMPERATURE;
|
||||||
bthome_adv.data_s16 = 2512;
|
bthome_adv.data_s16 = (int16_t)(sht4x_ReadTempeature()*100);
|
||||||
size_t size = sizeof(struct bthome_adv_t);
|
size_t size = sizeof(struct bthome_adv_t);
|
||||||
char *mem_ptr = k_malloc(size);
|
char *mem_ptr = k_malloc(size);
|
||||||
memcpy(mem_ptr, &bthome_adv, size);
|
memcpy(mem_ptr, &bthome_adv, size);
|
||||||
k_fifo_put(&fifo_adv_data, mem_ptr);
|
k_fifo_put(&fifo_adv_data, mem_ptr);
|
||||||
printk("Temperature: %d°\n",bthome_adv.data_s16);
|
printk("Temperature: %d°\n",bthome_adv.data_s16);
|
||||||
|
bthome_adv.type = HUMIDITY;
|
||||||
|
bthome_adv.data_u8 = (uint8_t)(sht4x_ReadHumidity());
|
||||||
|
char *mem_ptr2 = k_malloc(size);
|
||||||
|
memcpy(mem_ptr2, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
||||||
|
k_sem_give(&adv_send_ok);
|
||||||
|
printk("Humidity: %d pc \n",bthome_adv.data_u8);
|
||||||
}
|
}
|
||||||
K_WORK_DEFINE(work_temperature, work_temperature_handler);
|
K_WORK_DEFINE(work_temperature, work_temperature_handler);
|
||||||
|
|
||||||
//char pm_measure_data[10];
|
void timer_temperature_handler(struct k_timer *stm)
|
||||||
struct pms_data_t pms_data;
|
|
||||||
int pm_measure_position = 0;
|
|
||||||
bool pms_enable = false;
|
|
||||||
bool pms_warming = false;
|
|
||||||
#define WARMUPTIME_SDS_MS 15000
|
|
||||||
#define READINGTIME_SDS_MS 5000
|
|
||||||
|
|
||||||
|
|
||||||
void send_uart_cmd(uint8_t *buf)
|
|
||||||
{
|
{
|
||||||
//int msg_len = strlen(buf);
|
k_work_submit_to_queue(&workqueue_i2c, &work_temperature);
|
||||||
printk("Send to uart\n");
|
}
|
||||||
|
K_TIMER_DEFINE(timer_temperature, timer_temperature_handler, NULL);
|
||||||
|
|
||||||
for (int i = 0; i < 19; i++) {
|
static void work_pressure_handler(struct k_work *work)
|
||||||
uart_poll_out(uart_dev, buf[i]);
|
{
|
||||||
|
struct bthome_adv_t bthome_adv;
|
||||||
|
bthome_adv.type = PRESSURE;
|
||||||
|
bthome_adv.data_u32 = bmp180_readPressure();
|
||||||
|
size_t size = sizeof(struct bthome_adv_t);
|
||||||
|
char *mem_ptr = k_malloc(size);
|
||||||
|
memcpy(mem_ptr, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr);
|
||||||
|
k_sem_give(&adv_send_ok);
|
||||||
|
printk("Pressure: %d Pa \n",bthome_adv.data_u32);
|
||||||
}
|
}
|
||||||
|
K_WORK_DEFINE(work_pressure, work_pressure_handler);
|
||||||
|
|
||||||
|
|
||||||
|
void timer_pressure_handler(struct k_timer *stm)
|
||||||
|
{
|
||||||
|
k_work_submit_to_queue(&workqueue_i2c, &work_pressure);
|
||||||
}
|
}
|
||||||
|
K_TIMER_DEFINE(timer_pressure, timer_pressure_handler, NULL);
|
||||||
|
|
||||||
static void work_pms_handler(struct k_work *work)
|
static void work_pms_handler(struct k_work *work)
|
||||||
{
|
{
|
||||||
uint32_t ts_start_measure;
|
sds011_probe();
|
||||||
send_uart_cmd(SDS_WAKEUPCMD);
|
|
||||||
pms_warming = true;
|
|
||||||
pms_enable = true;
|
|
||||||
k_msleep(WARMUPTIME_SDS_MS);
|
|
||||||
pms_warming = false;
|
|
||||||
ts_start_measure = getTs();
|
|
||||||
|
|
||||||
struct pms_data_t *pms_data_read;
|
|
||||||
|
|
||||||
uint32_t sds_pm10_sum = 0;
|
|
||||||
uint32_t sds_pm25_sum = 0;
|
|
||||||
uint32_t sds_val_count = 0;
|
|
||||||
uint32_t sds_pm10_max = 0;
|
|
||||||
uint32_t sds_pm10_min = 20000;
|
|
||||||
uint32_t sds_pm25_max = 0;
|
|
||||||
uint32_t sds_pm25_min = 20000;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
pms_data_read = k_fifo_get(&fifo_pms, K_MSEC(READINGTIME_SDS_MS));
|
|
||||||
if(pms_data_read != NULL)
|
|
||||||
{
|
|
||||||
if(getTs() < (ts_start_measure + (READINGTIME_SDS_MS/1000)))
|
|
||||||
{
|
|
||||||
//printk("Parse PMS %d %d\n", ts_start_measure, getTs());
|
|
||||||
uint32_t pm10_serial = 0;
|
|
||||||
uint32_t pm25_serial = 0;
|
|
||||||
int checksum_is = pms_data_read->data[2] + pms_data_read->data[3] + pms_data_read->data[4] + pms_data_read->data[5] + pms_data_read->data[6] + pms_data_read->data[7];
|
|
||||||
if(pms_data_read->data[8] == (checksum_is % 256) && pms_data_read->data[0] == 170 && pms_data_read->data[1] == 192 && pms_data_read->data[9] == 171)
|
|
||||||
{
|
|
||||||
|
|
||||||
pm25_serial = pms_data_read->data[2] | pms_data_read->data[3] << 8;
|
|
||||||
pm10_serial = pms_data_read->data[4] | pms_data_read->data[5] << 8;
|
|
||||||
sds_pm10_sum += pm10_serial;
|
|
||||||
sds_pm25_sum += pm25_serial;
|
|
||||||
UPDATE_MIN_MAX(sds_pm10_min, sds_pm10_max, pm10_serial)
|
|
||||||
UPDATE_MIN_MAX(sds_pm25_min, sds_pm25_max, pm25_serial)
|
|
||||||
|
|
||||||
sds_val_count += 1;
|
|
||||||
|
|
||||||
|
|
||||||
printk("p10: %d p25: %d\n", pm10_serial, pm25_serial);
|
|
||||||
}
|
|
||||||
k_free(pms_data_read);
|
|
||||||
} else {
|
|
||||||
send_uart_cmd(SDS_SLEEPCMD);
|
|
||||||
pms_enable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (sds_val_count > 2) {
|
|
||||||
sds_pm10_sum = sds_pm10_sum - sds_pm10_min - sds_pm10_max;
|
|
||||||
sds_pm25_sum = sds_pm25_sum - sds_pm25_min - sds_pm25_max;
|
|
||||||
sds_val_count = sds_val_count - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sds_val_count > 0) {
|
|
||||||
|
|
||||||
struct bthome_adv_t bthome_adv;
|
struct bthome_adv_t bthome_adv;
|
||||||
bthome_adv.type = PM25;
|
bthome_adv.type = PM25;
|
||||||
bthome_adv.data_u16 = sds_pm25_sum / (sds_val_count * 10);
|
bthome_adv.data_u16 = sds011_ReadPM25();
|
||||||
size_t size = sizeof(struct bthome_adv_t);
|
size_t size = sizeof(struct bthome_adv_t);
|
||||||
char *mem_ptr = k_malloc(size);
|
char *mem_ptr = k_malloc(size);
|
||||||
memcpy(mem_ptr, &bthome_adv, size);
|
memcpy(mem_ptr, &bthome_adv, size);
|
||||||
k_fifo_put(&fifo_adv_data, mem_ptr);
|
k_fifo_put(&fifo_adv_data, mem_ptr);
|
||||||
printk("PM25: %d\n",bthome_adv.data_u16);
|
printk("PM25: %d\n",bthome_adv.data_u16);
|
||||||
bthome_adv.type = PM10;
|
bthome_adv.type = PM10;
|
||||||
bthome_adv.data_u16 = sds_pm10_sum / (sds_val_count * 10);
|
bthome_adv.data_u16 = sds011_ReadPM10();
|
||||||
char *mem_ptr2 = k_malloc(size);
|
char *mem_ptr2 = k_malloc(size);
|
||||||
memcpy(mem_ptr2, &bthome_adv, size);
|
memcpy(mem_ptr2, &bthome_adv, size);
|
||||||
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
||||||
printk("PM10: %d\n",bthome_adv.data_u16);
|
printk("PM10: %d\n",bthome_adv.data_u16);
|
||||||
|
k_sem_give(&adv_send_ok);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
K_WORK_DEFINE(work_pms, work_pms_handler);
|
K_WORK_DEFINE(work_pms, work_pms_handler);
|
||||||
|
|
||||||
void serial_cb(const struct device *dev, void *user_data)
|
|
||||||
|
void timer_pms_handler(struct k_timer *stm)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
k_work_submit_to_queue(&workqueue_pms, &work_pms);
|
||||||
|
|
||||||
if (!uart_irq_update(uart_dev)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!uart_irq_rx_ready(uart_dev)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read until FIFO empty */
|
|
||||||
while (uart_fifo_read(uart_dev, &c, 1) == 1) {
|
|
||||||
if(pms_enable == true && pms_warming == false)
|
|
||||||
{
|
|
||||||
//printk("UART char received: 0x%x\n", c);
|
|
||||||
if(c == 0xaa) { pm_measure_position = 0; pms_data.ts = getTs(); }
|
|
||||||
if(pm_measure_position >= 0) {
|
|
||||||
pms_data.data[pm_measure_position] = c;
|
|
||||||
pm_measure_position = pm_measure_position + 1;
|
|
||||||
}
|
|
||||||
if(pm_measure_position == 10) {
|
|
||||||
size_t size = sizeof(struct pms_data_t);
|
|
||||||
char *mem_ptr = k_malloc(size);
|
|
||||||
memcpy(mem_ptr, &pms_data, size);
|
|
||||||
k_fifo_put(&fifo_pms, mem_ptr);
|
|
||||||
}
|
|
||||||
//} else if(pms_enable == false) {
|
|
||||||
// send_uart_cmd(SDS_SLEEPCMD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
K_TIMER_DEFINE(timer_pms, timer_pms_handler, NULL);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
@ -446,6 +507,15 @@ struct bthome_adv_t {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// bt_passkey_set(192847);
|
// bt_passkey_set(192847);
|
||||||
|
mfg_bthome_data[0]=0xd2;
|
||||||
|
mfg_bthome_data[1]=0xfc;
|
||||||
|
mfg_bthome_data[2]=0x40;
|
||||||
|
mfg_bthome_sizetosend=3;
|
||||||
|
|
||||||
|
for(int i = 0; i < BTHOME_MAXELT; i++)
|
||||||
|
{
|
||||||
|
bthome_datapos[i] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
err = bt_enable(NULL);
|
err = bt_enable(NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -453,7 +523,6 @@ struct bthome_adv_t {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_sem_give(&ble_init_ok);
|
|
||||||
|
|
||||||
const struct device *dev = DEVICE_DT_GET(GPIO_PORT);
|
const struct device *dev = DEVICE_DT_GET(GPIO_PORT);
|
||||||
|
|
||||||
|
@ -462,26 +531,59 @@ struct bthome_adv_t {
|
||||||
//bt_conn_auth_cb_register(&auth_cb);
|
//bt_conn_auth_cb_register(&auth_cb);
|
||||||
//static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
|
//static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
|
||||||
|
|
||||||
if (!device_is_ready(uart_dev)) {
|
|
||||||
printk("UART device not found!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
|
k_work_queue_init(&workqueue_i2c);
|
||||||
|
k_work_queue_start(&workqueue_i2c, stack_wq_i2c, K_THREAD_STACK_SIZEOF(stack_wq_i2c), PRIORITY, NULL);
|
||||||
|
k_work_queue_init(&workqueue_pms);
|
||||||
|
k_work_queue_start(&workqueue_pms, stack_wq_pms, K_THREAD_STACK_SIZEOF(stack_wq_pms), PRIORITY, NULL);
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
if (ret == -ENOTSUP) {
|
if(sht4x_setup() == 0) {
|
||||||
printk("Interrupt-driven UART API support not enabled\n");
|
printk("SHT4x enabled\n");
|
||||||
} else if (ret == -ENOSYS) {
|
k_work_submit_to_queue(&workqueue_i2c, &work_temperature);
|
||||||
printk("UART device does not support interrupt-driven API\n");
|
k_timer_start(&timer_temperature, K_SECONDS(300), K_SECONDS(300));
|
||||||
|
eltenabled[TEMPERATURE] = 1;
|
||||||
|
eltenabled[HUMIDITY] = 1;
|
||||||
} else {
|
} else {
|
||||||
printk("Error setting UART callback: %d\n", ret);
|
printk("SHT4x disabled\n");
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uart_irq_rx_enable(uart_dev);
|
|
||||||
|
|
||||||
for(;;)
|
k_msleep(50);
|
||||||
|
|
||||||
|
if(bmp180_setup() == 0) {
|
||||||
|
printk("BMP180 enabled\n");
|
||||||
|
k_work_submit_to_queue(&workqueue_i2c, &work_pressure);
|
||||||
|
k_timer_start(&timer_pressure, K_SECONDS(1800), K_SECONDS(1800));
|
||||||
|
eltenabled[PRESSURE] = 1;
|
||||||
|
} else {
|
||||||
|
printk("BMP180 disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
k_msleep(50);
|
||||||
|
if(sds011_setup() == 0) {
|
||||||
|
printk("SDS011 enabled\n");
|
||||||
|
k_work_submit_to_queue(&workqueue_pms, &work_pms);
|
||||||
|
eltenabled[PM10] = 1;
|
||||||
|
eltenabled[PM25] = 1;
|
||||||
|
k_timer_start(&timer_pms, K_SECONDS(1800), K_SECONDS(1800));
|
||||||
|
} else {
|
||||||
|
printk("SDS011 disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
k_msleep(50);
|
||||||
|
k_work_submit(&work_battery);
|
||||||
|
k_timer_start(&timer_battery, K_SECONDS(3600), K_SECONDS(3600));
|
||||||
|
eltenabled[BATTERY] = 1;
|
||||||
|
eltenabled[VOLTAGE] = 1;
|
||||||
|
eltenabled[BATTERYVDD] = 1;
|
||||||
|
eltenabled[VOLTAGEVDD] = 1;
|
||||||
|
|
||||||
|
mfg_bthome_build();
|
||||||
|
|
||||||
|
k_sem_give(&ble_init_ok);
|
||||||
|
/* for(;;)
|
||||||
{
|
{
|
||||||
if(findiftoprobe(BATTERY, true) < 5)
|
if(findiftoprobe(BATTERY, true) < 5)
|
||||||
{
|
{
|
||||||
|
@ -497,7 +599,7 @@ struct bthome_adv_t {
|
||||||
}
|
}
|
||||||
k_msleep(1000*findsmallestwait());
|
k_msleep(1000*findsmallestwait());
|
||||||
|
|
||||||
}
|
} */
|
||||||
|
|
||||||
/*int len = 0;
|
/*int len = 0;
|
||||||
int pm10_serial = 0;
|
int pm10_serial = 0;
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
#include <sys/_stdint.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/uart.h>
|
||||||
|
|
||||||
|
#include "sds011.h"
|
||||||
|
|
||||||
|
extern struct k_fifo fifo_adv_data;
|
||||||
|
|
||||||
|
#define UPDATE_MIN(MIN, SAMPLE) if (SAMPLE < MIN) { MIN = SAMPLE; }
|
||||||
|
#define UPDATE_MAX(MAX, SAMPLE) if (SAMPLE > MAX) { MAX = SAMPLE; }
|
||||||
|
#define UPDATE_MIN_MAX(MIN, MAX, SAMPLE) { UPDATE_MIN(MIN, SAMPLE); UPDATE_MAX(MAX, SAMPLE); }
|
||||||
|
|
||||||
|
#define UART_PORT DT_NODELABEL(uart0)
|
||||||
|
static const struct device *const uart_dev = DEVICE_DT_GET(UART_PORT);
|
||||||
|
|
||||||
|
uint8_t SDS_SLEEPCMD[19] = {
|
||||||
|
0xAA, 0xB4, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB
|
||||||
|
};
|
||||||
|
uint8_t SDS_WAKEUPCMD[19] = {
|
||||||
|
0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB
|
||||||
|
};
|
||||||
|
static K_FIFO_DEFINE(fifo_pms);
|
||||||
|
struct pms_data_t {
|
||||||
|
void *fifo_reserved;
|
||||||
|
uint32_t ts;
|
||||||
|
char data[10];
|
||||||
|
};
|
||||||
|
//char pm_measure_data[10];
|
||||||
|
struct pms_data_t pms_data;
|
||||||
|
int pm_measure_position = 0;
|
||||||
|
bool pms_enable = false;
|
||||||
|
bool pms_warming = false;
|
||||||
|
#define WARMUPTIME_SDS_MS 15000
|
||||||
|
#define READINGTIME_SDS_MS 5000
|
||||||
|
|
||||||
|
uint16_t sds_pm10;
|
||||||
|
uint16_t sds_pm25;
|
||||||
|
|
||||||
|
bool uart_data_received = false;
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t getTsSDS()
|
||||||
|
{
|
||||||
|
uint32_t ts = (uint32_t) (k_uptime_get()/1000);
|
||||||
|
// LOG_INF("getTs: %d", ts);
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_uart_cmd(uint8_t *buf)
|
||||||
|
{
|
||||||
|
//int msg_len = strlen(buf);
|
||||||
|
printk("Send to uart\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 19; i++) {
|
||||||
|
uart_poll_out(uart_dev, buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void serial_cb(const struct device *dev, void *user_data)
|
||||||
|
{
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
if (!uart_irq_update(uart_dev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uart_irq_rx_ready(uart_dev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read until FIFO empty */
|
||||||
|
while (uart_fifo_read(uart_dev, &c, 1) == 1) {
|
||||||
|
if(c == 0xaa) { uart_data_received = true; }
|
||||||
|
if(pms_enable == true && pms_warming == false)
|
||||||
|
{
|
||||||
|
//printk("UART char received: 0x%x\n", c);
|
||||||
|
if(c == 0xaa) { pm_measure_position = 0; pms_data.ts = getTsSDS(); }
|
||||||
|
if(pm_measure_position >= 0) {
|
||||||
|
pms_data.data[pm_measure_position] = c;
|
||||||
|
pm_measure_position = pm_measure_position + 1;
|
||||||
|
}
|
||||||
|
if(pm_measure_position == 10) {
|
||||||
|
size_t size = sizeof(struct pms_data_t);
|
||||||
|
char *mem_ptr = k_malloc(size);
|
||||||
|
memcpy(mem_ptr, &pms_data, size);
|
||||||
|
k_fifo_put(&fifo_pms, mem_ptr);
|
||||||
|
}
|
||||||
|
//} else if(pms_enable == false) {
|
||||||
|
// send_uart_cmd(SDS_SLEEPCMD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sds011_setup()
|
||||||
|
{
|
||||||
|
if (!device_is_ready(uart_dev)) {
|
||||||
|
printk("UART device not found!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct uart_config uartcfg = { 9600, UART_CFG_PARITY_NONE, UART_CFG_STOP_BITS_1, UART_CFG_DATA_BITS_8, UART_CFG_FLOW_CTRL_NONE };
|
||||||
|
|
||||||
|
int ret = uart_configure(uart_dev, &uartcfg);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Error in comfiguring UART\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == -ENOTSUP) {
|
||||||
|
printk("Interrupt-driven UART API support not enabled\n");
|
||||||
|
} else if (ret == -ENOSYS) {
|
||||||
|
printk("UART device does not support interrupt-driven API\n");
|
||||||
|
} else {
|
||||||
|
printk("Error setting UART callback: %d\n", ret);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uart_irq_rx_enable(uart_dev);
|
||||||
|
|
||||||
|
send_uart_cmd(SDS_WAKEUPCMD);
|
||||||
|
k_msleep(2000);
|
||||||
|
if(uart_data_received == true) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int sds011_probe()
|
||||||
|
{
|
||||||
|
uint32_t ts_start_measure;
|
||||||
|
send_uart_cmd(SDS_WAKEUPCMD);
|
||||||
|
pms_warming = true;
|
||||||
|
pms_enable = true;
|
||||||
|
k_msleep(WARMUPTIME_SDS_MS);
|
||||||
|
pms_warming = false;
|
||||||
|
ts_start_measure = getTsSDS();
|
||||||
|
|
||||||
|
struct pms_data_t *pms_data_read;
|
||||||
|
|
||||||
|
uint32_t sds_pm10_sum = 0;
|
||||||
|
uint32_t sds_pm25_sum = 0;
|
||||||
|
uint32_t sds_val_count = 0;
|
||||||
|
uint32_t sds_pm10_max = 0;
|
||||||
|
uint32_t sds_pm10_min = 20000;
|
||||||
|
uint32_t sds_pm25_max = 0;
|
||||||
|
uint32_t sds_pm25_min = 20000;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
pms_data_read = k_fifo_get(&fifo_pms, K_MSEC(READINGTIME_SDS_MS));
|
||||||
|
if(pms_data_read != NULL)
|
||||||
|
{
|
||||||
|
if(getTsSDS() < (ts_start_measure + (READINGTIME_SDS_MS/1000)))
|
||||||
|
{
|
||||||
|
//printk("Parse PMS %d %d\n", ts_start_measure, getTsSDS());
|
||||||
|
uint32_t pm10_serial = 0;
|
||||||
|
uint32_t pm25_serial = 0;
|
||||||
|
int checksum_is = pms_data_read->data[2] + pms_data_read->data[3] + pms_data_read->data[4] + pms_data_read->data[5] + pms_data_read->data[6] + pms_data_read->data[7];
|
||||||
|
if(pms_data_read->data[8] == (checksum_is % 256) && pms_data_read->data[0] == 170 && pms_data_read->data[1] == 192 && pms_data_read->data[9] == 171)
|
||||||
|
{
|
||||||
|
|
||||||
|
pm25_serial = pms_data_read->data[2] | pms_data_read->data[3] << 8;
|
||||||
|
pm10_serial = pms_data_read->data[4] | pms_data_read->data[5] << 8;
|
||||||
|
sds_pm10_sum += pm10_serial;
|
||||||
|
sds_pm25_sum += pm25_serial;
|
||||||
|
UPDATE_MIN_MAX(sds_pm10_min, sds_pm10_max, pm10_serial)
|
||||||
|
UPDATE_MIN_MAX(sds_pm25_min, sds_pm25_max, pm25_serial)
|
||||||
|
|
||||||
|
sds_val_count += 1;
|
||||||
|
|
||||||
|
|
||||||
|
printk("p10: %d p25: %d\n", pm10_serial, pm25_serial);
|
||||||
|
}
|
||||||
|
k_free(pms_data_read);
|
||||||
|
} else {
|
||||||
|
send_uart_cmd(SDS_SLEEPCMD);
|
||||||
|
pms_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (sds_val_count > 2) {
|
||||||
|
sds_pm10_sum = sds_pm10_sum - sds_pm10_min - sds_pm10_max;
|
||||||
|
sds_pm25_sum = sds_pm25_sum - sds_pm25_min - sds_pm25_max;
|
||||||
|
sds_val_count = sds_val_count - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sds_val_count > 0) {
|
||||||
|
sds_pm25 = sds_pm25_sum / (sds_val_count * 10);
|
||||||
|
sds_pm10 = sds_pm10_sum / (sds_val_count * 10);
|
||||||
|
|
||||||
|
/* struct bthome_adv_t bthome_adv;
|
||||||
|
bthome_adv.type = PM25;
|
||||||
|
bthome_adv.data_u16 = sds_pm25_sum / (sds_val_count * 10);
|
||||||
|
size_t size = sizeof(struct bthome_adv_t);
|
||||||
|
char *mem_ptr = k_malloc(size);
|
||||||
|
memcpy(mem_ptr, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr);
|
||||||
|
printk("PM25: %d\n",bthome_adv.data_u16);
|
||||||
|
bthome_adv.type = PM10;
|
||||||
|
bthome_adv.data_u16 = sds_pm10_sum / (sds_val_count * 10);
|
||||||
|
char *mem_ptr2 = k_malloc(size);
|
||||||
|
memcpy(mem_ptr2, &bthome_adv, size);
|
||||||
|
k_fifo_put(&fifo_adv_data, mem_ptr2);
|
||||||
|
printk("PM10: %d\n",bthome_adv.data_u16);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sds011_ReadPM25()
|
||||||
|
{
|
||||||
|
return sds_pm25;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sds011_ReadPM10()
|
||||||
|
{
|
||||||
|
return sds_pm10;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
int sds011_setup();
|
||||||
|
int sds011_probe();
|
||||||
|
uint16_t sds011_ReadPM25();
|
||||||
|
uint16_t sds011_ReadPM10();
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(sht4x);
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <zephyr/drivers/sensor/sht4x.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "sht4x.h"
|
||||||
|
|
||||||
|
#if !DT_HAS_COMPAT_STATUS_OKAY(sensirion_sht4x)
|
||||||
|
#error "No sensirion,sht4x compatible node found in the device tree"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const struct device *const sht = DEVICE_DT_GET_ANY(sensirion_sht4x);
|
||||||
|
|
||||||
|
int sht4x_setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!device_is_ready(sht)) {
|
||||||
|
printk("Device %s is not ready.\n", sht->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
int sht4x_probe()
|
||||||
|
{
|
||||||
|
if (sensor_sample_fetch(sht)) {
|
||||||
|
printk("Failed to fetch sample from SHT4X device\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sht4x_ReadTempeature()
|
||||||
|
{
|
||||||
|
struct sensor_value temp;
|
||||||
|
sensor_channel_get(sht, SENSOR_CHAN_AMBIENT_TEMP, &temp);
|
||||||
|
|
||||||
|
|
||||||
|
return sensor_value_to_double(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
double sht4x_ReadHumidity()
|
||||||
|
{
|
||||||
|
struct sensor_value hum;
|
||||||
|
sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum);
|
||||||
|
|
||||||
|
|
||||||
|
return sensor_value_to_double(&hum);
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
int sht4x_setup();
|
||||||
|
int sht4x_probe();
|
||||||
|
double sht4x_ReadTempeature();
|
||||||
|
double sht4x_ReadHumidity();
|
|
@ -1,8 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.20.0)
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
set(BOARD nrf52832_outdoor)
|
set(BOARD nrf52dk_nrf52832)
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(tuxoutdoor)
|
project(tuxoutdoor)
|
||||||
|
|
||||||
FILE(GLOB app_sources src/*.c*)
|
FILE(GLOB app_sources ../src/*.c*)
|
||||||
target_sources(app PRIVATE ${app_sources})
|
target_sources(app PRIVATE ${app_sources})
|
|
@ -0,0 +1,76 @@
|
||||||
|
/ {
|
||||||
|
vbatt {
|
||||||
|
compatible = "voltage-divider";
|
||||||
|
io-channels = <&adc 4>;
|
||||||
|
output-ohms = <4600>;
|
||||||
|
full-ohms = <(4600 + 3230)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc 2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&spi0 {
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
&spi1 {
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
&i2c0 {
|
||||||
|
status = "okay";
|
||||||
|
clock-frequency = <I2C_BITRATE_FAST>;
|
||||||
|
sht4x@44 {
|
||||||
|
status = "okay";
|
||||||
|
compatible = "sensirion,sht4x";
|
||||||
|
reg = <0x44>;
|
||||||
|
repeatability = <2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2c1 {
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
&pinctrl {
|
||||||
|
uart0_default: uart0_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(UART_TX, 0, 19)>,
|
||||||
|
<NRF_PSEL(UART_RX, 0, 18)>,
|
||||||
|
<NRF_PSEL(UART_RTS, 0, 5)>,
|
||||||
|
<NRF_PSEL(UART_CTS, 0, 7)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uart0_sleep: uart0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(UART_TX, 0, 19)>,
|
||||||
|
<NRF_PSEL(UART_RX, 0, 18)>,
|
||||||
|
<NRF_PSEL(UART_RTS, 0, 5)>,
|
||||||
|
<NRF_PSEL(UART_CTS, 0, 7)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c0_default: i2c0_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SDA, 0, 17)>,
|
||||||
|
<NRF_PSEL(TWIM_SCL, 0, 16)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c0_sleep: i2c0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SDA, 0, 17)>,
|
||||||
|
<NRF_PSEL(TWIM_SCL, 0, 16)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
CONFIG_BT=y
|
CONFIG_BT=y
|
||||||
#CONFIG_BT_SMP=y
|
#CONFIG_BT_SMP=y
|
||||||
#CONFIG_BT_SIGNING=y
|
#CONFIG_BT_SIGNING=y
|
||||||
CONFIG_BT_PERIPHERAL=y
|
#CONFIG_BT_PERIPHERAL=y
|
||||||
#CONFIG_BT_PRIVACY=n # Random Address
|
#CONFIG_BT_PRIVACY=n # Random Address
|
||||||
#CONFIG_BT_FIXED_PASSKEY=y
|
#CONFIG_BT_FIXED_PASSKEY=y
|
||||||
CONFIG_BT_DEVICE_NAME="TuxOutdoor"
|
CONFIG_BT_DEVICE_NAME="TuxOutdoor"
|
||||||
|
@ -16,9 +16,13 @@ CONFIG_BT_DEVICE_NAME="TuxOutdoor"
|
||||||
#CONFIG_NVS=y
|
#CONFIG_NVS=y
|
||||||
#CONFIG_SETTINGS=y
|
#CONFIG_SETTINGS=y
|
||||||
|
|
||||||
|
CONFIG_SENSOR=y
|
||||||
|
CONFIG_SHT4X=y
|
||||||
|
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
CONFIG_LOG_DEFAULT_LEVEL=2
|
||||||
CONFIG_LOG_MAX_LEVEL=3
|
CONFIG_LOG_MAX_LEVEL=2
|
||||||
|
CONFIG_LOG_PRINTK=y
|
||||||
CONFIG_USE_SEGGER_RTT=y
|
CONFIG_USE_SEGGER_RTT=y
|
||||||
CONFIG_LOG_BACKEND_RTT=y
|
CONFIG_LOG_BACKEND_RTT=y
|
||||||
CONFIG_UART_CONSOLE=n
|
CONFIG_UART_CONSOLE=n
|
Loading…
Reference in New Issue