Refactor in files. Add BMP180 and SHT4x sensor, monitor VDD voltage, scheduling with timer
This commit is contained in:
		
							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 int battery_setup(const struct device *arg)
 | 
			
		||||
int battery_setup()
 | 
			
		||||
{
 | 
			
		||||
	int rc = divider_setup();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +151,7 @@ static int battery_setup(const struct device *arg)
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,12 +15,17 @@
 | 
			
		|||
 */
 | 
			
		||||
int battery_measure_enable(bool enable);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int battery_setup();
 | 
			
		||||
int batteryvdd_setup();
 | 
			
		||||
 | 
			
		||||
/** Measure the battery voltage.
 | 
			
		||||
 *
 | 
			
		||||
 * @return the battery voltage in millivolts, or a negative error
 | 
			
		||||
 * code.
 | 
			
		||||
 */
 | 
			
		||||
int16_t battery_sample(void);
 | 
			
		||||
int16_t batteryvdd_sample(void);
 | 
			
		||||
 | 
			
		||||
/** 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();
 | 
			
		||||
							
								
								
									
										496
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										496
									
								
								src/main.c
								
								
								
								
							| 
						 | 
				
			
			@ -27,39 +27,45 @@
 | 
			
		|||
#include <zephyr/devicetree.h>
 | 
			
		||||
#include <zephyr/drivers/sensor.h>
 | 
			
		||||
#include <zephyr/drivers/gpio.h>
 | 
			
		||||
#include <zephyr/drivers/uart.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include <zephyr/logging/log.h>
 | 
			
		||||
LOG_MODULE_REGISTER(main);
 | 
			
		||||
 | 
			
		||||
#include "battery.h"
 | 
			
		||||
#include "sht4x.h"
 | 
			
		||||
#include "bmp180.h"
 | 
			
		||||
#include "sds011.h"
 | 
			
		||||
#include "hal/nrf_gpiote.h"
 | 
			
		||||
 | 
			
		||||
static K_SEM_DEFINE(ble_init_ok, 0, 1);
 | 
			
		||||
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 {
 | 
			
		||||
    void *fifo_reserved;
 | 
			
		||||
    uint8_t type;
 | 
			
		||||
    int16_t data_s16;
 | 
			
		||||
    uint16_t data_u16;
 | 
			
		||||
    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 {
 | 
			
		||||
        enum captor_type captor;
 | 
			
		||||
| 
						 | 
				
			
			@ -69,16 +75,22 @@ struct bthome_adv_t {
 | 
			
		|||
    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(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 STACKSIZE 2048
 | 
			
		||||
#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[] = {
 | 
			
		||||
        /* "Curve" here eyeballed from captured data for the [Adafruit
 | 
			
		||||
         * 3.7v 2000 mAh](https://www.adafruit.com/product/2011) LIPO
 | 
			
		||||
| 
						 | 
				
			
			@ -96,24 +108,27 @@ struct bthome_adv_t {
 | 
			
		|||
        { 625, 3550 },
 | 
			
		||||
        { 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)
 | 
			
		||||
    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
 | 
			
		||||
        { 10000, 2800 },
 | 
			
		||||
        { 90, 2600 },
 | 
			
		||||
        { 50, 2440 },
 | 
			
		||||
        { 0, 2300 },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -131,14 +146,14 @@ struct bthome_adv_t {
 | 
			
		|||
       printk("Disconnected (reason 0x%02x)\n", reason);
 | 
			
		||||
       }*/
 | 
			
		||||
 | 
			
		||||
    uint32_t getTs()
 | 
			
		||||
    {
 | 
			
		||||
  /*  uint32_t getTs()
 | 
			
		||||
    {e
 | 
			
		||||
        uint32_t ts = (k_uptime_get_32()/1000);
 | 
			
		||||
        // LOG_INF("getTs: %d", ts);
 | 
			
		||||
        return ts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t findsmallestwait()
 | 
			
		||||
   uint16_t findsmallestwait()
 | 
			
		||||
    {
 | 
			
		||||
        uint16_t minval = UINT16_MAX;
 | 
			
		||||
        uint32_t ts = getTs();
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +181,7 @@ struct bthome_adv_t {
 | 
			
		|||
        return UINT16_MAX;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
            printk("Advertising failed to start (err %d)\n", err);
 | 
			
		||||
            return;
 | 
			
		||||
| 
						 | 
				
			
			@ -212,7 +231,7 @@ struct bthome_adv_t {
 | 
			
		|||
       .cancel = auth_cancel,
 | 
			
		||||
       };*/
 | 
			
		||||
 | 
			
		||||
    bool test_bthome_data_set()
 | 
			
		||||
    /*bool test_bthome_data_set()
 | 
			
		||||
    {
 | 
			
		||||
        for(int i = 0; i < sizeof(bthome_datapos); i++)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -223,59 +242,154 @@ struct bthome_adv_t {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
        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()
 | 
			
		||||
    {
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
            {
 | 
			
		||||
                mfg_bthome_data[10] = request->data_u16 >> 8;
 | 
			
		||||
                mfg_bthome_data[9] = request->data_u16;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[VOLTAGE]+2] = request->data_u16 >> 8;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[VOLTAGE]+1] = request->data_u16;
 | 
			
		||||
            } 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)
 | 
			
		||||
            {
 | 
			
		||||
                mfg_bthome_data[7] = request->data_s16 >> 8;
 | 
			
		||||
                mfg_bthome_data[6] = request->data_s16;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[TEMPERATURE]+2] = request->data_s16 >> 8;
 | 
			
		||||
                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)
 | 
			
		||||
            {
 | 
			
		||||
                mfg_bthome_data[13] = request->data_u16 >> 8;
 | 
			
		||||
                mfg_bthome_data[12] = request->data_u16;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[PM25]+2] = request->data_u16 >> 8;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[PM25]+1] = request->data_u16;
 | 
			
		||||
            } else if(request->type == PM10)
 | 
			
		||||
            {
 | 
			
		||||
                mfg_bthome_data[16] = request->data_u16 >> 8;
 | 
			
		||||
                mfg_bthome_data[15] = request->data_u16;
 | 
			
		||||
                mfg_bthome_data[bthome_datapos[PM10]+2] = request->data_u16 >> 8;
 | 
			
		||||
                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)
 | 
			
		||||
                {
 | 
			
		||||
                    bt_ready();
 | 
			
		||||
                    adv_activate = true;
 | 
			
		||||
                } 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);
 | 
			
		||||
                    printk("Update ADV\n");
 | 
			
		||||
                    //k_msleep(50);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            k_free(request);
 | 
			
		||||
        }
 | 
			
		||||
  }
 | 
			
		||||
    }
 | 
			
		||||
    K_THREAD_DEFINE(publish_adv_thread_id, STACKSIZE, publish_adv_thread, NULL, NULL, NULL, PRIORITY, 0, 0);
 | 
			
		||||
 | 
			
		||||
    static void work_battery_handler(struct k_work *work)
 | 
			
		||||
    {
 | 
			
		||||
        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);
 | 
			
		||||
        bthome_adv.type = VOLTAGE;
 | 
			
		||||
        battery_setup();
 | 
			
		||||
        bthome_adv.data_u16 = (uint16_t) battery_sample();
 | 
			
		||||
        char *mem_ptr = k_malloc(size);
 | 
			
		||||
        memcpy(mem_ptr, &bthome_adv, size);
 | 
			
		||||
        k_fifo_put(&fifo_adv_data, mem_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -285,167 +399,123 @@ struct bthome_adv_t {
 | 
			
		|||
        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("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);
 | 
			
		||||
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)
 | 
			
		||||
    {
 | 
			
		||||
        struct bthome_adv_t bthome_adv;
 | 
			
		||||
        sht4x_probe();
 | 
			
		||||
        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);
 | 
			
		||||
        char *mem_ptr = k_malloc(size);
 | 
			
		||||
        memcpy(mem_ptr, &bthome_adv, size);
 | 
			
		||||
        k_fifo_put(&fifo_adv_data, mem_ptr);
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
    //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
 | 
			
		||||
void timer_temperature_handler(struct k_timer *stm)
 | 
			
		||||
{
 | 
			
		||||
    k_work_submit_to_queue(&workqueue_i2c, &work_temperature);
 | 
			
		||||
}
 | 
			
		||||
    K_TIMER_DEFINE(timer_temperature, timer_temperature_handler, NULL);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void send_uart_cmd(uint8_t *buf)
 | 
			
		||||
static void work_pressure_handler(struct k_work *work)
 | 
			
		||||
    {
 | 
			
		||||
        //int msg_len = strlen(buf);
 | 
			
		||||
        printk("Send to uart\n");
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 19; i++) {
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
    static void work_pms_handler(struct k_work *work)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
    {
 | 
			
		||||
        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 = 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;
 | 
			
		||||
  sds011_probe();
 | 
			
		||||
        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);
 | 
			
		||||
            bthome_adv.data_u16 = sds011_ReadPM25();
 | 
			
		||||
    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);
 | 
			
		||||
            bthome_adv.data_u16 = sds011_ReadPM10();
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        k_sem_give(&adv_send_ok);
 | 
			
		||||
}
 | 
			
		||||
    K_WORK_DEFINE(work_pms, work_pms_handler);
 | 
			
		||||
 | 
			
		||||
    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(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);
 | 
			
		||||
        } 
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
void timer_pms_handler(struct k_timer *stm)
 | 
			
		||||
{
 | 
			
		||||
    k_work_submit_to_queue(&workqueue_pms, &work_pms);
 | 
			
		||||
}
 | 
			
		||||
    K_TIMER_DEFINE(timer_pms, timer_pms_handler, NULL);
 | 
			
		||||
   
 | 
			
		||||
    int main(void)
 | 
			
		||||
    {
 | 
			
		||||
        printk("Hello, It's TuxOutdooor\n");
 | 
			
		||||
        int err;
 | 
			
		||||
 | 
			
		||||
        //     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);
 | 
			
		||||
        if (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -453,7 +523,6 @@ struct bthome_adv_t {
 | 
			
		|||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        k_sem_give(&ble_init_ok);
 | 
			
		||||
 | 
			
		||||
        const struct device *dev = DEVICE_DT_GET(GPIO_PORT);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -461,27 +530,60 @@ struct bthome_adv_t {
 | 
			
		|||
        gpio_pin_set(dev, 20, 0);
 | 
			
		||||
        //bt_conn_auth_cb_register(&auth_cb);
 | 
			
		||||
        //static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
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 (!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);
 | 
			
		||||
  if(sht4x_setup() == 0) { 
 | 
			
		||||
    printk("SHT4x enabled\n");
 | 
			
		||||
    k_work_submit_to_queue(&workqueue_i2c, &work_temperature);
 | 
			
		||||
    k_timer_start(&timer_temperature, K_SECONDS(300), K_SECONDS(300));
 | 
			
		||||
  eltenabled[TEMPERATURE] = 1;
 | 
			
		||||
  eltenabled[HUMIDITY] = 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    printk("SHT4x disabled\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
        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 0;
 | 
			
		||||
        }
 | 
			
		||||
        uart_irq_rx_enable(uart_dev);
 | 
			
		||||
  k_msleep(50);
 | 
			
		||||
 | 
			
		||||
        for(;;)
 | 
			
		||||
  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)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -497,7 +599,7 @@ struct bthome_adv_t {
 | 
			
		|||
            }
 | 
			
		||||
            k_msleep(1000*findsmallestwait());
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        } */
 | 
			
		||||
 | 
			
		||||
        /*int len = 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)
 | 
			
		||||
set(BOARD nrf52832_outdoor)
 | 
			
		||||
set(BOARD nrf52dk_nrf52832)
 | 
			
		||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
 | 
			
		||||
 | 
			
		||||
project(tuxoutdoor)
 | 
			
		||||
 | 
			
		||||
FILE(GLOB app_sources src/*.c*)
 | 
			
		||||
FILE(GLOB app_sources ../src/*.c*)
 | 
			
		||||
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_SMP=y
 | 
			
		||||
#CONFIG_BT_SIGNING=y
 | 
			
		||||
CONFIG_BT_PERIPHERAL=y
 | 
			
		||||
#CONFIG_BT_PERIPHERAL=y
 | 
			
		||||
#CONFIG_BT_PRIVACY=n # Random Address
 | 
			
		||||
#CONFIG_BT_FIXED_PASSKEY=y
 | 
			
		||||
CONFIG_BT_DEVICE_NAME="TuxOutdoor"
 | 
			
		||||
| 
						 | 
				
			
			@ -16,9 +16,13 @@ CONFIG_BT_DEVICE_NAME="TuxOutdoor"
 | 
			
		|||
#CONFIG_NVS=y
 | 
			
		||||
#CONFIG_SETTINGS=y
 | 
			
		||||
 | 
			
		||||
CONFIG_SENSOR=y
 | 
			
		||||
CONFIG_SHT4X=y
 | 
			
		||||
 | 
			
		||||
CONFIG_LOG=y
 | 
			
		||||
CONFIG_LOG_DEFAULT_LEVEL=3
 | 
			
		||||
CONFIG_LOG_MAX_LEVEL=3
 | 
			
		||||
CONFIG_LOG_DEFAULT_LEVEL=2
 | 
			
		||||
CONFIG_LOG_MAX_LEVEL=2
 | 
			
		||||
CONFIG_LOG_PRINTK=y
 | 
			
		||||
CONFIG_USE_SEGGER_RTT=y
 | 
			
		||||
CONFIG_LOG_BACKEND_RTT=y
 | 
			
		||||
CONFIG_UART_CONSOLE=n
 | 
			
		||||
		Loading…
	
		Reference in New Issue