CODE
COMPONENT ARCHITECTURE
- driver
- node_acc_adxl367
- include
- node_acc_adxl367.h
- node_acc_adxl367_test.h
- node_acc_adxl367.c
- node_acc_adxl367_test.c
- CMakeLists.txt
- readme.txt
driver/node_acc_adxl355/CMakeLists.txt
set(src_dirs
.
)
set(include_dirs
include
)
set(requires
node_i2c
freertos
log
esp_driver_gpio
)
idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
node_acc_adxl367.h
/**
* @file node_acc_adxl367.h
* @brief ADXL367 (I2C): init, range/ODR, modes, XYZ/temp, FIFO, INT map, activity/inactivity.
*
* I2C via driver/node_i2c. Registers: driver/ref-adxl367. Tests/integration: node_acc_adxl367_test.h.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "driver/i2c_master.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Default 7-bit I2C address when ASEL is high (see datasheet). */
#define NODE_ACC_ADXL367_I2C_ADDR_0X53 0x53u
/** Alternate 7-bit I2C address when ASEL is low. */
#define NODE_ACC_ADXL367_I2C_ADDR_0X1D 0x1Du
/** Measurement range (FILTER_CTL[7:6]). */
typedef enum {
NODE_ACC_ADXL367_RANGE_2G = 0u,
NODE_ACC_ADXL367_RANGE_4G = 1u,
NODE_ACC_ADXL367_RANGE_8G = 2u,
} node_acc_adxl367_range_t;
/** Output data rate (FILTER_CTL[2:0]). Matches ADXL367 ODR encoding. */
typedef enum {
NODE_ACC_ADXL367_ODR_12_5_HZ = 0u,
NODE_ACC_ADXL367_ODR_25_HZ = 1u,
NODE_ACC_ADXL367_ODR_50_HZ = 2u,
NODE_ACC_ADXL367_ODR_100_HZ = 3u,
NODE_ACC_ADXL367_ODR_200_HZ = 4u,
NODE_ACC_ADXL367_ODR_400_HZ = 5u,
} node_acc_adxl367_odr_t;
/** Power/measurement mode (POWER_CTL[1:0]). */
typedef enum {
NODE_ACC_ADXL367_MODE_STANDBY = 0u,
NODE_ACC_ADXL367_MODE_MEASURE = 2u,
} node_acc_adxl367_mode_t;
/**
* Temperature / ADC channel selection (TEMP_CTL / ADC_CTL).
* adxl367_adc_read_en() in ref clears TEMP when toggling ADC; we only mask ADC_CTL for ADC_EN
* so TEMP_ONLY does not use that helper verbatim.
*/
typedef enum {
/** Accel only. */
NODE_ACC_ADXL367_MEAS_ACCEL_ONLY = 0u,
/** Temp only (API). */
NODE_ACC_ADXL367_MEAS_TEMP_ONLY,
/** Accel + temp. */
NODE_ACC_ADXL367_MEAS_ACCEL_AND_TEMP,
} node_acc_adxl367_meas_mode_t;
/** FIFO mode (FIFO_CONTROL[1:0]). See adxl367_set_fifo_mode. */
typedef enum {
NODE_ACC_ADXL367_FIFO_DISABLED = 0u,
NODE_ACC_ADXL367_FIFO_OLDEST_SAVED = 1u,
NODE_ACC_ADXL367_FIFO_STREAM = 2u,
NODE_ACC_ADXL367_FIFO_TRIGGERED = 3u,
} node_acc_adxl367_fifo_mode_t;
/** FIFO channel / format (FIFO_CONTROL[6:3]). See adxl367_set_fifo_format. */
typedef enum {
NODE_ACC_ADXL367_FIFO_FMT_XYZ = 0u,
NODE_ACC_ADXL367_FIFO_FMT_X = 1u,
NODE_ACC_ADXL367_FIFO_FMT_Y = 2u,
NODE_ACC_ADXL367_FIFO_FMT_Z = 3u,
NODE_ACC_ADXL367_FIFO_FMT_XYZT = 4u,
} node_acc_adxl367_fifo_format_t;
/**
* Device instance. @c i2c from @c i2c_add_device() after @c i2c_bus_init().
*/
typedef struct node_acc_adxl367_dev {
i2c_master_dev_handle_t i2c;
node_acc_adxl367_range_t range;
node_acc_adxl367_odr_t odr;
node_acc_adxl367_mode_t mode;
node_acc_adxl367_meas_mode_t meas_mode;
node_acc_adxl367_fifo_mode_t fifo_mode;
node_acc_adxl367_fifo_format_t fifo_format;
} node_acc_adxl367_dev_t;
/** INTMAP bits; layout matches ref adxl367_int_map. */
typedef struct node_acc_adxl367_int_map {
uint8_t err_fuse;
uint8_t err_user_regs;
uint8_t kpalv_timer;
uint8_t temp_adc_hi;
uint8_t temp_adc_low;
uint8_t tap_two;
uint8_t tap_one;
uint8_t int_low;
uint8_t awake;
uint8_t inact;
uint8_t act;
uint8_t fifo_overrun;
uint8_t fifo_watermark;
uint8_t fifo_ready;
uint8_t data_ready;
} node_acc_adxl367_int_map_t;
/** ACT_INACT_CTL ref mode: ABS fixed vs REL referenced baseline (ref adxl367_setup_activity_detection). */
typedef enum {
NODE_ACC_ADXL367_AI_REF_ABS = 0u,
NODE_ACC_ADXL367_AI_REF_REL = 1u,
} node_acc_adxl367_ai_ref_t;
/** STATUS (0x0B). */
#define NODE_ACC_ADXL367_STATUS_DATA_RDY (1u << 0)
#define NODE_ACC_ADXL367_STATUS_FIFO_RDY (1u << 1)
#define NODE_ACC_ADXL367_STATUS_FIFO_WATERMARK (1u << 2)
#define NODE_ACC_ADXL367_STATUS_FIFO_OVERRUN (1u << 3)
#define NODE_ACC_ADXL367_STATUS_ACT (1u << 4)
#define NODE_ACC_ADXL367_STATUS_INACT (1u << 5)
#define NODE_ACC_ADXL367_STATUS_AWAKE (1u << 6)
/** g to THRESH_ACT LSB at +/-2g scale intent (~4000 LSB/g, ref path). */
#define NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G(g) ((uint16_t)((float)(g) * 4000.0f))
/**
* @brief Soft-reset, probe, default 2g / 100 Hz, measure mode, then @c NODE_ACC_ADXL367_MEAS_ACCEL_ONLY.
*/
esp_err_t node_acc_adxl367_init(node_acc_adxl367_dev_t *dev);
esp_err_t node_acc_adxl367_soft_reset(node_acc_adxl367_dev_t *dev);
esp_err_t node_acc_adxl367_probe(node_acc_adxl367_dev_t *dev);
esp_err_t node_acc_adxl367_set_range(node_acc_adxl367_dev_t *dev, node_acc_adxl367_range_t range);
esp_err_t node_acc_adxl367_set_odr(node_acc_adxl367_dev_t *dev, node_acc_adxl367_odr_t odr);
esp_err_t node_acc_adxl367_set_mode(node_acc_adxl367_dev_t *dev, node_acc_adxl367_mode_t mode);
/**
* @brief Configure TEMP_CTL / ADC_CTL per mode. Stays in current power mode (typically measure).
*/
esp_err_t node_acc_adxl367_set_measurement_mode(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_meas_mode_t mode);
/** Raw XYZ; ESP_ERR_INVALID_STATE in MEAS_TEMP_ONLY. Same as ref adxl367_get_raw_xyz (DATA_RDY, XDATA_H). */
esp_err_t node_acc_adxl367_read_xyz_raw(node_acc_adxl367_dev_t *dev, int16_t *x, int16_t *y, int16_t *z);
/**
* @brief Raw temperature (14-bit sign-extended). Requires TEMP_EN; not allowed in @c NODE_ACC_ADXL367_MEAS_ACCEL_ONLY.
*/
esp_err_t node_acc_adxl367_read_temp_raw(node_acc_adxl367_dev_t *dev, int16_t *raw);
/** Celsius using ref-adxl367 adxl367_temp_conv coefficients. */
esp_err_t node_acc_adxl367_read_temp_celsius(node_acc_adxl367_dev_t *dev, float *celsius);
/** Read STATUS register (0x0B). */
esp_err_t node_acc_adxl367_read_status(node_acc_adxl367_dev_t *dev, uint8_t *status);
/**
* @brief Route interrupt sources to INT1 or INT2 (INTMAP1 / INTMAP2). See @c adxl367_int_map.
* @param int_pin 1 = INT1, 2 = INT2.
*/
esp_err_t node_acc_adxl367_int_map(node_acc_adxl367_dev_t *dev, uint8_t int_pin,
const node_acc_adxl367_int_map_t *map);
/** Activity: ref adxl367_setup_activity_detection. threshold 13-bit; time_act_samples at ODR. */
esp_err_t node_acc_adxl367_setup_activity_detection(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_ai_ref_t ref_mode,
uint16_t threshold,
uint8_t time_act_samples);
/** Inactivity: ref adxl367_setup_inactivity_detection. */
esp_err_t node_acc_adxl367_setup_inactivity_detection(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_ai_ref_t ref_mode,
uint16_t threshold,
uint16_t time_inact_samples);
/** Clear ACT/INACT enables (ACT_INACT_CTL[3:0]). */
esp_err_t node_acc_adxl367_act_inact_disable(node_acc_adxl367_dev_t *dev);
/** AXIS_MASK bits [2:0]: set bit disables axis. */
esp_err_t node_acc_adxl367_set_activity_axes_enabled(node_acc_adxl367_dev_t *dev, bool enable_x,
bool enable_y, bool enable_z);
/** ACT_INACT_CTL LINKLOOP 0-3 (datasheet). */
esp_err_t node_acc_adxl367_set_act_inact_linkloop(node_acc_adxl367_dev_t *dev, uint8_t linkloop_mode_0_to_3);
/**
* @brief FIFO setup: mode, format, watermark sample-sets count, 14-bit+CH ID read mode (adxl367_fifo_setup).
* @param sample_sets_nb Watermark in sample sets (e.g. 3 entries per set for XYZ).
*/
esp_err_t node_acc_adxl367_fifo_setup(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_fifo_mode_t mode,
node_acc_adxl367_fifo_format_t format,
uint16_t sample_sets_nb);
esp_err_t node_acc_adxl367_fifo_disable(node_acc_adxl367_dev_t *dev);
/** FIFO entry count (10-bit), ref adxl367_get_nb_of_fifo_entries. */
esp_err_t node_acc_adxl367_fifo_get_entry_count(node_acc_adxl367_dev_t *dev, uint16_t *count);
/**
* @brief Read and parse FIFO for @c NODE_ACC_ADXL367_FIFO_FMT_XYZ (14b+CH ID).
* Fills up to @p max_triplets complete XYZ samples; @p out_triplets may be less if FIFO is partial.
*/
esp_err_t node_acc_adxl367_fifo_drain_xyz(node_acc_adxl367_dev_t *dev, int16_t *x, int16_t *y, int16_t *z,
size_t max_triplets, size_t *out_triplets);
#ifdef __cplusplus
}
#endif
node_acc_adxl367.c
/**
* @file node_acc_adxl367.c
* @brief ADXL367 I2C driver (ref-adxl367/adxl367.c). Tests: node_acc_adxl367_test.h.
*/
#include "node_acc_adxl367.h"
#include <stddef.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "node_i2c.h"
static const char *TAG = "node_acc_adxl367";
/* Register map (subset) */
#define REG_DEVID_AD 0x00u
#define REG_DEVID_MST 0x01u
#define REG_PARTID 0x02u
#define REG_REVID 0x03u
#define REG_STATUS 0x0Bu
#define REG_XDATA_H 0x0Eu
#define REG_SOFT_RESET 0x1Fu
#define REG_FILTER_CTL 0x2Cu
#define REG_POWER_CTL 0x2Du
#define REG_TEMP_H 0x14u
#define REG_ADC_CTL 0x3Cu
#define REG_TEMP_CTL 0x3Du
#define REG_FIFO_ENTRIES_L 0x0Cu
#define REG_FIFO_ENTRIES_H 0x0Du
#define REG_FIFO_CONTROL 0x28u
#define REG_FIFO_SAMPLES 0x29u
#define REG_I2C_FIFO_DATA 0x18u
#define REG_INTMAP1_LWR 0x2Au
#define REG_INTMAP2_LWR 0x2Bu
#define REG_INTMAP1_UPPER 0x3Au
#define REG_INTMAP2_UPPER 0x3Bu
#define REG_THRESH_ACT_H 0x20u
#define REG_THRESH_ACT_L 0x21u
#define REG_TIME_ACT 0x22u
#define REG_THRESH_INACT_H 0x23u
#define REG_THRESH_INACT_L 0x24u
#define REG_TIME_INACT_H 0x25u
#define REG_TIME_INACT_L 0x26u
#define REG_ACT_INACT_CTL 0x27u
#define REG_AXIS_MASK 0x43u
#define INTMAP_UPPER_MASK 0xDFu
#define THRESH_H_MASK 0x7Fu
#define THRESH_L_MASK 0xFCu
#define ACT_EN_MSK 0x03u
#define INACT_EN_MSK 0x0Cu
#define LINKLOOP_MSK (0x3u << 4)
#define AXIS_MASK_ACT_BLOCK_MASK 0x07u
#define DEVID_AD_VAL 0xADu
#define DEVID_MST_VAL 0x1Du
#define PARTID_VAL 0xF7u
#define REVID_ADXL367 0x03u
#define RESET_KEY 0x52u
#define STATUS_DATA_RDY (1u << 0)
#define FILTER_CTL_RANGE_MASK 0xC0u
#define FILTER_CTL_ODR_MASK 0x07u
#define POWER_CTL_MEASURE_MASK 0x03u
#define ADC_EN_MASK (1u << 0)
#define TEMP_EN_MASK (1u << 0)
#define FIFO_CTL_MODE_MASK 0x03u
#define FIFO_CTL_CH_MASK 0x78u
#define FIFO_CTL_SAMPLES_BIT (1u << 2)
#define ADC_CTL_FIFO_RD_MODE_MASK 0xC0u
#define FIFO_RD_14B_CHID 3u
#define STATUS_FIFO_RDY (1u << 1)
#define STATUS_FIFO_WATERMARK (1u << 2)
#define STATUS_FIFO_OVERRUN (1u << 3)
#define FIFO_MAX_READ_BYTES 512u
/** adxl367_temp_conv in ref-adxl367/adxl367.c */
#define TEMP_OFFSET 1185
#define TEMP_SCALE_NUM 18518518LL
#define TEMP_SCALE_DEN 1000000000LL
#define I2C_TIMEOUT_MS 1000
/* Low-level helpers: node_i2c only (see node_i2c.h). */
static esp_err_t reg_write(node_acc_adxl367_dev_t *dev, uint8_t reg, uint8_t val)
{
uint8_t buf[2] = {reg, val};
return i2c_write_data(dev->i2c, buf, sizeof(buf), I2C_TIMEOUT_MS);
}
static esp_err_t reg_read(node_acc_adxl367_dev_t *dev, uint8_t reg, uint8_t *data, size_t len)
{
if (len == 0 || data == NULL) {
return ESP_ERR_INVALID_ARG;
}
return i2c_write_read_data(dev->i2c, ®, 1, data, len, I2C_TIMEOUT_MS);
}
static esp_err_t reg_update_mask(node_acc_adxl367_dev_t *dev, uint8_t reg, uint8_t mask, uint8_t set_bits)
{
uint8_t v = 0;
esp_err_t err = reg_read(dev, reg, &v, 1);
if (err != ESP_OK) {
return err;
}
v = (uint8_t)((v & (uint8_t)~mask) | (set_bits & mask));
return reg_write(dev, reg, v);
}
/** 14-bit pack: ref adxl367_get_raw_xyz. */
static int16_t pack_14bit_xy(uint8_t hi, uint8_t lo)
{
int16_t v = (int16_t)(((int16_t)hi << 6) | (int16_t)(lo >> 2));
if (v & (int16_t)(1 << 13)) {
v |= (int16_t)(3 << 14);
}
return v;
}
static esp_err_t adc_en_set_only(node_acc_adxl367_dev_t *dev, bool enable)
{
return reg_update_mask(dev, REG_ADC_CTL, ADC_EN_MASK, enable ? ADC_EN_MASK : 0u);
}
static esp_err_t temp_en_set(node_acc_adxl367_dev_t *dev, bool enable)
{
return reg_update_mask(dev, REG_TEMP_CTL, TEMP_EN_MASK, enable ? TEMP_EN_MASK : 0u);
}
/** Poll STATUS until DATA_RDY (ref @c adxl367_get_raw_xyz uses an unbounded while; we cap for RTOS). */
static esp_err_t wait_data_rdy(node_acc_adxl367_dev_t *dev)
{
const int max_poll = 200;
for (int i = 0; i < max_poll; i++) {
uint8_t st = 0;
esp_err_t err = reg_read(dev, REG_STATUS, &st, 1);
if (err != ESP_OK) {
return err;
}
if (st & STATUS_DATA_RDY) {
return ESP_OK;
}
vTaskDelay(pdMS_TO_TICKS(1));
}
return ESP_ERR_TIMEOUT;
}
esp_err_t node_acc_adxl367_set_measurement_mode(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_meas_mode_t mode)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (mode > NODE_ACC_ADXL367_MEAS_ACCEL_AND_TEMP) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = adc_en_set_only(dev, false);
if (err != ESP_OK) {
return err;
}
switch (mode) {
case NODE_ACC_ADXL367_MEAS_ACCEL_ONLY:
err = temp_en_set(dev, false);
break;
case NODE_ACC_ADXL367_MEAS_TEMP_ONLY:
err = temp_en_set(dev, true);
break;
case NODE_ACC_ADXL367_MEAS_ACCEL_AND_TEMP:
err = temp_en_set(dev, true);
break;
default:
return ESP_ERR_INVALID_ARG;
}
if (err != ESP_OK) {
return err;
}
dev->meas_mode = mode;
return ESP_OK;
}
esp_err_t node_acc_adxl367_read_temp_raw(node_acc_adxl367_dev_t *dev, int16_t *raw)
{
if (dev == NULL || raw == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (dev->meas_mode == NODE_ACC_ADXL367_MEAS_ACCEL_ONLY) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = wait_data_rdy(dev);
if (err != ESP_OK) {
return err;
}
uint8_t t[2];
err = reg_read(dev, REG_TEMP_H, t, sizeof(t));
if (err != ESP_OK) {
return err;
}
*raw = pack_14bit_xy(t[0], t[1]);
return ESP_OK;
}
esp_err_t node_acc_adxl367_read_temp_celsius(node_acc_adxl367_dev_t *dev, float *celsius)
{
if (dev == NULL || celsius == NULL) {
return ESP_ERR_INVALID_ARG;
}
int16_t raw = 0;
esp_err_t err = node_acc_adxl367_read_temp_raw(dev, &raw);
if (err != ESP_OK) {
return err;
}
int64_t v = (int64_t)raw + (int64_t)TEMP_OFFSET;
v = v * TEMP_SCALE_NUM;
*celsius = (float)v / (float)TEMP_SCALE_DEN;
return ESP_OK;
}
esp_err_t node_acc_adxl367_soft_reset(node_acc_adxl367_dev_t *dev)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = reg_write(dev, REG_SOFT_RESET, RESET_KEY);
if (err != ESP_OK) {
return err;
}
vTaskDelay(pdMS_TO_TICKS(20));
dev->range = NODE_ACC_ADXL367_RANGE_2G;
dev->odr = NODE_ACC_ADXL367_ODR_100_HZ;
dev->mode = NODE_ACC_ADXL367_MODE_STANDBY;
dev->meas_mode = NODE_ACC_ADXL367_MEAS_ACCEL_ONLY;
dev->fifo_mode = NODE_ACC_ADXL367_FIFO_DISABLED;
dev->fifo_format = NODE_ACC_ADXL367_FIFO_FMT_XYZ;
return ESP_OK;
}
static int16_t pack_fifo_14b_chid(uint8_t hi, uint8_t lo)
{
int16_t v = (int16_t)(((int16_t)(hi & 0x3Fu) << 8) | lo);
if (v & (int16_t)(1 << 13)) {
v |= (int16_t)(3 << 14);
}
return v;
}
static esp_err_t fifo_set_sample_sets_nb(node_acc_adxl367_dev_t *dev, uint16_t sets_nb)
{
esp_err_t err = reg_update_mask(dev, REG_FIFO_CONTROL, FIFO_CTL_SAMPLES_BIT,
(sets_nb & (1u << 9)) ? FIFO_CTL_SAMPLES_BIT : 0u);
if (err != ESP_OK) {
return err;
}
return reg_write(dev, REG_FIFO_SAMPLES, (uint8_t)(sets_nb & 0xFFu));
}
static esp_err_t fifo_read_payload(node_acc_adxl367_dev_t *dev, uint8_t *data, size_t len)
{
uint8_t reg = REG_I2C_FIFO_DATA;
return i2c_write_read_data(dev->i2c, ®, 1, data, len, I2C_TIMEOUT_MS);
}
esp_err_t node_acc_adxl367_read_status(node_acc_adxl367_dev_t *dev, uint8_t *status)
{
if (dev == NULL || status == NULL) {
return ESP_ERR_INVALID_ARG;
}
return reg_read(dev, REG_STATUS, status, 1);
}
static uint8_t intmap_bit(uint8_t v)
{
return (uint8_t)(v & 1u);
}
esp_err_t node_acc_adxl367_int_map(node_acc_adxl367_dev_t *dev, uint8_t int_pin,
const node_acc_adxl367_int_map_t *map)
{
if (dev == NULL || map == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (int_pin != 1u && int_pin != 2u) {
return ESP_ERR_INVALID_ARG;
}
uint8_t upper = (uint8_t)((intmap_bit(map->err_fuse) << 7) | (intmap_bit(map->err_user_regs) << 6) |
(intmap_bit(map->kpalv_timer) << 4) | (intmap_bit(map->temp_adc_hi) << 3) |
(intmap_bit(map->temp_adc_low) << 2) | (intmap_bit(map->tap_two) << 1) |
intmap_bit(map->tap_one));
uint8_t lower = (uint8_t)((intmap_bit(map->int_low) << 7) | (intmap_bit(map->awake) << 6) |
(intmap_bit(map->inact) << 5) | (intmap_bit(map->act) << 4) |
(intmap_bit(map->fifo_overrun) << 3) | (intmap_bit(map->fifo_watermark) << 2) |
(intmap_bit(map->fifo_ready) << 1) | intmap_bit(map->data_ready));
uint8_t reg_upper = (int_pin == 1u) ? REG_INTMAP1_UPPER : REG_INTMAP2_UPPER;
uint8_t reg_lower = (int_pin == 1u) ? REG_INTMAP1_LWR : REG_INTMAP2_LWR;
esp_err_t err = reg_update_mask(dev, reg_upper, INTMAP_UPPER_MASK, upper);
if (err != ESP_OK) {
return err;
}
return reg_write(dev, reg_lower, lower);
}
esp_err_t node_acc_adxl367_act_inact_disable(node_acc_adxl367_dev_t *dev)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
return reg_update_mask(dev, REG_ACT_INACT_CTL, ACT_EN_MSK | INACT_EN_MSK, 0u);
}
esp_err_t node_acc_adxl367_set_activity_axes_enabled(node_acc_adxl367_dev_t *dev, bool enable_x,
bool enable_y, bool enable_z)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (!enable_x && !enable_y && !enable_z) {
return ESP_ERR_INVALID_ARG;
}
uint8_t block = 0u;
if (!enable_x) {
block |= (1u << 0);
}
if (!enable_y) {
block |= (1u << 1);
}
if (!enable_z) {
block |= (1u << 2);
}
return reg_update_mask(dev, REG_AXIS_MASK, AXIS_MASK_ACT_BLOCK_MASK, block);
}
esp_err_t node_acc_adxl367_set_act_inact_linkloop(node_acc_adxl367_dev_t *dev, uint8_t linkloop_mode_0_to_3)
{
if (dev == NULL || linkloop_mode_0_to_3 > 3u) {
return ESP_ERR_INVALID_ARG;
}
return reg_update_mask(dev, REG_ACT_INACT_CTL, LINKLOOP_MSK, (uint8_t)(linkloop_mode_0_to_3 << 4));
}
/* Register writes follow driver/ref-adxl367/adxl367.c adxl367_setup_activity_detection(). */
esp_err_t node_acc_adxl367_setup_activity_detection(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_ai_ref_t ref_mode,
uint16_t threshold,
uint8_t time_act_samples)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (threshold > 0x1FFFu || ref_mode > NODE_ACC_ADXL367_AI_REF_REL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t act_val = (ref_mode == NODE_ACC_ADXL367_AI_REF_ABS) ? 1u : 3u;
esp_err_t err = reg_update_mask(dev, REG_ACT_INACT_CTL, ACT_EN_MSK, act_val);
if (err != ESP_OK) {
return err;
}
err = reg_update_mask(dev, REG_THRESH_ACT_H, THRESH_H_MASK, (uint8_t)(threshold >> 6));
if (err != ESP_OK) {
return err;
}
err = reg_update_mask(dev, REG_THRESH_ACT_L, THRESH_L_MASK, (uint8_t)((threshold & 0x3Fu) << 2));
if (err != ESP_OK) {
return err;
}
return reg_write(dev, REG_TIME_ACT, time_act_samples);
}
/* Register writes follow driver/ref-adxl367/adxl367.c adxl367_setup_inactivity_detection(). */
esp_err_t node_acc_adxl367_setup_inactivity_detection(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_ai_ref_t ref_mode,
uint16_t threshold,
uint16_t time_inact_samples)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (threshold > 0x1FFFu || ref_mode > NODE_ACC_ADXL367_AI_REF_REL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t inact_val = (ref_mode == NODE_ACC_ADXL367_AI_REF_ABS) ? 1u : 3u;
esp_err_t err = reg_update_mask(dev, REG_ACT_INACT_CTL, INACT_EN_MSK, (uint8_t)(inact_val << 2));
if (err != ESP_OK) {
return err;
}
err = reg_update_mask(dev, REG_THRESH_INACT_H, THRESH_H_MASK, (uint8_t)(threshold >> 6));
if (err != ESP_OK) {
return err;
}
err = reg_update_mask(dev, REG_THRESH_INACT_L, THRESH_L_MASK, (uint8_t)((threshold & 0x3Fu) << 2));
if (err != ESP_OK) {
return err;
}
err = reg_write(dev, REG_TIME_INACT_H, (uint8_t)(time_inact_samples >> 8));
if (err != ESP_OK) {
return err;
}
return reg_write(dev, REG_TIME_INACT_L, (uint8_t)(time_inact_samples & 0xFFu));
}
esp_err_t node_acc_adxl367_fifo_setup(node_acc_adxl367_dev_t *dev,
node_acc_adxl367_fifo_mode_t mode,
node_acc_adxl367_fifo_format_t format,
uint16_t sample_sets_nb)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (mode > NODE_ACC_ADXL367_FIFO_TRIGGERED || format > NODE_ACC_ADXL367_FIFO_FMT_XYZT) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = reg_update_mask(dev, REG_FIFO_CONTROL, FIFO_CTL_MODE_MASK, (uint8_t)mode);
if (err != ESP_OK) {
return err;
}
err = reg_update_mask(dev, REG_FIFO_CONTROL, FIFO_CTL_CH_MASK, (uint8_t)((uint8_t)format << 3));
if (err != ESP_OK) {
return err;
}
err = fifo_set_sample_sets_nb(dev, sample_sets_nb);
if (err != ESP_OK) {
return err;
}
/* adxl367_set_fifo_read_mode: ADXL367_14B_CHID -> ADC_CTL[7:6] = 3 */
err = reg_update_mask(dev, REG_ADC_CTL, ADC_CTL_FIFO_RD_MODE_MASK, FIFO_RD_14B_CHID << 6);
if (err != ESP_OK) {
return err;
}
dev->fifo_mode = mode;
dev->fifo_format = format;
return ESP_OK;
}
esp_err_t node_acc_adxl367_fifo_disable(node_acc_adxl367_dev_t *dev)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = reg_update_mask(dev, REG_FIFO_CONTROL, FIFO_CTL_MODE_MASK, 0u);
if (err == ESP_OK) {
dev->fifo_mode = NODE_ACC_ADXL367_FIFO_DISABLED;
}
return err;
}
esp_err_t node_acc_adxl367_fifo_get_entry_count(node_acc_adxl367_dev_t *dev, uint16_t *count)
{
if (dev == NULL || count == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t v[2];
esp_err_t err = reg_read(dev, REG_FIFO_ENTRIES_L, v, sizeof(v));
if (err != ESP_OK) {
return err;
}
*count = (uint16_t)(((uint16_t)(v[1] & 0x03u) << 8) | v[0]);
return ESP_OK;
}
esp_err_t node_acc_adxl367_fifo_drain_xyz(node_acc_adxl367_dev_t *dev, int16_t *x, int16_t *y, int16_t *z,
size_t max_triplets, size_t *out_triplets)
{
if (dev == NULL || x == NULL || y == NULL || z == NULL || out_triplets == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (dev->fifo_format != NODE_ACC_ADXL367_FIFO_FMT_XYZ) {
return ESP_ERR_INVALID_STATE;
}
uint16_t n_ent = 0;
esp_err_t err = node_acc_adxl367_fifo_get_entry_count(dev, &n_ent);
if (err != ESP_OK) {
return err;
}
if (n_ent == 0) {
*out_triplets = 0;
return ESP_OK;
}
size_t n_bytes = (size_t)n_ent * 2u;
if (n_bytes > FIFO_MAX_READ_BYTES) {
n_bytes = FIFO_MAX_READ_BYTES;
}
uint8_t buf[FIFO_MAX_READ_BYTES];
err = fifo_read_payload(dev, buf, n_bytes);
if (err != ESP_OK) {
return err;
}
int16_t *px = x;
int16_t *py = y;
int16_t *pz = z;
size_t nt = 0;
for (size_t i = 0; i + 1 < n_bytes && nt < max_triplets; i += 2) {
uint8_t ch = (uint8_t)(buf[i] >> 6);
int16_t val = pack_fifo_14b_chid(buf[i], buf[i + 1]);
switch (ch) {
case 0u:
if ((size_t)(px - x) >= max_triplets) {
return ESP_ERR_NO_MEM;
}
*px++ = val;
break;
case 1u:
if ((size_t)(py - y) >= max_triplets) {
return ESP_ERR_NO_MEM;
}
*py++ = val;
break;
case 2u:
if ((size_t)(pz - z) >= max_triplets) {
return ESP_ERR_NO_MEM;
}
*pz++ = val;
nt++;
break;
default:
ESP_LOGE(TAG, "FIFO bad channel id %u", (unsigned)ch);
return ESP_ERR_INVALID_RESPONSE;
}
}
*out_triplets = nt;
return ESP_OK;
}
esp_err_t node_acc_adxl367_probe(node_acc_adxl367_dev_t *dev)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t v = 0;
esp_err_t err = reg_read(dev, REG_DEVID_AD, &v, 1);
if (err != ESP_OK) {
return err;
}
if (v != DEVID_AD_VAL) {
ESP_LOGE(TAG, "DEVID_AD mismatch: got 0x%02X expect 0x%02X", v, DEVID_AD_VAL);
return ESP_ERR_NOT_FOUND;
}
err = reg_read(dev, REG_DEVID_MST, &v, 1);
if (err != ESP_OK) {
return err;
}
if (v != DEVID_MST_VAL) {
ESP_LOGE(TAG, "DEVID_MST mismatch: got 0x%02X expect 0x%02X", v, DEVID_MST_VAL);
return ESP_ERR_NOT_FOUND;
}
err = reg_read(dev, REG_PARTID, &v, 1);
if (err != ESP_OK) {
return err;
}
if (v != PARTID_VAL) {
ESP_LOGE(TAG, "PARTID mismatch: got 0x%02X expect 0x%02X", v, PARTID_VAL);
return ESP_ERR_NOT_FOUND;
}
err = reg_read(dev, REG_REVID, &v, 1);
if (err != ESP_OK) {
return err;
}
if (v != REVID_ADXL367) {
ESP_LOGE(TAG, "REVID mismatch: got 0x%02X expect 0x%02X (ADXL367)", v, REVID_ADXL367);
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
esp_err_t node_acc_adxl367_set_range(node_acc_adxl367_dev_t *dev, node_acc_adxl367_range_t range)
{
if (dev == NULL || range > NODE_ACC_ADXL367_RANGE_8G) {
return ESP_ERR_INVALID_ARG;
}
uint8_t shifted = (uint8_t)((uint8_t)range << 6);
esp_err_t err = reg_update_mask(dev, REG_FILTER_CTL, FILTER_CTL_RANGE_MASK, shifted);
if (err == ESP_OK) {
dev->range = range;
}
return err;
}
esp_err_t node_acc_adxl367_set_odr(node_acc_adxl367_dev_t *dev, node_acc_adxl367_odr_t odr)
{
if (dev == NULL || odr > NODE_ACC_ADXL367_ODR_400_HZ) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = reg_update_mask(dev, REG_FILTER_CTL, FILTER_CTL_ODR_MASK, (uint8_t)odr);
if (err == ESP_OK) {
dev->odr = odr;
}
return err;
}
esp_err_t node_acc_adxl367_set_mode(node_acc_adxl367_dev_t *dev, node_acc_adxl367_mode_t mode)
{
if (dev == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (mode != NODE_ACC_ADXL367_MODE_STANDBY && mode != NODE_ACC_ADXL367_MODE_MEASURE) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err =
reg_update_mask(dev, REG_POWER_CTL, POWER_CTL_MEASURE_MASK, (uint8_t)mode);
if (err != ESP_OK) {
return err;
}
if (mode == NODE_ACC_ADXL367_MODE_MEASURE) {
vTaskDelay(pdMS_TO_TICKS(100));
}
dev->mode = mode;
return ESP_OK;
}
esp_err_t node_acc_adxl367_read_xyz_raw(node_acc_adxl367_dev_t *dev, int16_t *x, int16_t *y, int16_t *z)
{
if (dev == NULL || x == NULL || y == NULL || z == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (dev->meas_mode == NODE_ACC_ADXL367_MEAS_TEMP_ONLY) {
return ESP_ERR_INVALID_STATE;
}
/* Same flow as Analog @c adxl367_get_raw_xyz: wait DATA_RDY, then read 6 bytes from XDATA_H (burst). */
esp_err_t err = wait_data_rdy(dev);
if (err != ESP_OK) {
if (err == ESP_ERR_TIMEOUT) {
ESP_LOGW(TAG, "DATA_RDY timeout");
}
return err;
}
uint8_t b[6];
err = reg_read(dev, REG_XDATA_H, b, sizeof(b));
if (err != ESP_OK) {
return err;
}
*x = pack_14bit_xy(b[0], b[1]);
*y = pack_14bit_xy(b[2], b[3]);
*z = pack_14bit_xy(b[4], b[5]);
return ESP_OK;
}
esp_err_t node_acc_adxl367_init(node_acc_adxl367_dev_t *dev)
{
if (dev == NULL || dev->i2c == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = node_acc_adxl367_soft_reset(dev);
if (err != ESP_OK) {
return err;
}
err = node_acc_adxl367_probe(dev);
if (err != ESP_OK) {
return err;
}
err = node_acc_adxl367_set_range(dev, NODE_ACC_ADXL367_RANGE_2G);
if (err != ESP_OK) {
return err;
}
err = node_acc_adxl367_set_odr(dev, NODE_ACC_ADXL367_ODR_100_HZ);
if (err != ESP_OK) {
return err;
}
err = node_acc_adxl367_set_mode(dev, NODE_ACC_ADXL367_MODE_MEASURE);
if (err != ESP_OK) {
return err;
}
err = node_acc_adxl367_set_measurement_mode(dev, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (err != ESP_OK) {
return err;
}
ESP_LOGI(TAG, "Init OK (2g, 100 Hz, measure, accel-only)");
return ESP_OK;
}
node_acc_adxl367_test.h
/**
* @file node_acc_adxl367_test.h
* @brief Phases 1-5 tests; Phase 6: run_phase6_default_app. Driver: node_acc_adxl367.h.
*/
#pragma once
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t node_acc_adxl367_run_phase1_test(void);
esp_err_t node_acc_adxl367_run_phase2_test(void);
esp_err_t node_acc_adxl367_run_phase3_test(void);
esp_err_t node_acc_adxl367_run_phase4_test(void);
esp_err_t node_acc_adxl367_run_phase5_test(void);
/** Phase 6 default: does not return. Calls transition monitor (UART motion/still lines). */
void node_acc_adxl367_run_phase6_default_app(void);
esp_err_t node_acc_adxl367_run_xyz_stats_capture(void);
/** Software motion/still from max sample delta; does not return. */
void node_acc_adxl367_run_transition_monitor_forever(void);
#ifdef __cplusplus
}
#endif
node_acc_adxl367_test.c
/**
* @file node_acc_adxl367_test.c
* @brief Phases 1-5 tests; Phase 6: run_phase6_default_app.
*/
#include "node_acc_adxl367_test.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "node_acc_adxl367.h"
#include "node_i2c.h"
#include <inttypes.h>
#include <stdint.h>
static const char *TAG = "adxl367_test";
/** ~g from raw accel code (same scale intent as @c NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G). */
#define ADXL367_STATS_CODE_TO_G(c) ((double)(c) / 4000.0)
/** ADXL367 INT1 on this board (DOC: MORE-PERCEPTION/ADXL367). Override if wiring differs. */
#ifndef NODE_ACC_ADXL367_TEST_INT1_GPIO
#define NODE_ACC_ADXL367_TEST_INT1_GPIO 10
#endif
/** ADXL367 INT2 (DOC: MORE-PERCEPTION/ADXL367). */
#ifndef NODE_ACC_ADXL367_TEST_INT2_GPIO
#define NODE_ACC_ADXL367_TEST_INT2_GPIO 18
#endif
/** Phase 5: monitor window (ms) for linked ACT/INACT demo. */
#ifndef NODE_ACC_ADXL367_TEST_P5_WINDOW_MS
#define NODE_ACC_ADXL367_TEST_P5_WINDOW_MS 60000
#endif
#ifndef NODE_ACC_ADXL367_TEST_P5_POLL_MS
#define NODE_ACC_ADXL367_TEST_P5_POLL_MS 50
#endif
/** Delay before gpio_intr_enable(INT2) after config (baseline settle). */
#ifndef NODE_ACC_ADXL367_TEST_P5_ARM_MS
#define NODE_ACC_ADXL367_TEST_P5_ARM_MS 3000
#endif
/** Phase 5 THRESH_ACT scale (g, +/-2g intent). */
#ifndef NODE_ACC_ADXL367_TEST_P5_THRESH_G
#define NODE_ACC_ADXL367_TEST_P5_THRESH_G 0.22f
#endif
/** TIME_ACT sample count at ODR. */
#ifndef NODE_ACC_ADXL367_TEST_P5_TIME_ACT_SAMPLES
#define NODE_ACC_ADXL367_TEST_P5_TIME_ACT_SAMPLES 32u
#endif
/** THRESH_INACT (g) for referenced inactivity. */
#ifndef NODE_ACC_ADXL367_TEST_P5_THRESH_INACT_G
#define NODE_ACC_ADXL367_TEST_P5_THRESH_INACT_G 0.10f
#endif
/** TIME_INACT sample count. */
#ifndef NODE_ACC_ADXL367_TEST_P5_TIME_INACT_SAMPLES
#define NODE_ACC_ADXL367_TEST_P5_TIME_INACT_SAMPLES 250u
#endif
/** ACT_INACT_CTL[5:4]: 3 = linked + internal STATUS ack (see datasheet). */
#ifndef NODE_ACC_ADXL367_TEST_P5_LINKLOOP_MODE
#define NODE_ACC_ADXL367_TEST_P5_LINKLOOP_MODE 3u
#endif
/** Stats capture duration (ms), one sample per DATA_RDY. */
#ifndef NODE_ACC_ADXL367_TEST_STATS_MS
#define NODE_ACC_ADXL367_TEST_STATS_MS 15000
#endif
/** max(|dx|,|dy|,|dz|) between consecutive samples; above: still_to_motion. */
#ifndef NODE_ACC_ADXL367_MONITOR_DELTA_HIGH_LSB
#define NODE_ACC_ADXL367_MONITOR_DELTA_HIGH_LSB 350
#endif
/** Below this for MONITOR_STILL_COUNT samples: motion_to_still. */
#ifndef NODE_ACC_ADXL367_MONITOR_DELTA_LOW_LSB
#define NODE_ACC_ADXL367_MONITOR_DELTA_LOW_LSB 120
#endif
#ifndef NODE_ACC_ADXL367_MONITOR_STILL_COUNT
#define NODE_ACC_ADXL367_MONITOR_STILL_COUNT 45u
#endif
/** Ignore saturated / invalid samples (|code| above this on any axis). */
#ifndef NODE_ACC_ADXL367_MONITOR_ABS_MAX
#define NODE_ACC_ADXL367_MONITOR_ABS_MAX 7800
#endif
static uint32_t adxl367_uabs_diff(int16_t a, int16_t b)
{
int32_t d = (int32_t)a - (int32_t)b;
if (d < 0) {
d = -d;
}
return (uint32_t)d;
}
static uint32_t adxl367_max_u32(uint32_t a, uint32_t b, uint32_t c)
{
uint32_t m = a;
if (b > m) {
m = b;
}
if (c > m) {
m = c;
}
return m;
}
static void IRAM_ATTR p4_fifo_int_isr(void *arg)
{
SemaphoreHandle_t sem = (SemaphoreHandle_t)arg;
if (sem != NULL) {
(void)xSemaphoreGiveFromISR(sem, NULL);
}
}
static void IRAM_ATTR p5_act_int_isr(void *arg)
{
SemaphoreHandle_t sem = (SemaphoreHandle_t)arg;
if (sem != NULL) {
(void)xSemaphoreGiveFromISR(sem, NULL);
}
}
static esp_err_t probe_i2c_and_init(node_acc_adxl367_dev_t *acc, i2c_master_dev_handle_t *out_dev)
{
static const uint8_t k_addrs[] = {
NODE_ACC_ADXL367_I2C_ADDR_0X1D,
NODE_ACC_ADXL367_I2C_ADDR_0X53,
};
esp_err_t ret = ESP_ERR_NOT_FOUND;
*out_dev = NULL;
for (size_t a = 0; a < sizeof(k_addrs) / sizeof(k_addrs[0]); a++) {
uint8_t addr = k_addrs[a];
ret = i2c_add_device(addr, I2C_MASTER_FREQ_HZ, out_dev);
if (ret != ESP_OK) {
continue;
}
acc->i2c = *out_dev;
ret = node_acc_adxl367_init(acc);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "ADXL367 at I2C 0x%02X", (unsigned)addr);
return ESP_OK;
}
ESP_LOGD(TAG, "no chip at 0x%02X: %s", (unsigned)addr, esp_err_to_name(ret));
(void)i2c_remove_device(*out_dev);
*out_dev = NULL;
}
if (*out_dev == NULL) {
ESP_LOGE(TAG, "No ADXL367 on I2C (tried 0x1D and 0x53).");
}
return ret;
}
esp_err_t node_acc_adxl367_run_xyz_stats_capture(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "stats: set_measurement_mode failed: %s", esp_err_to_name(ret));
goto out;
}
int64_t sx = 0, sy = 0, sz = 0;
int16_t min_x = 0, max_x = 0, min_y = 0, max_y = 0, min_z = 0, max_z = 0;
uint32_t n = 0;
bool first = true;
ESP_LOGI(TAG, "======== XYZ stats capture: %d ms (keep board still for noise floor) ========",
(int)NODE_ACC_ADXL367_TEST_STATS_MS);
const TickType_t t_end = xTaskGetTickCount() + pdMS_TO_TICKS(NODE_ACC_ADXL367_TEST_STATS_MS);
while (xTaskGetTickCount() < t_end) {
int16_t x = 0, y = 0, z = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "stats: read_xyz_raw failed: %s", esp_err_to_name(ret));
break;
}
sx += x;
sy += y;
sz += z;
if (first) {
min_x = max_x = x;
min_y = max_y = y;
min_z = max_z = z;
first = false;
} else {
if (x < min_x) {
min_x = x;
}
if (x > max_x) {
max_x = x;
}
if (y < min_y) {
min_y = y;
}
if (y > max_y) {
max_y = y;
}
if (z < min_z) {
min_z = z;
}
if (z > max_z) {
max_z = z;
}
}
n++;
}
if (ret == ESP_OK && n > 0) {
const int32_t mx = (int32_t)(sx / (int64_t)n);
const int32_t my = (int32_t)(sy / (int64_t)n);
const int32_t mz = (int32_t)(sz / (int64_t)n);
const int32_t span_x = (int32_t)max_x - (int32_t)min_x;
const int32_t span_y = (int32_t)max_y - (int32_t)min_y;
const int32_t span_z = (int32_t)max_z - (int32_t)min_z;
ESP_LOGI(TAG, "stats: samples=%u (~%.0f Hz if steady DATA_RDY)", (unsigned)n,
(double)n * 1000.0 / (double)NODE_ACC_ADXL367_TEST_STATS_MS);
ESP_LOGI(TAG, "stats: X mean=%" PRId32 " (~%.4f g) min=%d max=%d span=%" PRId32 " (~%.4f g)", mx,
ADXL367_STATS_CODE_TO_G(mx), (int)min_x, (int)max_x, (int32_t)span_x,
ADXL367_STATS_CODE_TO_G(span_x));
ESP_LOGI(TAG, "stats: Y mean=%" PRId32 " (~%.4f g) min=%d max=%d span=%" PRId32 " (~%.4f g)", my,
ADXL367_STATS_CODE_TO_G(my), (int)min_y, (int)max_y, (int32_t)span_y,
ADXL367_STATS_CODE_TO_G(span_y));
ESP_LOGI(TAG, "stats: Z mean=%" PRId32 " (~%.4f g) min=%d max=%d span=%" PRId32 " (~%.4f g)", mz,
ADXL367_STATS_CODE_TO_G(mz), (int)min_z, (int)max_z, (int32_t)span_z,
ADXL367_STATS_CODE_TO_G(span_z));
ESP_LOGI(TAG,
"stats: THRESH_ACT LSB ~ g*4000 (+/-2g intent)");
} else if (n == 0) {
ret = ESP_ERR_INVALID_STATE;
}
out:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
return ret;
}
esp_err_t node_acc_adxl367_run_phase1_test(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
for (int i = 0; i < 8; i++) {
int16_t x = 0, y = 0, z = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "read_xyz_raw failed: %s", esp_err_to_name(ret));
break;
}
ESP_LOGI(TAG, "p1 sample %d: x=%d y=%d z=%d", i, (int)x, (int)y, (int)z);
vTaskDelay(pdMS_TO_TICKS(100));
}
(void)i2c_remove_device(i2c_dev);
return ret;
}
esp_err_t node_acc_adxl367_run_phase2_test(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
/* ACCEL_ONLY: one XYZ sample */
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
goto out;
}
{
int16_t x = 0, y = 0, z = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p2 accel-only xyz failed: %s", esp_err_to_name(ret));
goto out;
}
ESP_LOGI(TAG, "p2 accel-only: x=%d y=%d z=%d", (int)x, (int)y, (int)z);
}
/* ACCEL_AND_TEMP */
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_AND_TEMP);
if (ret != ESP_OK) {
goto out;
}
{
int16_t x = 0, y = 0, z = 0;
float tc = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p2 accel+temp xyz failed: %s", esp_err_to_name(ret));
goto out;
}
ret = node_acc_adxl367_read_temp_celsius(&acc, &tc);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p2 accel+temp temp C failed: %s", esp_err_to_name(ret));
goto out;
}
ESP_LOGI(TAG, "p2 accel+temp: x=%d y=%d z=%d temp=%.2f C", (int)x, (int)y, (int)z, (double)tc);
}
/* TEMP_ONLY */
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_TEMP_ONLY);
if (ret != ESP_OK) {
goto out;
}
{
float tc = 0;
ret = node_acc_adxl367_read_temp_celsius(&acc, &tc);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p2 temp-only temp failed: %s", esp_err_to_name(ret));
goto out;
}
ESP_LOGI(TAG, "p2 temp-only: temp=%.2f C", (double)tc);
int16_t x = 0, y = 0, z = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG, "p2 temp-only: expected INVALID_STATE for xyz");
ret = ESP_FAIL;
goto out;
}
ESP_LOGI(TAG, "p2 temp-only: xyz correctly rejected (INVALID_STATE)");
ret = ESP_OK;
}
out:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
return ret;
}
/** STATUS FIFO watermark bit. */
#define P3_STATUS_FIFO_WATERMARK (1u << 2)
esp_err_t node_acc_adxl367_run_phase3_test(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
goto out;
}
/* Stream mode, XYZ, watermark at 8 sample sets (XYZ => 8*3 FIFO entries when full). */
ret = node_acc_adxl367_fifo_setup(&acc, NODE_ACC_ADXL367_FIFO_STREAM, NODE_ACC_ADXL367_FIFO_FMT_XYZ, 8);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p3 fifo_setup failed: %s", esp_err_to_name(ret));
goto out;
}
for (int w = 0; w < 50; w++) {
uint8_t st = 0;
ret = node_acc_adxl367_read_status(&acc, &st);
if (ret != ESP_OK) {
goto out;
}
if ((st & P3_STATUS_FIFO_WATERMARK) != 0) {
ESP_LOGI(TAG, "p3 STATUS 0x%02X (FIFO watermark)", (unsigned)st);
break;
}
vTaskDelay(pdMS_TO_TICKS(20));
}
uint16_t n_ent = 0;
ret = node_acc_adxl367_fifo_get_entry_count(&acc, &n_ent);
if (ret != ESP_OK) {
goto out;
}
ESP_LOGI(TAG, "p3 FIFO entries before drain: %u", (unsigned)n_ent);
int16_t x[32], y[32], z[32];
size_t nt = 0;
ret = node_acc_adxl367_fifo_drain_xyz(&acc, x, y, z, sizeof(x) / sizeof(x[0]), &nt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p3 fifo_drain_xyz failed: %s", esp_err_to_name(ret));
goto out;
}
ESP_LOGI(TAG, "p3 drained complete XYZ triplets: %u", (unsigned)nt);
for (size_t i = 0; i < nt && i < 4u; i++) {
ESP_LOGI(TAG, "p3 triplet %u: x=%d y=%d z=%d", (unsigned)i, (int)x[i], (int)y[i], (int)z[i]);
}
ret = node_acc_adxl367_fifo_disable(&acc);
if (ret != ESP_OK) {
goto out;
}
ESP_LOGI(TAG, "p3 FIFO disabled OK");
out:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
return ret;
}
esp_err_t node_acc_adxl367_run_phase4_test(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
SemaphoreHandle_t sem = NULL;
bool handler_added = false;
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
sem = xSemaphoreCreateBinary();
if (sem == NULL) {
ret = ESP_ERR_NO_MEM;
goto out;
}
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
goto out_sem;
}
node_acc_adxl367_int_map_t imap = {0};
imap.fifo_watermark = 1u;
imap.int_low = 1u;
ret = node_acc_adxl367_int_map(&acc, 1u, &imap);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p4 int_map failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = node_acc_adxl367_fifo_setup(&acc, NODE_ACC_ADXL367_FIFO_STREAM, NODE_ACC_ADXL367_FIFO_FMT_XYZ, 8);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p4 fifo_setup failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = gpio_install_isr_service(0);
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG, "p4 gpio_install_isr_service failed: %s", esp_err_to_name(ret));
goto out_sem;
}
gpio_config_t io = {
.pin_bit_mask = 1ull << NODE_ACC_ADXL367_TEST_INT1_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_NEGEDGE,
};
ret = gpio_config(&io);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p4 gpio_config failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = gpio_isr_handler_add((gpio_num_t)NODE_ACC_ADXL367_TEST_INT1_GPIO, p4_fifo_int_isr, sem);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p4 gpio_isr_handler_add failed: %s", esp_err_to_name(ret));
goto out_sem;
}
handler_added = true;
gpio_intr_enable((gpio_num_t)NODE_ACC_ADXL367_TEST_INT1_GPIO);
if (xSemaphoreTake(sem, pdMS_TO_TICKS(3000)) != pdTRUE) {
ESP_LOGE(TAG, "p4 timeout waiting for INT1 (FIFO watermark)");
ret = ESP_ERR_TIMEOUT;
goto out_gpio;
}
uint8_t st = 0;
ret = node_acc_adxl367_read_status(&acc, &st);
if (ret != ESP_OK) {
goto out_gpio;
}
ESP_LOGI(TAG, "p4 STATUS 0x%02X (after INT)", (unsigned)st);
uint16_t n_ent = 0;
ret = node_acc_adxl367_fifo_get_entry_count(&acc, &n_ent);
if (ret != ESP_OK) {
goto out_gpio;
}
ESP_LOGI(TAG, "p4 FIFO entries: %u", (unsigned)n_ent);
int16_t x[32], y[32], z[32];
size_t nt = 0;
ret = node_acc_adxl367_fifo_drain_xyz(&acc, x, y, z, sizeof(x) / sizeof(x[0]), &nt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p4 fifo_drain_xyz failed: %s", esp_err_to_name(ret));
goto out_gpio;
}
ESP_LOGI(TAG, "p4 drained XYZ triplets: %u", (unsigned)nt);
if (nt > 0) {
ESP_LOGI(TAG, "p4 first triplet: x=%d y=%d z=%d", (int)x[0], (int)y[0], (int)z[0]);
}
ret = node_acc_adxl367_fifo_disable(&acc);
if (ret != ESP_OK) {
goto out_gpio;
}
ESP_LOGI(TAG, "p4 FIFO disabled OK");
out_gpio:
if (handler_added) {
gpio_intr_disable((gpio_num_t)NODE_ACC_ADXL367_TEST_INT1_GPIO);
gpio_isr_handler_remove((gpio_num_t)NODE_ACC_ADXL367_TEST_INT1_GPIO);
}
gpio_reset_pin((gpio_num_t)NODE_ACC_ADXL367_TEST_INT1_GPIO);
out_sem:
vSemaphoreDelete(sem);
out:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
return ret;
}
esp_err_t node_acc_adxl367_run_phase5_test(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
SemaphoreHandle_t sem = NULL;
bool handler_added = false;
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
return ret;
}
sem = xSemaphoreCreateBinary();
if (sem == NULL) {
ret = ESP_ERR_NO_MEM;
goto out;
}
ret = node_acc_adxl367_fifo_disable(&acc);
if (ret != ESP_OK) {
goto out_sem;
}
ret = node_acc_adxl367_act_inact_disable(&acc);
if (ret != ESP_OK) {
goto out_sem;
}
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
goto out_sem;
}
/* REF activity/inact, LINKLOOP=3, X axis only. */
ret = node_acc_adxl367_setup_activity_detection(
&acc, NODE_ACC_ADXL367_AI_REF_REL, NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G(NODE_ACC_ADXL367_TEST_P5_THRESH_G),
(uint8_t)NODE_ACC_ADXL367_TEST_P5_TIME_ACT_SAMPLES);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 setup_activity failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = node_acc_adxl367_setup_inactivity_detection(
&acc, NODE_ACC_ADXL367_AI_REF_REL,
NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G(NODE_ACC_ADXL367_TEST_P5_THRESH_INACT_G),
(uint16_t)NODE_ACC_ADXL367_TEST_P5_TIME_INACT_SAMPLES);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 setup_inactivity failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = node_acc_adxl367_set_act_inact_linkloop(&acc, (uint8_t)NODE_ACC_ADXL367_TEST_P5_LINKLOOP_MODE);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 linkloop failed: %s", esp_err_to_name(ret));
goto out_sem;
}
/* AXIS_MASK: block Y/Z so ACT/INACT use X only (same mask applies to both). */
ret = node_acc_adxl367_set_activity_axes_enabled(&acc, true, false, false);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 set_activity_axes failed: %s", esp_err_to_name(ret));
goto out_sem;
}
vTaskDelay(pdMS_TO_TICKS(200));
node_acc_adxl367_int_map_t imap = {0};
imap.act = 1u;
imap.inact = 1u;
imap.int_low = 1u;
ret = node_acc_adxl367_int_map(&acc, 2u, &imap);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 int_map failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = gpio_install_isr_service(0);
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG, "p5 gpio_install_isr_service failed: %s", esp_err_to_name(ret));
goto out_sem;
}
gpio_config_t io = {
.pin_bit_mask = 1ull << NODE_ACC_ADXL367_TEST_INT2_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_NEGEDGE,
};
ret = gpio_config(&io);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 gpio_config failed: %s", esp_err_to_name(ret));
goto out_sem;
}
ret = gpio_isr_handler_add((gpio_num_t)NODE_ACC_ADXL367_TEST_INT2_GPIO, p5_act_int_isr, sem);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "p5 gpio_isr_handler_add failed: %s", esp_err_to_name(ret));
goto out_sem;
}
handler_added = true;
/* INT2 off until arm delay. */
ESP_LOGI(TAG, "p5 linked ACT/INACT, window %d s", (int)(NODE_ACC_ADXL367_TEST_P5_WINDOW_MS / 1000));
ESP_LOGI(TAG, "THRESH_ACT ~%.2f g (%u LSB), TIME_ACT=%u; THRESH_INACT ~%.2f g (%u LSB), TIME_INACT=%u",
(double)NODE_ACC_ADXL367_TEST_P5_THRESH_G,
(unsigned)NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G(NODE_ACC_ADXL367_TEST_P5_THRESH_G),
(unsigned)NODE_ACC_ADXL367_TEST_P5_TIME_ACT_SAMPLES, (double)NODE_ACC_ADXL367_TEST_P5_THRESH_INACT_G,
(unsigned)NODE_ACC_ADXL367_THRESH_ACT_LSB_FROM_G(NODE_ACC_ADXL367_TEST_P5_THRESH_INACT_G),
(unsigned)NODE_ACC_ADXL367_TEST_P5_TIME_INACT_SAMPLES);
ESP_LOGI(TAG, "LINKLOOP=%u, axes: X only (Y/Z masked)", (unsigned)NODE_ACC_ADXL367_TEST_P5_LINKLOOP_MODE);
ESP_LOGI(TAG, "Waiting %d ms with INT2 disabled (reference settle; avoids false start)",
(int)NODE_ACC_ADXL367_TEST_P5_ARM_MS);
vTaskDelay(pdMS_TO_TICKS(NODE_ACC_ADXL367_TEST_P5_ARM_MS));
{
uint8_t st_clr = 0;
for (int i = 0; i < 3; i++) {
(void)node_acc_adxl367_read_status(&acc, &st_clr);
}
while (xSemaphoreTake(sem, 0) == pdTRUE) {
}
gpio_intr_enable((gpio_num_t)NODE_ACC_ADXL367_TEST_INT2_GPIO);
vTaskDelay(pdMS_TO_TICKS(50));
while (xSemaphoreTake(sem, 0) == pdTRUE) {
}
ESP_LOGI(TAG, "INT2 on; poll STATUS");
const TickType_t t_end = xTaskGetTickCount() + pdMS_TO_TICKS(NODE_ACC_ADXL367_TEST_P5_WINDOW_MS);
ret = ESP_OK;
while (xTaskGetTickCount() < t_end) {
while (xSemaphoreTake(sem, 0) == pdTRUE) {
uint8_t st = 0;
(void)node_acc_adxl367_read_status(&acc, &st);
if ((st & NODE_ACC_ADXL367_STATUS_ACT) != 0) {
ESP_LOGI(TAG, "[activity] motion (STATUS 0x%02X)", (unsigned)st);
} else if ((st & NODE_ACC_ADXL367_STATUS_INACT) != 0) {
ESP_LOGI(TAG, "[inactive] still / below inact threshold (STATUS 0x%02X)", (unsigned)st);
} else {
ESP_LOGD(TAG, "INT2 edge, STATUS 0x%02X (no ACT/INACT latched)", (unsigned)st);
}
}
vTaskDelay(pdMS_TO_TICKS(NODE_ACC_ADXL367_TEST_P5_POLL_MS));
}
ESP_LOGI(TAG, "======== Phase 5 end ========");
}
if (handler_added) {
gpio_intr_disable((gpio_num_t)NODE_ACC_ADXL367_TEST_INT2_GPIO);
gpio_isr_handler_remove((gpio_num_t)NODE_ACC_ADXL367_TEST_INT2_GPIO);
}
gpio_reset_pin((gpio_num_t)NODE_ACC_ADXL367_TEST_INT2_GPIO);
(void)node_acc_adxl367_act_inact_disable(&acc);
node_acc_adxl367_int_map_t zmap = {0};
(void)node_acc_adxl367_int_map(&acc, 2u, &zmap);
out_sem:
vSemaphoreDelete(sem);
out:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
return ret;
}
void node_acc_adxl367_run_transition_monitor_forever(void)
{
i2c_master_dev_handle_t i2c_dev = NULL;
node_acc_adxl367_dev_t acc = {0};
esp_err_t ret = probe_i2c_and_init(&acc, &i2c_dev);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "transition monitor: init failed");
while (1) {
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
ret = node_acc_adxl367_set_measurement_mode(&acc, NODE_ACC_ADXL367_MEAS_ACCEL_ONLY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "transition monitor: accel-only failed: %s", esp_err_to_name(ret));
goto hang;
}
(void)node_acc_adxl367_fifo_disable(&acc);
(void)node_acc_adxl367_act_inact_disable(&acc);
vTaskDelay(pdMS_TO_TICKS(200));
ESP_LOGI(TAG, "transition monitor: max sample delta, high>%d low<%d still_cnt=%u",
(int)NODE_ACC_ADXL367_MONITOR_DELTA_HIGH_LSB, (int)NODE_ACC_ADXL367_MONITOR_DELTA_LOW_LSB,
(unsigned)NODE_ACC_ADXL367_MONITOR_STILL_COUNT);
bool have_prev = false;
int16_t px = 0, py = 0, pz = 0;
bool moving = false;
uint32_t still_cnt = 0;
for (;;) {
int16_t x = 0, y = 0, z = 0;
ret = node_acc_adxl367_read_xyz_raw(&acc, &x, &y, &z);
if (ret != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(10));
continue;
}
if (x > NODE_ACC_ADXL367_MONITOR_ABS_MAX || x < -NODE_ACC_ADXL367_MONITOR_ABS_MAX ||
y > NODE_ACC_ADXL367_MONITOR_ABS_MAX || y < -NODE_ACC_ADXL367_MONITOR_ABS_MAX ||
z > NODE_ACC_ADXL367_MONITOR_ABS_MAX || z < -NODE_ACC_ADXL367_MONITOR_ABS_MAX) {
have_prev = false;
vTaskDelay(pdMS_TO_TICKS(5));
continue;
}
if (!have_prev) {
px = x;
py = y;
pz = z;
have_prev = true;
continue;
}
const uint32_t dx = adxl367_uabs_diff(x, px);
const uint32_t dy = adxl367_uabs_diff(y, py);
const uint32_t dz = adxl367_uabs_diff(z, pz);
const uint32_t dmax = adxl367_max_u32(dx, dy, dz);
px = x;
py = y;
pz = z;
if (dmax > (uint32_t)NODE_ACC_ADXL367_MONITOR_DELTA_HIGH_LSB) {
still_cnt = 0;
if (!moving) {
ESP_LOGI(TAG, "[still_to_motion] max_delta=%u (~%.4f g)", (unsigned)dmax, (double)dmax / 4000.0);
moving = true;
}
} else if (dmax < (uint32_t)NODE_ACC_ADXL367_MONITOR_DELTA_LOW_LSB) {
still_cnt++;
if (moving && still_cnt >= NODE_ACC_ADXL367_MONITOR_STILL_COUNT) {
ESP_LOGI(TAG, "[motion_to_still] max_delta=%u (~%.4f g)", (unsigned)dmax, (double)dmax / 4000.0);
moving = false;
still_cnt = 0;
}
} else {
still_cnt = 0;
}
}
hang:
if (i2c_dev != NULL) {
(void)i2c_remove_device(i2c_dev);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
void node_acc_adxl367_run_phase6_default_app(void)
{
ESP_LOGI(TAG, "phase6 default app");
node_acc_adxl367_run_transition_monitor_forever();
}
main.cpp
/**
* @file AIoTNode.cpp
*/
#include "nvs_flash.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "node_i2c.h"
#include "node_acc_adxl367_test.h"
#ifdef __cplusplus
extern "C" {
#endif
static const char *TAG = "AIoTNode";
#ifndef AIOTNODE_BOOT_RUN_ADXL367_STATS
#define AIOTNODE_BOOT_RUN_ADXL367_STATS 0
#endif
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(i2c_bus_init());
#if AIOTNODE_BOOT_RUN_ADXL367_STATS
ret = node_acc_adxl367_run_xyz_stats_capture();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "XYZ stats failed: %s", esp_err_to_name(ret));
}
#endif
node_acc_adxl367_run_phase6_default_app();
}
#ifdef __cplusplus
}
#endif