Initial commit

main
Nigreon 2023-09-01 03:24:45 +02:00
commit 82c0bcc836
6 changed files with 880 additions and 0 deletions

8
CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.20.0)
set(BOARD nrf52832_outdoor)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(tuxoutdoor)
FILE(GLOB app_sources src/*.c*)
target_sources(app PRIVATE ${app_sources})

View File

@ -0,0 +1,8 @@
/ {
vbatt {
compatible = "voltage-divider";
io-channels = <&adc 4>;
output-ohms = <4600>;
full-ohms = <(4600 + 3230)>;
};
};

37
prj.conf Normal file
View File

@ -0,0 +1,37 @@
CONFIG_BT=y
#CONFIG_BT_SMP=y
#CONFIG_BT_SIGNING=y
CONFIG_BT_PERIPHERAL=y
#CONFIG_BT_PRIVACY=n # Random Address
#CONFIG_BT_FIXED_PASSKEY=y
CONFIG_BT_DEVICE_NAME="TuxOutdoor"
#CONFIG_BT_DEVICE_APPEARANCE=833
#CONFIG_BT_DEVICE_NAME_DYNAMIC=y
#CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
#CONFIG_BT_SETTINGS=y
#CONFIG_FLASH=y
#CONFIG_FLASH_PAGE_LAYOUT=y
#CONFIG_FLASH_MAP=y
#CONFIG_NVS=y
#CONFIG_SETTINGS=y
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_LOG_MAX_LEVEL=3
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_ADC=y
CONFIG_GPIO=y
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_BOARD_ENABLE_DCDC=n
CONFIG_HEAP_MEM_POOL_SIZE=512
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_NANO=y

231
src/battery.c Normal file
View File

@ -0,0 +1,231 @@
/*
* 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(BATTERY, CONFIG_ADC_LOG_LEVEL);
#define VBATT DT_PATH(vbatt)
#define ZEPHYR_USER DT_PATH(zephyr_user)
#ifdef CONFIG_BOARD_THINGY52_NRF52832
/* This board uses a divider that reduces max voltage to
* reference voltage (600 mV).
*/
#define BATTERY_ADC_GAIN ADC_GAIN_1
#else
/* 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
#endif
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 divider_config = {
#if DT_NODE_HAS_STATUS(VBATT, okay)
.io_channel = {
DT_IO_CHANNELS_INPUT(VBATT),
},
.power_gpios = GPIO_DT_SPEC_GET_OR(VBATT, power_gpios, {}),
.output_ohm = DT_PROP(VBATT, output_ohms),
.full_ohm = DT_PROP(VBATT, full_ohms),
#else /* /vbatt exists */
.io_channel = {
DT_IO_CHANNELS_INPUT(ZEPHYR_USER),
},
#endif /* /vbatt exists */
};
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 divider_data = {
#if DT_NODE_HAS_STATUS(VBATT, okay)
.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(VBATT)),
#else
.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(ZEPHYR_USER)),
#endif
};
static int divider_setup(void)
{
const struct divider_config *cfg = &divider_config;
const struct io_channel_config *iocp = &cfg->io_channel;
const struct gpio_dt_spec *gcp = &cfg->power_gpios;
struct divider_data *ddp = &divider_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),
};
if (cfg->output_ohm != 0) {
accp->input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0
+ iocp->channel;
} else {
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 AIN%u got %d", iocp->channel, rc);
return rc;
}
static bool battery_ok;
static int battery_setup(const struct device *arg)
{
int rc = divider_setup();
battery_ok = (rc == 0);
LOG_INF("Battery setup: %d %d", rc, battery_ok);
return rc;
}
SYS_INIT(battery_setup, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
int battery_measure_enable(bool enable)
{
int rc = -ENOENT;
if (battery_ok) {
const struct gpio_dt_spec *gcp = &divider_config.power_gpios;
rc = 0;
if (gcp->port) {
rc = gpio_pin_set_dt(gcp, enable);
}
}
return rc;
}
int16_t battery_sample(void)
{
int16_t rc = -ENOENT;
if (battery_ok) {
struct divider_data *ddp = &divider_data;
const struct divider_config *dcp = &divider_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);
if (dcp->output_ohm != 0) {
rc = val * (uint64_t)dcp->full_ohm
/ dcp->output_ohm;
LOG_INF("raw %u ~ %u mV => %d mV\n",
ddp->raw, val, rc);
} else {
rc = val;
LOG_INF("raw %u ~ %u mV\n", ddp->raw, val);
}
}
}
return rc;
}
uint16_t battery_level_pptt(uint16_t batt_mV,
const struct battery_level_point *curve)
{
const struct battery_level_point *pb = curve;
if (batt_mV >= pb->lvl_mV) {
/* Measured voltage above highest point, cap at maximum. */
return pb->lvl_pptt;
}
/* Go down to the last point at or below the measured voltage. */
while ((pb->lvl_pptt > 0)
&& (batt_mV < pb->lvl_mV)) {
++pb;
}
if (batt_mV < pb->lvl_mV) {
/* Below lowest point, cap at minimum */
return pb->lvl_pptt;
}
/* Linear interpolation between below and above points. */
const struct battery_level_point *pa = pb - 1;
return pb->lvl_pptt
+ ((pa->lvl_pptt - pb->lvl_pptt)
* (batt_mV - pb->lvl_mV)
/ (pa->lvl_mV - pb->lvl_mV));
}

53
src/battery.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2019 Peter Bigot Consulting, LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef APPLICATION_BATTERY_H_
#define APPLICATION_BATTERY_H_
/** Enable or disable measurement of the battery voltage.
*
* @param enable true to enable, false to disable
*
* @return zero on success, or a negative error code.
*/
int battery_measure_enable(bool enable);
/** Measure the battery voltage.
*
* @return the battery voltage in millivolts, or a negative error
* code.
*/
int16_t battery_sample(void);
/** A point in a battery discharge curve sequence.
*
* A discharge curve is defined as a sequence of these points, where
* the first point has #lvl_pptt set to 10000 and the last point has
* #lvl_pptt set to zero. Both #lvl_pptt and #lvl_mV should be
* monotonic decreasing within the sequence.
*/
struct battery_level_point {
/** Remaining life at #lvl_mV. */
uint16_t lvl_pptt;
/** Battery voltage at #lvl_pptt remaining life. */
uint16_t lvl_mV;
};
/** Calculate the estimated battery level based on a measured voltage.
*
* @param batt_mV a measured battery voltage level.
*
* @param curve the discharge curve for the type of battery installed
* on the system.
*
* @return the estimated remaining capacity in parts per ten
* thousand.
*/
uint16_t battery_level_pptt(uint16_t batt_mV,
const struct battery_level_point *curve);
#endif /* APPLICATION_BATTERY_H_ */

543
src/main.c Normal file
View File

@ -0,0 +1,543 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/errno.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/uart.h>
#include <math.h>
#include "battery.h"
#include "hal/nrf_gpiote.h"
static K_SEM_DEFINE(ble_init_ok, 0, 1);
static K_FIFO_DEFINE(fifo_adv_data);
struct bthome_adv_t {
void *fifo_reserved;
uint8_t type;
int16_t data_s16;
uint16_t data_u16;
uint8_t data_u8;
};
#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;
uint16_t wait;
};
struct captor_wait params[] = { {BATTERY, 120 }, {TEMPERATURE, 60}, {PM25, 60} };
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),
};
#define GPIO_PORT DT_NODELABEL(gpio0)
#define STACKSIZE 2048
#define PRIORITY 7
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
* 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.
*/
{ 10000, 3950 },
{ 625, 3550 },
{ 0, 3100 },
};
#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];
};
//#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
/* static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed (err 0x%02x)\n", err);
} else {
printk("Connected\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected (reason 0x%02x)\n", reason);
}*/
uint32_t getTs()
{
uint32_t ts = (k_uptime_get_32()/1000);
// LOG_INF("getTs: %d", ts);
return ts;
}
uint16_t findsmallestwait()
{
uint16_t minval = UINT16_MAX;
uint32_t ts = getTs();
for(int i = 0; i < sizeof(params) / sizeof(params[0]); i++)
{
if(params[i].wait != 0) {
//LOG_INF("%s %d", params[i].captor[j].captor, params[i].captor[j].wait);
uint32_t wait = (uint32_t)params[i].wait;
if((uint16_t)(wait-(ts % wait)) < minval) { minval = (uint16_t)(wait-(ts % wait)); }
}
}
return minval;
}
uint16_t findiftoprobe(enum captor_type captorp, bool record)
{
uint32_t ts = getTs();
//LOG_INF("findiftoprobe: %s", captorp);
for(int i = 0; i < sizeof(params) / sizeof(params[0]); i++)
{
if(captorp == params[i].captor) {
return (uint16_t)(ts % (uint32_t)params[i].wait);
}
}
return UINT16_MAX;
}
static void bt_ready(void)
{
int err;
printk("Bluetooth initialized\n");
/*if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}*/
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
printk("Advertising successfully started\n");
}
/* static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Passkey for %s: %06u\n", addr, passkey);
}
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing cancelled: %s\n", addr);
}
static struct bt_conn_auth_cb auth_cb = {
.passkey_display = auth_passkey_display,
.passkey_entry = NULL,
.cancel = auth_cancel,
};*/
bool test_bthome_data_set()
{
for(int i = 0; i < sizeof(bthome_datapos); i++)
{
if(mfg_bthome_data[bthome_datapos[i]] == 0x00)
{
//printk("BTHome POS %d empty\n", bthome_datapos[i]);
return false;
}
}
return true;
}
void publish_adv_thread()
{
bool adv_activate = false;
k_sem_take(&ble_init_ok, K_FOREVER);
for (;;) {
struct bthome_adv_t *request = k_fifo_get(&fifo_adv_data, K_FOREVER);
if(request->type == VOLTAGE)
{
mfg_bthome_data[10] = request->data_u16 >> 8;
mfg_bthome_data[9] = request->data_u16;
} else if(request->type == BATTERY)
{
mfg_bthome_data[4] = request->data_u8;
} else if(request->type == TEMPERATURE)
{
mfg_bthome_data[7] = request->data_s16 >> 8;
mfg_bthome_data[6] = request->data_s16;
} else if(request->type == PM25)
{
mfg_bthome_data[13] = request->data_u16 >> 8;
mfg_bthome_data[12] = request->data_u16;
} else if(request->type == PM10)
{
mfg_bthome_data[16] = request->data_u16 >> 8;
mfg_bthome_data[15] = request->data_u16;
}
if(test_bthome_data_set() == true)
{
if(adv_activate == false)
{
bt_ready();
adv_activate = true;
} else {
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);
char *mem_ptr = k_malloc(size);
memcpy(mem_ptr, &bthome_adv, size);
k_fifo_put(&fifo_adv_data, mem_ptr);
bthome_adv.type = BATTERY;
bthome_adv.data_u8 = round(battery_level_pptt(bthome_adv.data_u16, battery_levels)/100);
char *mem_ptr2 = k_malloc(size);
memcpy(mem_ptr2, &bthome_adv, size);
k_fifo_put(&fifo_adv_data, mem_ptr2);
printk("Battery: %d mV (%d%%)\n",bthome_adv.data_u16, bthome_adv.data_u8);
}
K_WORK_DEFINE(work_battery, work_battery_handler);
static void work_temperature_handler(struct k_work *work)
{
struct bthome_adv_t bthome_adv;
bthome_adv.type = TEMPERATURE;
bthome_adv.data_s16 = 2512;
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);
}
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 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]);
}
}
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;
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);
}
}
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);
}
}
}
int main(void)
{
printk("Hello, It's TuxOutdooor\n");
int err;
// bt_passkey_set(192847);
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return 0;
}
k_sem_give(&ble_init_ok);
const struct device *dev = DEVICE_DT_GET(GPIO_PORT);
gpio_pin_configure(dev, 20, GPIO_OUTPUT);
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);
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 (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);
for(;;)
{
if(findiftoprobe(BATTERY, true) < 5)
{
k_work_submit(&work_battery);
}
if(findiftoprobe(TEMPERATURE, true) < 5)
{
k_work_submit(&work_temperature);
}
if(findiftoprobe(PM25, true) < 5)
{
k_work_submit(&work_pms);
}
k_msleep(1000*findsmallestwait());
}
/*int len = 0;
int pm10_serial = 0;
int pm25_serial = 0;
int checksum_is;
int checksum_ok = 0;
int error = 1;
float p10 = 0.0;
float p25 = 0.0;
for(;;) {
char value;
if(uart_poll_in(uart_dev, &value) == 0)
{
printk("UART char received: 0x%x\n", value);
printk("len %d\n", len);
switch (len) {
case (0): if (value != 170) { len = -1; }; break;
case (1): if (value != 192) { len = -1; }; break;
case (2): pm25_serial = value; checksum_is = value; break;
case (3): pm25_serial += (value << 8); checksum_is += value; break;
case (4): pm10_serial = value; checksum_is += value; break;
case (5): pm10_serial += (value << 8); checksum_is += value; break;
case (6): checksum_is += value; break;
case (7): checksum_is += value; break;
case (8): if (value == (checksum_is % 256)) { checksum_ok = 1; } else { len = -1; }; break;
case (9): if (value != 171) { len = -1; }; break;
}
len++;
if (len == 10 && checksum_ok == 1) {
p10 = (float)pm10_serial/10.0;
p25 = (float)pm25_serial/10.0;
len = 0; checksum_ok = 0; pm10_serial = 0.0; pm25_serial = 0.0; checksum_is = 0;
error = 0;
printk("p10: %f p25: %f\n", p10, p25);
}
} else {
//printk("No UART Data\n");
k_msleep(100);
}
}*/
return 0;
}