diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..286a0e2 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Windows", + "cStandard": "c11", + "cppStandard": "c++17", + "includePath": [ + "${config:idf.espIdfPath}/components/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${config:idf.espIdfPath}/components" + ], + "limitSymbolsToIncludedHeaders": false + }, + "compileCommands": "${workspaceFolder}/build/compile_commands.json", + "compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-13.2.0_20240530/riscv32-esp-elf/bin/riscv32-esp-elf-gcc" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..49877e5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "idf.adapterTargetName": "esp32c6", + "idf.flashType": "UART", + "files.associations": { + "*.c": "c", + "*.h": "c" + }, + "editor.formatOnSave": true, + "idf.port": "/dev/tty.usbmodem11101", + "idf.gitPath": "git", + "idf.espIdfPath": "/Users/lost/esp/v5.3.1/esp-idf", + "idf.pythonBinPath": "/Users/lost/.espressif/python_env/idf5.3_py3.9_env/bin/python", + "idf.toolsPath": "/Users/lost/.espressif", + "idf.customExtraPaths": "/Users/lost/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin:/Users/lost/.espressif/tools/riscv32-esp-elf-gdb/14.2_20240403/riscv32-esp-elf-gdb/bin:/Users/lost/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20240530/xtensa-esp-elf/bin:/Users/lost/.espressif/tools/riscv32-esp-elf/esp-13.2.0_20240530/riscv32-esp-elf/bin:/Users/lost/.espressif/tools/esp32ulp-elf/2.38_20240113/esp32ulp-elf/bin:/Users/lost/.espressif/tools/cmake/3.24.0/CMake.app/Contents/bin:/Users/lost/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240318/openocd-esp32/bin:/Users/lost/.espressif/tools/ninja/1.11.1:/Users/lost/.espressif/tools/esp-rom-elfs/20240305", + "idf.customExtraVars": { + "OPENOCD_SCRIPTS": "/Users/lost/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240318/openocd-esp32/share/openocd/scripts", + "ESP_ROM_ELF_DIR": "/Users/lost/.espressif/tools/esp-rom-elfs/20240305/" + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..04a9b16 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +# The following lines of boilerplate must be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(Q_sensor) + +# Add a custom command that will be executed before building the main target +add_custom_target(PreBuildCommand + COMMAND ${CMAKE_COMMAND} -E echo "Executing update version script..." + COMMAND bash ${CMAKE_SOURCE_DIR}/tools/update_version.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Update version script finish!" +) + +# Add a dependency of the main project on PreBuildCommand build target +add_dependencies(${CMAKE_PROJECT_NAME}.elf PreBuildCommand) + +# Define a custom target for the OTA script +add_custom_target(make_ota ALL + COMMAND ${CMAKE_COMMAND} -E echo "Executing make OTA script..." + COMMAND bash ${CMAKE_SOURCE_DIR}/tools/make_ota.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Make OTA script finish!" +) + +# Add a dependency of make_ota target on the main project build target +add_dependencies(make_ota ${CMAKE_PROJECT_NAME}.elf) \ No newline at end of file diff --git a/components/ags10/.eil.yml b/components/ags10/.eil.yml new file mode 100644 index 0000000..48c3906 --- /dev/null +++ b/components/ags10/.eil.yml @@ -0,0 +1,22 @@ +name: ags10 +description: Driver for AGS10 TVOC sensor +version: 0.5.0 +groups: + - tvoc +code_owners: xyzroe +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp32c3 + - esp8266 + - esp32s2 + - esp32c3 + - esp32c6 +license: BSD-3 +copyrights: + - name: xyzroe + year: 2024 diff --git a/components/ags10/CMakeLists.txt b/components/ags10/CMakeLists.txt new file mode 100644 index 0000000..76bdb51 --- /dev/null +++ b/components/ags10/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS ags10.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) \ No newline at end of file diff --git a/components/ags10/LICENSE b/components/ags10/LICENSE new file mode 100644 index 0000000..caddd1b --- /dev/null +++ b/components/ags10/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2024 xyzroe + +Based on https://github.com/adafruit/Adafruit_AGS02MA + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +1. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +1. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/ags10/ags10.c b/components/ags10/ags10.c new file mode 100644 index 0000000..901eb21 --- /dev/null +++ b/components/ags10/ags10.c @@ -0,0 +1,202 @@ +#include "ags10.h" +#include +#include + +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) + +static const char *TAG = "ags10"; + +static uint8_t crc8(const uint8_t *data, int len); +static bool _read_reg(i2c_dev_t *dev, uint8_t cmd, uint16_t delayms, uint8_t *value, size_t value_size); + +esp_err_t ags10_init_desc(i2c_dev_t *dev, i2c_port_t port, uint8_t addr, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->port = port; + dev->addr = addr; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + // esp_err_t err = i2c_param_config(port, &dev->cfg); + // if (err != ESP_OK) + //{ + // ESP_LOGE(TAG, "I2C param config failed: %s", esp_err_to_name(err)); + // return err; + // } + + // err = i2c_driver_install(port, I2C_MODE_MASTER, 0, 0, 0); + // if (err != ESP_OK) + //{ + // ESP_LOGE(TAG, "I2C driver install failed: %s", esp_err_to_name(err)); + // return err; + //} + + return i2c_dev_create_mutex(dev); +} + +esp_err_t ags10_free_desc(i2c_dev_t *dev) +{ + // i2c_driver_delete(dev->port); + CHECK_ARG(dev); + return i2c_dev_delete_mutex(dev); +} + +esp_err_t ags10_read_tvoc(i2c_dev_t *dev, uint32_t *tvoc) +{ + CHECK_ARG(dev && tvoc); + + uint8_t buf[5]; + if (!_read_reg(dev, AGS10_TVOCSTAT_REG, 1500, buf, sizeof(buf))) + { + return ESP_FAIL; + } + + *tvoc = (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return ESP_OK; +} + +esp_err_t ags10_read_version(i2c_dev_t *dev, uint8_t *version) +{ + CHECK_ARG(dev && version); + + uint8_t buf[5]; + if (!_read_reg(dev, AGS10_VERSION_REG, 30, buf, sizeof(buf))) + { + return ESP_FAIL; + } + + *version = buf[3]; + return ESP_OK; +} + +esp_err_t ags10_read_resistance(i2c_dev_t *dev, uint32_t *resistance) +{ + CHECK_ARG(dev && resistance); + + uint8_t buf[5]; + if (!_read_reg(dev, AGS10_GASRES_REG, 1500, buf, sizeof(buf))) + { + return ESP_FAIL; + } + + *resistance = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return ESP_OK; +} + +esp_err_t ags10_set_i2c_address(i2c_dev_t *dev, uint8_t new_address) +{ + CHECK_ARG(dev); + + uint8_t buf[6]; + + new_address &= 0x7F; + + buf[0] = AGS10_SETADDR_REG; + buf[3] = buf[1] = new_address; + buf[4] = buf[2] = ~new_address; + buf[5] = crc8(buf + 1, 4); + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_write(cmd, buf, 6, true); + i2c_master_stop(cmd); + esp_err_t err = i2c_master_cmd_begin(dev->port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to set new address: %s", esp_err_to_name(err)); + return err; + } + + dev->addr = new_address; + return ESP_OK; +} + +esp_err_t ags10_set_zero_point_with_factory_defaults(i2c_dev_t *dev) +{ + return ags10_set_zero_point_with(dev, 0xFFFF); +} + +esp_err_t ags10_set_zero_point_with_current_resistance(i2c_dev_t *dev) +{ + return ags10_set_zero_point_with(dev, 0x0000); +} + +esp_err_t ags10_set_zero_point_with(i2c_dev_t *dev, uint16_t value) +{ + CHECK_ARG(dev); + + uint8_t buf[5] = {0x00, 0x0C, (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF), 0}; + buf[4] = crc8(buf, 4); + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_write(cmd, buf, 5, true); + i2c_master_stop(cmd); + esp_err_t err = i2c_master_cmd_begin(dev->port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to set zero point: %s", esp_err_to_name(err)); + return err; + } + + return ESP_OK; +} + +static bool _read_reg(i2c_dev_t *dev, uint8_t cmd, uint16_t delayms, uint8_t *value, size_t value_size) + +{ + I2C_DEV_TAKE_MUTEX(dev); + + esp_err_t err = i2c_dev_write(dev, NULL, 0, &cmd, 1); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to send read command: %s", esp_err_to_name(err)); + I2C_DEV_GIVE_MUTEX(dev); + return false; + } + + vTaskDelay(pdMS_TO_TICKS(delayms)); + + err = i2c_dev_read(dev, NULL, 0, value, value_size); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to read data: %s", esp_err_to_name(err)); + I2C_DEV_GIVE_MUTEX(dev); + return false; + } + + I2C_DEV_GIVE_MUTEX(dev); + + return true; +} + +static uint8_t crc8(const uint8_t *data, int len) +{ + const uint8_t POLYNOMIAL = 0x31; + uint8_t crc = 0xFF; + + for (int j = len; j; --j) + { + crc ^= *data++; + + for (int i = 8; i; --i) + { + crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1); + } + } + return crc; +} \ No newline at end of file diff --git a/components/ags10/ags10.h b/components/ags10/ags10.h new file mode 100644 index 0000000..49e3a8f --- /dev/null +++ b/components/ags10/ags10.h @@ -0,0 +1,108 @@ +#ifndef _AGS10_H +#define _AGS10_H + +#include +#include +#include +#include + +#define AGS10_I2CADDR_DEFAULT 0x1A ///< AGS10 default I2C address +#define AGS10_TVOCSTAT_REG 0x00 ///< Status and TVOC reading +#define AGS10_VERSION_REG 0x11 ///< Firmware version +#define AGS10_GASRES_REG 0x20 ///< Raw gas resistance +#define AGS10_SETADDR_REG 0x21 ///< Change I2C address +#define AGS10_CRC8_INIT 0xFF ///< CRC8 init value +#define AGS10_CRC8_POLYNOMIAL 0x31 ///< CRC8 polynomial +#define I2C_FREQ_HZ 20000 ///< Fixed I2C frequency for AGS10 + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * @brief Initialize the AGS10 sensor descriptor + * + * @param dev Pointer to the I2C device descriptor + * @param port I2C port number + * @param addr I2C address of the sensor + * @param sda_gpio GPIO number for SDA + * @param scl_gpio GPIO number for SCL + * @return ESP_OK on success + */ + esp_err_t ags10_init_desc(i2c_dev_t *dev, i2c_port_t port, uint8_t addr, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + + /** + * @brief Free the AGS10 sensor descriptor + * + * @param dev Pointer to the I2C device descriptor + * @return ESP_OK on success + */ + esp_err_t ags10_free_desc(i2c_dev_t *dev); + + /** + * @brief Read TVOC value from the sensor + * + * @param dev Pointer to the I2C device descriptor + * @param[out] tvoc Pointer to store the TVOC value + * @return ESP_OK on success + */ + esp_err_t ags10_read_tvoc(i2c_dev_t *dev, uint32_t *tvoc); + + /** + * @brief Read firmware version from the sensor + * + * @param dev Pointer to the I2C device descriptor + * @param[out] version Pointer to store the firmware version + * @return ESP_OK on success + */ + esp_err_t ags10_read_version(i2c_dev_t *dev, uint8_t *version); + + /** + * @brief Read resistance value from the sensor + * + * @param dev Pointer to the I2C device descriptor + * @param[out] resistance Pointer to store the resistance value + * @return ESP_OK on success + */ + esp_err_t ags10_read_resistance(i2c_dev_t *dev, uint32_t *resistance); + + /** + * @brief Set new I2C address for the sensor + * + * @param dev Pointer to the I2C device descriptor + * @param new_address New I2C address + * @return ESP_OK on success + */ + esp_err_t ags10_set_i2c_address(i2c_dev_t *dev, uint8_t new_address); + + /** + * @brief Set zero-point calibration with factory defaults + * + * @param dev Pointer to the I2C device descriptor + * @return ESP_OK on success + */ + esp_err_t ags10_set_zero_point_with_factory_defaults(i2c_dev_t *dev); + + /** + * @brief Set zero-point calibration with current resistance + * + * @param dev Pointer to the I2C device descriptor + * @return ESP_OK on success + */ + esp_err_t ags10_set_zero_point_with_current_resistance(i2c_dev_t *dev); + + /** + * @brief Set zero-point calibration with a specific value + * + * @param dev Pointer to the I2C device descriptor + * @param value Calibration value + * @return ESP_OK on success + */ + esp_err_t ags10_set_zero_point_with(i2c_dev_t *dev, uint16_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* _AGS10_H */ \ No newline at end of file diff --git a/components/ags10/component.mk b/components/ags10/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/ags10/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/aht/.eil.yml b/components/aht/.eil.yml new file mode 100644 index 0000000..af3718f --- /dev/null +++ b/components/aht/.eil.yml @@ -0,0 +1,22 @@ +name: aht +description: Driver for AHT10/AHT15/AHT20 temperature and humidity sensor +version: 1.0.0 +groups: + - temperature + - humidity +code_owners: + - UncleRus +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: BSD-3 +copyrights: + - name: UncleRus + year: 2021 diff --git a/components/aht/CMakeLists.txt b/components/aht/CMakeLists.txt new file mode 100644 index 0000000..70f4ca3 --- /dev/null +++ b/components/aht/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS aht.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) diff --git a/components/aht/LICENSE b/components/aht/LICENSE new file mode 100644 index 0000000..6864265 --- /dev/null +++ b/components/aht/LICENSE @@ -0,0 +1,26 @@ +Copyright 2021 Ruslan V. Uss + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/aht/aht.c b/components/aht/aht.c new file mode 100644 index 0000000..263a0d8 --- /dev/null +++ b/components/aht/aht.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2021 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file aht.c + * + * ESP-IDF driver for humidty/temperature sensors AHT10/AHT15/AHT20 + * + * Copyright (c) 2021 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#include "aht.h" +#include +#include +#include + +#define I2C_FREQ_HZ 400000 // 400kHz + +static const char *TAG = "aht"; + +#define CMD_CALIBRATE_1X (0xe1) +#define CMD_CALIBRATE_20 (0xbe) +#define CMD_RESET (0xba) +#define CMD_MODE_NORMAL (0xa8) +#define CMD_START_MEASUREMENT (0xac) + +#define ARG_MODE_NORMAL (0x00) +#define ARG_MODE_CYCLE (0x20) +#define ARG_MODE_CALIBRATE (0x08) +#define ARG_MEAS_DATA (0x33) + +#define BIT_STATUS_BUSY BIT(7) +#define BIT_STATUS_CAL BIT(3) + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) + +static esp_err_t send_cmd_nolock(aht_t *dev, uint8_t cmd0, uint8_t cmd1, uint8_t cmd2, uint32_t delay_ms) +{ + uint8_t buf[3] = {cmd0, cmd1, cmd2}; + CHECK(i2c_dev_write(&dev->i2c_dev, NULL, 0, &buf, 3)); + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + + return ESP_OK; +} + +static esp_err_t setup_nolock(aht_t *dev) +{ + return send_cmd_nolock(dev, dev->type == AHT_TYPE_AHT1x ? CMD_CALIBRATE_1X : CMD_CALIBRATE_20, + (dev->mode == AHT_MODE_NORMAL ? ARG_MODE_NORMAL : ARG_MODE_CYCLE) | ARG_MODE_CALIBRATE, 0, 350); +} + +/////////////////////////////////////////////////////////////////////////////// + +esp_err_t aht_init_desc(aht_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + if (addr != AHT_I2C_ADDRESS_GND || addr > AHT_I2C_ADDRESS_VCC) + { + ESP_LOGE(TAG, "Invalid I2C address"); + return ESP_ERR_INVALID_ARG; + } + + dev->i2c_dev.port = port; + dev->i2c_dev.addr = addr; + dev->i2c_dev.cfg.sda_io_num = sda_gpio; + dev->i2c_dev.cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(&dev->i2c_dev); +} + +esp_err_t aht_free_desc(aht_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(&dev->i2c_dev); +} + +esp_err_t aht_init(aht_t *dev) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + I2C_DEV_CHECK(&dev->i2c_dev, setup_nolock(dev)); + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t aht_reset(aht_t *dev) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + + uint8_t cmd = CMD_RESET; + I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &cmd, 1)); + vTaskDelay(pdMS_TO_TICKS(20)); + I2C_DEV_CHECK(&dev->i2c_dev, setup_nolock(dev)); + + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t aht_get_status(aht_t *dev, bool *busy, bool *calibrated) +{ + CHECK_ARG(dev && (busy || calibrated)); + + uint8_t status; + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_read(&dev->i2c_dev, NULL, 0, &status, 1)); + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + if (busy) + *busy = (status & BIT_STATUS_BUSY) != 0; + if (calibrated) + *calibrated = (status & BIT_STATUS_CAL) != 0; + + return ESP_OK; +} + +esp_err_t aht_get_data(aht_t *dev, float *temperature, float *humidity) +{ + CHECK_ARG(dev && (temperature || humidity)); + + uint8_t buf[6]; + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + I2C_DEV_CHECK(&dev->i2c_dev, send_cmd_nolock(dev, CMD_START_MEASUREMENT, ARG_MEAS_DATA, 0, 80)); + I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_read(&dev->i2c_dev, NULL, 0, buf, 6)); + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + if (humidity) + { + uint32_t raw = ((uint32_t)buf[1] << 12) | ((uint32_t)buf[2] << 4) | (buf[3] >> 4); + *humidity = (float)raw * 100 / 0x100000; + } + + if (temperature) + { + uint32_t raw = ((uint32_t)(buf[3] & 0x0f) << 16) | ((uint32_t)buf[4] << 8) | buf[5]; + *temperature = (float)raw * 200 / 0x100000 - 50; + } + + return ESP_OK; +} diff --git a/components/aht/aht.h b/components/aht/aht.h new file mode 100644 index 0000000..c4df6c1 --- /dev/null +++ b/components/aht/aht.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2021 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file aht.h + * @defgroup aht aht + * @{ + * + * ESP-IDF driver for humidty/temperature sensors AHT10/AHT15/AHT20 + * + * Copyright (c) 2021 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#ifndef __AHT_H__ +#define __AHT_H__ + +#include +#include + +#define AHT_I2C_ADDRESS_GND 0x38 //!< Device address when ADDR pin connected to GND +#define AHT_I2C_ADDRESS_VCC 0x39 //!< Device address when ADDR pin connected to VCC + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Device types + */ +typedef enum { + AHT_TYPE_AHT1x = 0, //!< AHT10, AHT15 + AHT_TYPE_AHT20, //!< AHT20 +} aht_type_t; + +/** + * Device modes + */ +typedef enum { + AHT_MODE_NORMAL = 0, //!< Normal mode + AHT_MODE_CYCLE, //!< Continuous measurements mode, undocumented +} aht_mode_t; + +/** + * Device descriptor + */ +typedef struct +{ + i2c_dev_t i2c_dev; + aht_type_t type; + aht_mode_t mode; +} aht_t; + +/** + * @brief Initialize device descriptor + * + * @param dev Device descriptor + * @param addr Device I2C address + * @param port I2C port + * @param sda_gpio SDA GPIO + * @param scl_gpio SCL GPIO + * @return `ESP_OK` on success + */ +esp_err_t aht_init_desc(aht_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + +/** + * @brief Free device descriptor + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t aht_free_desc(aht_t *dev); + +/** + * @brief Init device + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t aht_init(aht_t *dev); + +/** + * @brief Soft reset device + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t aht_reset(aht_t *dev); + +/** + * @brief Get device status + * + * @param dev Device descriptor + * @param[out] busy Busy flag + * - true: device currently measuring + * - false: device in indle mode + * @param[out] calibrated Calibration success flag + * - true: sensor calibrated + * - false: sensor not calibrated + * @return `ESP_OK` on success + */ +esp_err_t aht_get_status(aht_t *dev, bool *busy, bool *calibrated); + +/** + * @brief Get temperature and relative humidity + * + * @param dev Device descriptor + * @param[out] temperature Temperature, degrees Celsius + * @param[out] humidity Relative humidity, percents + * @return `ESP_OK` on success + */ +esp_err_t aht_get_data(aht_t *dev, float *temperature, float *humidity); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* __AHT_H__ */ diff --git a/components/aht/component.mk b/components/aht/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/aht/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/bh1750/.eil.yml b/components/bh1750/.eil.yml new file mode 100644 index 0000000..912c366 --- /dev/null +++ b/components/bh1750/.eil.yml @@ -0,0 +1,23 @@ +name: bh1750 +description: Driver for BH1750 light sensor +version: 1.1.0 +groups: + - light +code_owners: + - UncleRus +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: BSD-3 +copyrights: + - name: UncleRus + year: 2018 + - name: Andrej + year: 2017 diff --git a/components/bh1750/CMakeLists.txt b/components/bh1750/CMakeLists.txt new file mode 100644 index 0000000..37a0e49 --- /dev/null +++ b/components/bh1750/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS bh1750.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) diff --git a/components/bh1750/LICENSE b/components/bh1750/LICENSE new file mode 100644 index 0000000..61e3282 --- /dev/null +++ b/components/bh1750/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017 Andrej Krutak +Copyright (c) 2018 Ruslan V. Uss + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/bh1750/bh1750.c b/components/bh1750/bh1750.c new file mode 100644 index 0000000..52123f7 --- /dev/null +++ b/components/bh1750/bh1750.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2017 Andrej Krutak + * Copyright (c) 2018 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file bh1750.c + * + * @ingroup bh1750 ESP-IDF driver for BH1750 light sensor + * + * ESP-IDF driver for BH1750 light sensor + * + * Datasheet: ROHM Semiconductor bh1750fvi-e.pdf + * + * Ported from esp-open-rtos + * + * Copyright (c) 2017 Andrej Krutak \n + * Copyright (c) 2018 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include "bh1750.h" + +#define OPCODE_HIGH 0x0 +#define OPCODE_HIGH2 0x1 +#define OPCODE_LOW 0x3 + +#define OPCODE_CONT 0x10 +#define OPCODE_OT 0x20 + +#define OPCODE_POWER_DOWN 0x00 +#define OPCODE_POWER_ON 0x01 +#define OPCODE_MT_HI 0x40 +#define OPCODE_MT_LO 0x60 + +#define I2C_FREQ_HZ 400000 + +static const char *TAG = "bh1750"; + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) + +inline static esp_err_t send_command_nolock(i2c_dev_t *dev, uint8_t cmd) +{ + return i2c_dev_write(dev, NULL, 0, &cmd, 1); +} + +static esp_err_t send_command(i2c_dev_t *dev, uint8_t cmd) +{ + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, send_command_nolock(dev, cmd)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +esp_err_t bh1750_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + if (addr != BH1750_ADDR_LO && addr != BH1750_ADDR_HI) + { + ESP_LOGE(TAG, "Invalid I2C address"); + return ESP_ERR_INVALID_ARG; + } + + dev->port = port; + dev->addr = addr; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + return i2c_dev_create_mutex(dev); +} + +esp_err_t bh1750_free_desc(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(dev); +} + +esp_err_t bh1750_power_down(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return send_command(dev, OPCODE_POWER_DOWN); +} + +esp_err_t bh1750_power_on(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return send_command(dev, OPCODE_POWER_ON); +} + +esp_err_t bh1750_setup(i2c_dev_t *dev, bh1750_mode_t mode, bh1750_resolution_t resolution) +{ + CHECK_ARG(dev); + + uint8_t opcode = mode == BH1750_MODE_CONTINUOUS ? OPCODE_CONT : OPCODE_OT; + switch (resolution) + { + case BH1750_RES_LOW: + opcode |= OPCODE_LOW; + break; + case BH1750_RES_HIGH: + opcode |= OPCODE_HIGH; + break; + default: + opcode |= OPCODE_HIGH2; + break; + } + + CHECK(send_command(dev, opcode)); + + ESP_LOGD(TAG, "bh1750_setup(PORT = %d, ADDR = 0x%02x, VAL = 0x%02x)", dev->port, dev->addr, opcode); + + return ESP_OK; +} + +esp_err_t bh1750_set_measurement_time(i2c_dev_t *dev, uint8_t time) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, send_command_nolock(dev, OPCODE_MT_HI | (time >> 5))); + I2C_DEV_CHECK(dev, send_command_nolock(dev, OPCODE_MT_LO | (time & 0x1f))); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +esp_err_t bh1750_read(i2c_dev_t *dev, uint16_t *level) +{ + CHECK_ARG(dev && level); + + uint8_t buf[2]; + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, i2c_dev_read(dev, NULL, 0, buf, 2)); + I2C_DEV_GIVE_MUTEX(dev); + + *level = buf[0] << 8 | buf[1]; + *level = (*level * 10) / 12; // convert to LUX + + return ESP_OK; +} diff --git a/components/bh1750/bh1750.h b/components/bh1750/bh1750.h new file mode 100644 index 0000000..23f703b --- /dev/null +++ b/components/bh1750/bh1750.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017 Andrej Krutak + * Copyright (c) 2018 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file bh1750.h + * + * @defgroup bh1750 bh1750 + * @{ + * + * ESP-IDF driver for BH1750 light sensor + * + * Datasheet: ROHM Semiconductor bh1750fvi-e.pdf + * + * Ported from esp-open-rtos + * + * Copyright (c) 2017 Andrej Krutak \n + * Copyright (c) 2018 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#ifndef __BH1750_H__ +#define __BH1750_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BH1750_ADDR_LO 0x23 //!< I2C address when ADDR pin floating/low +#define BH1750_ADDR_HI 0x5c //!< I2C address when ADDR pin high + +/** + * Measurement mode + */ +typedef enum +{ + BH1750_MODE_ONE_TIME = 0, //!< One time measurement + BH1750_MODE_CONTINUOUS //!< Continuous measurement +} bh1750_mode_t; + +/** + * Measurement resolution + */ +typedef enum +{ + BH1750_RES_LOW = 0, //!< 4 lx resolution, measurement time is usually 16 ms + BH1750_RES_HIGH, //!< 1 lx resolution, measurement time is usually 120 ms + BH1750_RES_HIGH2 //!< 0.5 lx resolution, measurement time is usually 120 ms +} bh1750_resolution_t; + +/** + * @brief Initialize device descriptor + * + * @param[out] dev Device descriptor + * @param[in] addr I2C address, ::BH1750_ADDR_LO or ::BH1750_ADDR_HI + * @param[in] port I2C port number + * @param[in] sda_gpio GPIO pin number for SDA + * @param[in] scl_gpio GPIO pin number for SCL + * @return `ESP_OK` on success + */ +esp_err_t bh1750_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + +/** + * @brief Free device descriptor + * + * @param dev Pointer to device descriptor + * @return `ESP_OK` on success + */ +esp_err_t bh1750_free_desc(i2c_dev_t *dev); + +/** + * @brief Power down device + * + * @param dev Pointer to device descriptor + * @return `ESP_OK` on success + */ +esp_err_t bh1750_power_down(i2c_dev_t *dev); + +/** + * @brief Power on device + * + * @param dev Pointer to device descriptor + * @return `ESP_OK` on success + */ +esp_err_t bh1750_power_on(i2c_dev_t *dev); + +/** + * @brief Setup device parameters + * + * @param dev Pointer to device descriptor + * @param mode Measurement mode + * @param resolution Measurement resolution + * @return `ESP_OK` on success + */ +esp_err_t bh1750_setup(i2c_dev_t *dev, bh1750_mode_t mode, bh1750_resolution_t resolution); + +/** + * @brief Set measurement time + * + * @param dev Pointer to device descriptor + * @param time Measurement time (see datasheet) + * @return `ESP_OK` on success + */ +esp_err_t bh1750_set_measurement_time(i2c_dev_t *dev, uint8_t time); + +/** + * @brief Read LUX value from the device. + * + * @param dev Pointer to device descriptor + * @param[out] level read value in lux units + * @return `ESP_OK` on success + */ +esp_err_t bh1750_read(i2c_dev_t *dev, uint16_t *level); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* __BH1750_H__ */ diff --git a/components/bh1750/component.mk b/components/bh1750/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/bh1750/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/bmp280/.eil.yml b/components/bmp280/.eil.yml new file mode 100644 index 0000000..e8c48cd --- /dev/null +++ b/components/bmp280/.eil.yml @@ -0,0 +1,24 @@ +name: bmp280 +description: Driver for BMP280/BME280 digital pressure sensor +version: 1.0.0 +groups: + - pressure + - temperature +code_owners: + - UncleRus +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: MIT +copyrights: + - name: sheinz + year: 2016 + - name: UncleRus + year: 2018 diff --git a/components/bmp280/CMakeLists.txt b/components/bmp280/CMakeLists.txt new file mode 100644 index 0000000..d6fdeae --- /dev/null +++ b/components/bmp280/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS bmp280.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) diff --git a/components/bmp280/LICENSE b/components/bmp280/LICENSE new file mode 100644 index 0000000..3bed1c1 --- /dev/null +++ b/components/bmp280/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 sheinz (https://github.com/sheinz) +Copyright (c) 2018 Ruslan V. Uss (https://github.com/UncleRus) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/components/bmp280/bmp280.c b/components/bmp280/bmp280.c new file mode 100644 index 0000000..ef69299 --- /dev/null +++ b/components/bmp280/bmp280.c @@ -0,0 +1,423 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 sheinz + * Copyright (c) 2018 Ruslan V. Uss + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file bmp280.c + * + * ESP-IDF driver for BMP280/BME280 digital pressure sensor + * + * Ported from esp-open-rtos + * + * Copyright (c) 2016 sheinz \n + * Copyright (c) 2018 Ruslan V. Uss + * + * MIT Licensed as described in the file LICENSE + */ + +#include "bmp280.h" +#include +#include +#include + +#define I2C_FREQ_HZ 400000 // 400kHz // Max 1MHz for esp-idf + +static const char *TAG = "bmp280"; + +/** + * BMP280 registers + */ +#define BMP280_REG_TEMP_XLSB 0xFC /* bits: 7-4 */ +#define BMP280_REG_TEMP_LSB 0xFB +#define BMP280_REG_TEMP_MSB 0xFA +#define BMP280_REG_TEMP (BMP280_REG_TEMP_MSB) +#define BMP280_REG_PRESS_XLSB 0xF9 /* bits: 7-4 */ +#define BMP280_REG_PRESS_LSB 0xF8 +#define BMP280_REG_PRESS_MSB 0xF7 +#define BMP280_REG_PRESSURE (BMP280_REG_PRESS_MSB) +#define BMP280_REG_CONFIG 0xF5 /* bits: 7-5 t_sb; 4-2 filter; 0 spi3w_en */ +#define BMP280_REG_CTRL 0xF4 /* bits: 7-5 osrs_t; 4-2 osrs_p; 1-0 mode */ +#define BMP280_REG_STATUS 0xF3 /* bits: 3 measuring; 0 im_update */ +#define BMP280_REG_CTRL_HUM 0xF2 /* bits: 2-0 osrs_h; */ +#define BMP280_REG_RESET 0xE0 +#define BMP280_REG_ID 0xD0 +#define BMP280_REG_CALIB 0x88 +#define BMP280_REG_HUM_CALIB 0x88 + +#define BMP280_RESET_VALUE 0xB6 + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) +#define CHECK_LOGE(dev, x, msg, ...) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + { \ + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); \ + ESP_LOGE(TAG, msg, ##__VA_ARGS__); \ + return __; \ + } \ + } while (0) + +static esp_err_t read_register16(i2c_dev_t *dev, uint8_t reg, uint16_t *r) +{ + uint8_t d[] = {0, 0}; + + CHECK(i2c_dev_read_reg(dev, reg, d, 2)); + *r = d[0] | (d[1] << 8); + + return ESP_OK; +} + +inline static esp_err_t write_register8(i2c_dev_t *dev, uint8_t addr, uint8_t value) +{ + return i2c_dev_write_reg(dev, addr, &value, 1); +} + +static esp_err_t read_calibration_data(bmp280_t *dev) +{ + CHECK(read_register16(&dev->i2c_dev, 0x88, &dev->dig_T1)); + CHECK(read_register16(&dev->i2c_dev, 0x8a, (uint16_t *)&dev->dig_T2)); + CHECK(read_register16(&dev->i2c_dev, 0x8c, (uint16_t *)&dev->dig_T3)); + CHECK(read_register16(&dev->i2c_dev, 0x8e, &dev->dig_P1)); + CHECK(read_register16(&dev->i2c_dev, 0x90, (uint16_t *)&dev->dig_P2)); + CHECK(read_register16(&dev->i2c_dev, 0x92, (uint16_t *)&dev->dig_P3)); + CHECK(read_register16(&dev->i2c_dev, 0x94, (uint16_t *)&dev->dig_P4)); + CHECK(read_register16(&dev->i2c_dev, 0x96, (uint16_t *)&dev->dig_P5)); + CHECK(read_register16(&dev->i2c_dev, 0x98, (uint16_t *)&dev->dig_P6)); + CHECK(read_register16(&dev->i2c_dev, 0x9a, (uint16_t *)&dev->dig_P7)); + CHECK(read_register16(&dev->i2c_dev, 0x9c, (uint16_t *)&dev->dig_P8)); + CHECK(read_register16(&dev->i2c_dev, 0x9e, (uint16_t *)&dev->dig_P9)); + + ESP_LOGD(TAG, "Calibration data received:"); + ESP_LOGD(TAG, "dig_T1=%d", dev->dig_T1); + ESP_LOGD(TAG, "dig_T2=%d", dev->dig_T2); + ESP_LOGD(TAG, "dig_T3=%d", dev->dig_T3); + ESP_LOGD(TAG, "dig_P1=%d", dev->dig_P1); + ESP_LOGD(TAG, "dig_P2=%d", dev->dig_P2); + ESP_LOGD(TAG, "dig_P3=%d", dev->dig_P3); + ESP_LOGD(TAG, "dig_P4=%d", dev->dig_P4); + ESP_LOGD(TAG, "dig_P5=%d", dev->dig_P5); + ESP_LOGD(TAG, "dig_P6=%d", dev->dig_P6); + ESP_LOGD(TAG, "dig_P7=%d", dev->dig_P7); + ESP_LOGD(TAG, "dig_P8=%d", dev->dig_P8); + ESP_LOGD(TAG, "dig_P9=%d", dev->dig_P9); + + return ESP_OK; +} + +static esp_err_t read_hum_calibration_data(bmp280_t *dev) +{ + uint16_t h4, h5; + + CHECK(i2c_dev_read_reg(&dev->i2c_dev, 0xa1, &dev->dig_H1, 1)); + CHECK(read_register16(&dev->i2c_dev, 0xe1, (uint16_t *)&dev->dig_H2)); + CHECK(i2c_dev_read_reg(&dev->i2c_dev, 0xe3, &dev->dig_H3, 1)); + CHECK(read_register16(&dev->i2c_dev, 0xe4, &h4)); + CHECK(read_register16(&dev->i2c_dev, 0xe5, &h5)); + CHECK(i2c_dev_read_reg(&dev->i2c_dev, 0xe7, (uint8_t *)&dev->dig_H6, 1)); + + dev->dig_H4 = (h4 & 0x00ff) << 4 | (h4 & 0x0f00) >> 8; + dev->dig_H5 = h5 >> 4; + ESP_LOGD(TAG, "Calibration data received:"); + ESP_LOGD(TAG, "dig_H1=%d", dev->dig_H1); + ESP_LOGD(TAG, "dig_H2=%d", dev->dig_H2); + ESP_LOGD(TAG, "dig_H3=%d", dev->dig_H3); + ESP_LOGD(TAG, "dig_H4=%d", dev->dig_H4); + ESP_LOGD(TAG, "dig_H5=%d", dev->dig_H5); + ESP_LOGD(TAG, "dig_H6=%d", dev->dig_H6); + + return ESP_OK; +} + +esp_err_t bmp280_init_desc(bmp280_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + if (addr != BMP280_I2C_ADDRESS_0 && addr != BMP280_I2C_ADDRESS_1) + { + ESP_LOGE(TAG, "Invalid I2C address"); + return ESP_ERR_INVALID_ARG; + } + + dev->i2c_dev.port = port; + dev->i2c_dev.addr = addr; + dev->i2c_dev.cfg.sda_io_num = sda_gpio; + dev->i2c_dev.cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(&dev->i2c_dev); +} + +esp_err_t bmp280_free_desc(bmp280_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(&dev->i2c_dev); +} + +esp_err_t bmp280_init_default_params(bmp280_params_t *params) +{ + CHECK_ARG(params); + + params->mode = BMP280_MODE_NORMAL; + params->filter = BMP280_FILTER_OFF; + params->oversampling_pressure = BMP280_STANDARD; + params->oversampling_temperature = BMP280_STANDARD; + params->oversampling_humidity = BMP280_STANDARD; + params->standby = BMP280_STANDBY_250; + + return ESP_OK; +} + +esp_err_t bmp280_init(bmp280_t *dev, bmp280_params_t *params) +{ + CHECK_ARG(dev && params); + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + + CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, BMP280_REG_ID, &dev->id, 1), "Sensor not found"); + + if (dev->id != BMP280_CHIP_ID && dev->id != BME280_CHIP_ID) + { + CHECK_LOGE(dev, ESP_ERR_INVALID_VERSION, + "Invalid chip ID: expected: 0x%x (BME280) or 0x%x (BMP280) got: 0x%x", + BME280_CHIP_ID, BMP280_CHIP_ID, dev->id); + } + + // Soft reset. + CHECK_LOGE(dev, write_register8(&dev->i2c_dev, BMP280_REG_RESET, BMP280_RESET_VALUE), "Failed to reset sensor"); + + // Wait until finished copying over the NVP data. + while (1) + { + uint8_t status; + if (!i2c_dev_read_reg(&dev->i2c_dev, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0) + break; + } + + CHECK_LOGE(dev, read_calibration_data(dev), "Failed to read calibration data"); + + if (dev->id == BME280_CHIP_ID) + { + CHECK_LOGE(dev, read_hum_calibration_data(dev), "Failed to read humidity calibration data"); + } + + uint8_t config = (params->standby << 5) | (params->filter << 2); + ESP_LOGD(TAG, "Writing config reg=%x", config); + + CHECK_LOGE(dev, write_register8(&dev->i2c_dev, BMP280_REG_CONFIG, config), "Failed to configure sensor"); + + if (params->mode == BMP280_MODE_FORCED) + { + params->mode = BMP280_MODE_SLEEP; // initial mode for forced is sleep + } + + uint8_t ctrl = (params->oversampling_temperature << 5) | (params->oversampling_pressure << 2) | (params->mode); + + if (dev->id == BME280_CHIP_ID) + { + // Write crtl hum reg first, only active after write to BMP280_REG_CTRL. + uint8_t ctrl_hum = params->oversampling_humidity; + ESP_LOGD(TAG, "Writing ctrl hum reg=%x", ctrl_hum); + CHECK_LOGE(dev, write_register8(&dev->i2c_dev, BMP280_REG_CTRL_HUM, ctrl_hum), "Failed to control sensor"); + } + + ESP_LOGD(TAG, "Writing ctrl reg=%x", ctrl); + CHECK_LOGE(dev, write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl), "Failed to control sensor"); + + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t bmp280_force_measurement(bmp280_t *dev) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + + uint8_t ctrl; + I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_read_reg(&dev->i2c_dev, BMP280_REG_CTRL, &ctrl, 1)); + ctrl &= ~0b11; // clear two lower bits + ctrl |= BMP280_MODE_FORCED; + ESP_LOGD(TAG, "Writing ctrl reg=%x", ctrl); + CHECK_LOGE(dev, write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl), "Failed to start forced mode"); + + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t bmp280_is_measuring(bmp280_t *dev, bool *busy) +{ + CHECK_ARG(dev && busy); + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + + const uint8_t regs[2] = {BMP280_REG_STATUS, BMP280_REG_CTRL}; + uint8_t status[2]; + CHECK_LOGE(dev, i2c_dev_read(&dev->i2c_dev, regs, 2, status, 2), "Failed to read status registers"); + + // Check mode - FORCED means BM280 is busy (it switches to SLEEP mode when finished) + // Additionally, check 'measuring' bit in status register + *busy = ((status[1] & 0b11) == BMP280_MODE_FORCED) || (status[0] & (1 << 3)); + + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +/** + * Compensation algorithm is taken from BMP280 datasheet. + * + * Return value is in degrees Celsius. + */ +static inline int32_t compensate_temperature(bmp280_t *dev, int32_t adc_temp, int32_t *fine_temp) +{ + int32_t var1, var2; + + var1 = ((((adc_temp >> 3) - ((int32_t)dev->dig_T1 << 1))) * (int32_t)dev->dig_T2) >> 11; + var2 = (((((adc_temp >> 4) - (int32_t)dev->dig_T1) * ((adc_temp >> 4) - (int32_t)dev->dig_T1)) >> 12) * (int32_t)dev->dig_T3) >> 14; + + *fine_temp = var1 + var2; + return (*fine_temp * 5 + 128) >> 8; +} + +/** + * Compensation algorithm is taken from BMP280 datasheet. + * + * Return value is in Pa, 24 integer bits and 8 fractional bits. + */ +static inline uint32_t compensate_pressure(bmp280_t *dev, int32_t adc_press, int32_t fine_temp) +{ + int64_t var1, var2, p; + + var1 = (int64_t)fine_temp - 128000; + var2 = var1 * var1 * (int64_t)dev->dig_P6; + var2 = var2 + ((var1 * (int64_t)dev->dig_P5) << 17); + var2 = var2 + (((int64_t)dev->dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)dev->dig_P3) >> 8) + ((var1 * (int64_t)dev->dig_P2) << 12); + var1 = (((int64_t)1 << 47) + var1) * ((int64_t)dev->dig_P1) >> 33; + + if (var1 == 0) + { + return 0; // avoid exception caused by division by zero + } + + p = 1048576 - adc_press; + p = (((p << 31) - var2) * 3125) / var1; + var1 = ((int64_t)dev->dig_P9 * (p >> 13) * (p >> 13)) >> 25; + var2 = ((int64_t)dev->dig_P8 * p) >> 19; + + p = ((p + var1 + var2) >> 8) + ((int64_t)dev->dig_P7 << 4); + return p; +} + +/** + * Compensation algorithm is taken from BME280 datasheet. + * + * Return value is in Pa, 24 integer bits and 8 fractional bits. + */ +static inline uint32_t compensate_humidity(bmp280_t *dev, int32_t adc_hum, int32_t fine_temp) +{ + int32_t v_x1_u32r; + + v_x1_u32r = fine_temp - (int32_t)76800; + v_x1_u32r = ((((adc_hum << 14) - ((int32_t)dev->dig_H4 << 20) - ((int32_t)dev->dig_H5 * v_x1_u32r)) + (int32_t)16384) >> 15) * (((((((v_x1_u32r * (int32_t)dev->dig_H6) >> 10) * (((v_x1_u32r * (int32_t)dev->dig_H3) >> 11) + (int32_t)32768)) >> 10) + (int32_t)2097152) * (int32_t)dev->dig_H2 + 8192) >> 14); + v_x1_u32r = v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * (int32_t)dev->dig_H1) >> 4); + v_x1_u32r = v_x1_u32r < 0 ? 0 : v_x1_u32r; + v_x1_u32r = v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r; + return v_x1_u32r >> 12; +} + +esp_err_t bmp280_read_fixed(bmp280_t *dev, int32_t *temperature, uint32_t *pressure, uint32_t *humidity) +{ + CHECK_ARG(dev && temperature && pressure); + + int32_t adc_pressure; + int32_t adc_temp; + uint8_t data[8]; + + // Only the BME280 supports reading the humidity. + if (dev->id != BME280_CHIP_ID) + { + if (humidity) + *humidity = 0; + humidity = NULL; + } + + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + + // Need to read in one sequence to ensure they match. + size_t size = humidity ? 8 : 6; + CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, 0xf7, data, size), "Failed to read data"); + + adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4; + adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4; + ESP_LOGD(TAG, "ADC temperature: %" PRIi32, adc_temp); + ESP_LOGD(TAG, "ADC pressure: %" PRIi32, adc_pressure); + + int32_t fine_temp; + *temperature = compensate_temperature(dev, adc_temp, &fine_temp); + *pressure = compensate_pressure(dev, adc_pressure, fine_temp); + + if (humidity) + { + int32_t adc_humidity = data[6] << 8 | data[7]; + ESP_LOGD(TAG, "ADC humidity: %" PRIi32, adc_humidity); + *humidity = compensate_humidity(dev, adc_humidity, fine_temp); + } + + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t bmp280_read_float(bmp280_t *dev, float *temperature, float *pressure, float *humidity) +{ + int32_t fixed_temperature; + uint32_t fixed_pressure; + uint32_t fixed_humidity; + CHECK(bmp280_read_fixed(dev, &fixed_temperature, &fixed_pressure, humidity ? &fixed_humidity : NULL)); + *temperature = (float)fixed_temperature / 100; + *pressure = (float)fixed_pressure / 256; + if (humidity) + *humidity = (float)fixed_humidity / 1024; + + return ESP_OK; +} diff --git a/components/bmp280/bmp280.h b/components/bmp280/bmp280.h new file mode 100644 index 0000000..051f1f9 --- /dev/null +++ b/components/bmp280/bmp280.h @@ -0,0 +1,250 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 sheinz + * Copyright (c) 2018 Ruslan V. Uss + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file bmp280.h + * @defgroup bmp280 bmp280 + * @{ + * + * ESP-IDF driver for BMP280/BME280 digital pressure sensor + * + * Ported from esp-open-rtos + * + * Copyright (c) 2016 sheinz \n + * Copyright (c) 2018 Ruslan V. Uss + * + * MIT Licensed as described in the file LICENSE + */ +#ifndef __BMP280_H__ +#define __BMP280_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BMP280_I2C_ADDRESS_0 0x76 //!< I2C address when SDO pin is low +#define BMP280_I2C_ADDRESS_1 0x77 //!< I2C address when SDO pin is high + +#define BMP280_CHIP_ID 0x58 //!< BMP280 has chip-id 0x58 +#define BME280_CHIP_ID 0x60 //!< BME280 has chip-id 0x60 + +/** + * Mode of BMP280 module operation. + */ +typedef enum { + BMP280_MODE_SLEEP = 0, //!< Sleep mode + BMP280_MODE_FORCED = 1, //!< Measurement is initiated by user + BMP280_MODE_NORMAL = 3 //!< Continues measurement +} BMP280_Mode; + +typedef enum { + BMP280_FILTER_OFF = 0, + BMP280_FILTER_2 = 1, + BMP280_FILTER_4 = 2, + BMP280_FILTER_8 = 3, + BMP280_FILTER_16 = 4 +} BMP280_Filter; + +/** + * Pressure oversampling settings + */ +typedef enum { + BMP280_SKIPPED = 0, //!< no measurement + BMP280_ULTRA_LOW_POWER = 1, //!< oversampling x1 + BMP280_LOW_POWER = 2, //!< oversampling x2 + BMP280_STANDARD = 3, //!< oversampling x4 + BMP280_HIGH_RES = 4, //!< oversampling x8 + BMP280_ULTRA_HIGH_RES = 5 //!< oversampling x16 +} BMP280_Oversampling; + +/** + * Stand by time between measurements in normal mode + */ +typedef enum { + BMP280_STANDBY_05 = 0, //!< stand by time 0.5ms + BMP280_STANDBY_62 = 1, //!< stand by time 62.5ms + BMP280_STANDBY_125 = 2, //!< stand by time 125ms + BMP280_STANDBY_250 = 3, //!< stand by time 250ms + BMP280_STANDBY_500 = 4, //!< stand by time 500ms + BMP280_STANDBY_1000 = 5, //!< stand by time 1s + BMP280_STANDBY_2000 = 6, //!< stand by time 2s BMP280, 10ms BME280 + BMP280_STANDBY_4000 = 7, //!< stand by time 4s BMP280, 20ms BME280 +} BMP280_StandbyTime; + +/** + * Configuration parameters for BMP280 module. + * Use function ::bmp280_init_default_params() to use default configuration. + */ +typedef struct { + BMP280_Mode mode; + BMP280_Filter filter; + BMP280_Oversampling oversampling_pressure; + BMP280_Oversampling oversampling_temperature; + BMP280_Oversampling oversampling_humidity; + BMP280_StandbyTime standby; +} bmp280_params_t; + +/** + * Device descriptor + */ +typedef struct { + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + + /* Humidity compensation for BME280 */ + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; + + i2c_dev_t i2c_dev; //!< I2C device descriptor + uint8_t id; //!< Chip ID +} bmp280_t; + +/** + * @brief Initialize device descriptor + * + * @param dev Device descriptor + * @param addr BMP280 address + * @param port I2C port number + * @param sda_gpio GPIO pin for SDA + * @param scl_gpio GPIO pin for SCL + * @return `ESP_OK` on success + */ +esp_err_t bmp280_init_desc(bmp280_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + +/** + * @brief Free device descriptor + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t bmp280_free_desc(bmp280_t *dev); + +/** + * @brief Initialize default parameters + * + * Default configuration: + * + * - mode: NORMAL + * - filter: OFF + * - oversampling: x4 + * - standby time: 250ms + * + * @param[out] params Default parameters + * @return `ESP_OK` on success + */ +esp_err_t bmp280_init_default_params(bmp280_params_t *params); + +/** + * @brief Initialize BMP280 module + * + * Probes for the device, soft resets the device, reads the calibration + * constants, and configures the device using the supplied parameters. + * + * This may be called again to soft reset the device and initialize it again. + * + * @param dev Device descriptor + * @param params Parameters + * @return `ESP_OK` on success + */ +esp_err_t bmp280_init(bmp280_t *dev, bmp280_params_t *params); + +/** + * @brief Start measurement in forced mode + * + * The module remains in forced mode after this call. + * Do not call this method in normal mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t bmp280_force_measurement(bmp280_t *dev); + +/** + * @brief Check if BMP280 is busy + * + * @param dev Device descriptor + * @param[out] busy true if BMP280 measures temperature/pressure + * @return `ESP_OK` on success + */ +esp_err_t bmp280_is_measuring(bmp280_t *dev, bool *busy); + +/** + * @brief Read raw compensated temperature and pressure data + * + * Temperature in degrees Celsius times 100. + * + * Pressure in Pascals in fixed point 24 bit integer 8 bit fraction format. + * + * Humidity is optional and only read for the BME280, in percent relative + * humidity as a fixed point 22 bit integer and 10 bit fraction format. + * + * @param dev Device descriptor + * @param[out] temperature Temperature, deg.C * 100 + * @param[out] pressure Pressure + * @param[out] humidity Humidity, optional + * @return `ESP_OK` on success + */ +esp_err_t bmp280_read_fixed(bmp280_t *dev, int32_t *temperature, + uint32_t *pressure, uint32_t *humidity); + +/** + * @brief Read compensated temperature and pressure data + * + * Humidity is optional and only read for the BME280. + * + * @param dev Device descriptor + * @param[out] temperature Temperature, deg.C + * @param[out] pressure Pressure, Pascal + * @param[out] humidity Relative humidity, percents (optional) + * @return `ESP_OK` on success + */ +esp_err_t bmp280_read_float(bmp280_t *dev, float *temperature, + float *pressure, float *humidity); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif // __BMP280_H__ diff --git a/components/bmp280/component.mk b/components/bmp280/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/bmp280/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/esp_idf_lib_helpers/.eil.yml b/components/esp_idf_lib_helpers/.eil.yml new file mode 100644 index 0000000..eb4f9e0 --- /dev/null +++ b/components/esp_idf_lib_helpers/.eil.yml @@ -0,0 +1,20 @@ +name: esp_idf_lib_helpers +description: Common support library for esp-idf-lib +version: 1.2.0 +groups: + - common +code_owners: + - trombik + - UncleRus +depends: + - freertos +thread_safe: n/a +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: ISC +copyrights: + - name: trombik + year: 2019 diff --git a/components/esp_idf_lib_helpers/CMakeLists.txt b/components/esp_idf_lib_helpers/CMakeLists.txt new file mode 100644 index 0000000..44bd43a --- /dev/null +++ b/components/esp_idf_lib_helpers/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register( + INCLUDE_DIRS . + REQUIRES freertos +) diff --git a/components/esp_idf_lib_helpers/LICENSE b/components/esp_idf_lib_helpers/LICENSE new file mode 100644 index 0000000..f81d3d2 --- /dev/null +++ b/components/esp_idf_lib_helpers/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2019 Tomoyuki Sakurai + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/components/esp_idf_lib_helpers/component.mk b/components/esp_idf_lib_helpers/component.mk new file mode 100644 index 0000000..c03a32e --- /dev/null +++ b/components/esp_idf_lib_helpers/component.mk @@ -0,0 +1,8 @@ +COMPONENT_ADD_INCLUDEDIRS = . + +ifdef CONFIG_IDF_TARGET_ESP8266 +COMPONENT_DEPENDS = esp8266 freertos +else +COMPONENT_DEPENDS = freertos +endif + diff --git a/components/esp_idf_lib_helpers/esp_idf_lib_helpers.h b/components/esp_idf_lib_helpers/esp_idf_lib_helpers.h new file mode 100644 index 0000000..2c74e3b --- /dev/null +++ b/components/esp_idf_lib_helpers/esp_idf_lib_helpers.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 Tomoyuki Sakurai + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__ESP_IDF_LIB_HELPERS__H__) +#define __ESP_IDF_LIB_HELPERS__H__ + +/* XXX this header file does not need to include freertos/FreeRTOS.h. + * but without it, ESP8266 RTOS SDK does not include `sdkconfig.h` in correct + * order. as this header depends on sdkconfig.h, sdkconfig.h must be included + * first. however, the SDK includes this header first, then includes + * `sdkconfig.h` when freertos/FreeRTOS.h is not explicitly included. an + * evidence can be found in `build/${COMPONENT}/${COMPONENT}.d` in a failed + * build. + */ +#include +#include + +#if !defined(ESP_IDF_VERSION) || !defined(ESP_IDF_VERSION_VAL) +#error Unknown ESP-IDF/ESP8266 RTOS SDK version +#endif + +/* Minimal supported version for ESP32, ESP32S2 */ +#define HELPER_ESP32_MIN_VER ESP_IDF_VERSION_VAL(3, 3, 5) +/* Minimal supported version for ESP8266 */ +#define HELPER_ESP8266_MIN_VER ESP_IDF_VERSION_VAL(3, 3, 0) + +/* HELPER_TARGET_IS_ESP32 + * 1 when the target is esp32 + */ +#if defined(CONFIG_IDF_TARGET_ESP32) \ + || defined(CONFIG_IDF_TARGET_ESP32S2) \ + || defined(CONFIG_IDF_TARGET_ESP32S3) \ + || defined(CONFIG_IDF_TARGET_ESP32C2) \ + || defined(CONFIG_IDF_TARGET_ESP32C3) \ + || defined(CONFIG_IDF_TARGET_ESP32C6) \ + || defined(CONFIG_IDF_TARGET_ESP32H2) +#define HELPER_TARGET_IS_ESP32 (1) +#define HELPER_TARGET_IS_ESP8266 (0) + +/* HELPER_TARGET_IS_ESP8266 + * 1 when the target is esp8266 + */ +#elif defined(CONFIG_IDF_TARGET_ESP8266) +#define HELPER_TARGET_IS_ESP32 (0) +#define HELPER_TARGET_IS_ESP8266 (1) +#else +#error BUG: cannot determine the target +#endif + +#if HELPER_TARGET_IS_ESP32 && ESP_IDF_VERSION < HELPER_ESP32_MIN_VER +#error Unsupported ESP-IDF version. Please update! +#endif + +#if HELPER_TARGET_IS_ESP8266 && ESP_IDF_VERSION < HELPER_ESP8266_MIN_VER +#error Unsupported ESP8266 RTOS SDK version. Please update! +#endif + +/* show the actual values for debugging */ +#if DEBUG +#define VALUE_TO_STRING(x) #x +#define VALUE(x) VALUE_TO_STRING(x) +#define VAR_NAME_VALUE(var) #var "=" VALUE(var) +#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32C3)) +#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32H2)) +#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32S2)) +#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32)) +#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP8266)) +#pragma message(VAR_NAME_VALUE(ESP_IDF_VERSION_MAJOR)) +#endif + +#endif diff --git a/components/esp_idf_lib_helpers/ets_sys.h b/components/esp_idf_lib_helpers/ets_sys.h new file mode 100644 index 0000000..eb83481 --- /dev/null +++ b/components/esp_idf_lib_helpers/ets_sys.h @@ -0,0 +1,21 @@ +#if CONFIG_IDF_TARGET_ESP32 +#include +#elif CONFIG_IDF_TARGET_ESP32C2 +#include +#elif CONFIG_IDF_TARGET_ESP32C3 +#include +#elif CONFIG_IDF_TARGET_ESP32C6 +#include +#elif CONFIG_IDF_TARGET_ESP32H2 +#include +#elif CONFIG_IDF_TARGET_ESP32H4 +#include +#elif CONFIG_IDF_TARGET_ESP32S2 +#include +#elif CONFIG_IDF_TARGET_ESP32S3 +#include +#elif CONFIG_IDF_TARGET_ESP8266 +#include +#else +#error "ets_sys: Unknown target" +#endif diff --git a/components/i2cdev/.eil.yml b/components/i2cdev/.eil.yml new file mode 100644 index 0000000..10c8abb --- /dev/null +++ b/components/i2cdev/.eil.yml @@ -0,0 +1,21 @@ +name: i2cdev +description: ESP-IDF I2C master thread-safe utilities +version: 1.5.0 +groups: + - common +code_owners: + - UncleRus +depends: + - driver + - freertos + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: MIT +copyrights: + - name: UncleRus + year: 2018 diff --git a/components/i2cdev/CMakeLists.txt b/components/i2cdev/CMakeLists.txt new file mode 100644 index 0000000..585cfb2 --- /dev/null +++ b/components/i2cdev/CMakeLists.txt @@ -0,0 +1,11 @@ +if(${IDF_TARGET} STREQUAL esp8266) + set(req esp8266 freertos esp_idf_lib_helpers) +else() + set(req driver freertos esp_idf_lib_helpers) +endif() + +idf_component_register( + SRCS i2cdev.c + INCLUDE_DIRS . + REQUIRES ${req} +) diff --git a/components/i2cdev/Kconfig b/components/i2cdev/Kconfig new file mode 100644 index 0000000..aaff31d --- /dev/null +++ b/components/i2cdev/Kconfig @@ -0,0 +1,17 @@ +menu "I2C" + +config I2CDEV_TIMEOUT + int "I2C transaction timeout, milliseconds" + default 1000 + range 10 5000 + +config I2CDEV_NOLOCK + bool "Disable the use of mutexes" + default n + help + Attention! After enabling this option, all I2C device + drivers will become non-thread safe. + Use this option if you need to access your I2C devices + from interrupt handlers. + +endmenu \ No newline at end of file diff --git a/components/i2cdev/LICENSE b/components/i2cdev/LICENSE new file mode 100644 index 0000000..d546673 --- /dev/null +++ b/components/i2cdev/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Ruslan V. Uss (https://github.com/UncleRus) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/components/i2cdev/component.mk b/components/i2cdev/component.mk new file mode 100644 index 0000000..877b269 --- /dev/null +++ b/components/i2cdev/component.mk @@ -0,0 +1,7 @@ +COMPONENT_ADD_INCLUDEDIRS = . + +ifdef CONFIG_IDF_TARGET_ESP8266 +COMPONENT_DEPENDS = esp8266 freertos esp_idf_lib_helpers +else +COMPONENT_DEPENDS = driver freertos esp_idf_lib_helpers +endif diff --git a/components/i2cdev/i2cdev.c b/components/i2cdev/i2cdev.c new file mode 100644 index 0000000..7f1bba2 --- /dev/null +++ b/components/i2cdev/i2cdev.c @@ -0,0 +1,340 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ruslan V. Uss + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file i2cdev.c + * + * ESP-IDF I2C master thread-safe functions for communication with I2C slave + * + * Copyright (c) 2018 Ruslan V. Uss + * + * MIT Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include +#include "i2cdev.h" + +static const char *TAG = "i2cdev"; + +typedef struct { + SemaphoreHandle_t lock; + i2c_config_t config; + bool installed; +} i2c_port_state_t; + +static i2c_port_state_t states[I2C_NUM_MAX]; + +#if CONFIG_I2CDEV_NOLOCK +#define SEMAPHORE_TAKE(port) +#else +#define SEMAPHORE_TAKE(port) do { \ + if (!xSemaphoreTake(states[port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT))) \ + { \ + ESP_LOGE(TAG, "Could not take port mutex %d", port); \ + return ESP_ERR_TIMEOUT; \ + } \ + } while (0) +#endif + +#if CONFIG_I2CDEV_NOLOCK +#define SEMAPHORE_GIVE(port) +#else +#define SEMAPHORE_GIVE(port) do { \ + if (!xSemaphoreGive(states[port].lock)) \ + { \ + ESP_LOGE(TAG, "Could not give port mutex %d", port); \ + return ESP_FAIL; \ + } \ + } while (0) +#endif + +esp_err_t i2cdev_init() +{ + memset(states, 0, sizeof(states)); + +#if !CONFIG_I2CDEV_NOLOCK + for (int i = 0; i < I2C_NUM_MAX; i++) + { + states[i].lock = xSemaphoreCreateMutex(); + if (!states[i].lock) + { + ESP_LOGE(TAG, "Could not create port mutex %d", i); + return ESP_FAIL; + } + } +#endif + + return ESP_OK; +} + +esp_err_t i2cdev_done() +{ + for (int i = 0; i < I2C_NUM_MAX; i++) + { + if (!states[i].lock) continue; + + if (states[i].installed) + { + SEMAPHORE_TAKE(i); + i2c_driver_delete(i); + states[i].installed = false; + SEMAPHORE_GIVE(i); + } +#if !CONFIG_I2CDEV_NOLOCK + vSemaphoreDelete(states[i].lock); +#endif + states[i].lock = NULL; + } + return ESP_OK; +} + +esp_err_t i2c_dev_create_mutex(i2c_dev_t *dev) +{ +#if !CONFIG_I2CDEV_NOLOCK + if (!dev) return ESP_ERR_INVALID_ARG; + + ESP_LOGV(TAG, "[0x%02x at %d] creating mutex", dev->addr, dev->port); + + dev->mutex = xSemaphoreCreateMutex(); + if (!dev->mutex) + { + ESP_LOGE(TAG, "[0x%02x at %d] Could not create device mutex", dev->addr, dev->port); + return ESP_FAIL; + } +#endif + + return ESP_OK; +} + +esp_err_t i2c_dev_delete_mutex(i2c_dev_t *dev) +{ +#if !CONFIG_I2CDEV_NOLOCK + if (!dev) return ESP_ERR_INVALID_ARG; + + ESP_LOGV(TAG, "[0x%02x at %d] deleting mutex", dev->addr, dev->port); + + vSemaphoreDelete(dev->mutex); +#endif + return ESP_OK; +} + +esp_err_t i2c_dev_take_mutex(i2c_dev_t *dev) +{ +#if !CONFIG_I2CDEV_NOLOCK + if (!dev) return ESP_ERR_INVALID_ARG; + + ESP_LOGV(TAG, "[0x%02x at %d] taking mutex", dev->addr, dev->port); + + if (!xSemaphoreTake(dev->mutex, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT))) + { + ESP_LOGE(TAG, "[0x%02x at %d] Could not take device mutex", dev->addr, dev->port); + return ESP_ERR_TIMEOUT; + } +#endif + return ESP_OK; +} + +esp_err_t i2c_dev_give_mutex(i2c_dev_t *dev) +{ +#if !CONFIG_I2CDEV_NOLOCK + if (!dev) return ESP_ERR_INVALID_ARG; + + ESP_LOGV(TAG, "[0x%02x at %d] giving mutex", dev->addr, dev->port); + + if (!xSemaphoreGive(dev->mutex)) + { + ESP_LOGE(TAG, "[0x%02x at %d] Could not give device mutex", dev->addr, dev->port); + return ESP_FAIL; + } +#endif + return ESP_OK; +} + +inline static bool cfg_equal(const i2c_config_t *a, const i2c_config_t *b) +{ + return a->scl_io_num == b->scl_io_num + && a->sda_io_num == b->sda_io_num +#if HELPER_TARGET_IS_ESP32 + && a->master.clk_speed == b->master.clk_speed +#elif HELPER_TARGET_IS_ESP8266 + && ((a->clk_stretch_tick && a->clk_stretch_tick == b->clk_stretch_tick) + || (!a->clk_stretch_tick && b->clk_stretch_tick == I2CDEV_MAX_STRETCH_TIME) + ) // see line 232 +#endif + && a->scl_pullup_en == b->scl_pullup_en + && a->sda_pullup_en == b->sda_pullup_en; +} + +static esp_err_t i2c_setup_port(const i2c_dev_t *dev) +{ + if (dev->port >= I2C_NUM_MAX) return ESP_ERR_INVALID_ARG; + + esp_err_t res; + if (!cfg_equal(&dev->cfg, &states[dev->port].config) || !states[dev->port].installed) + { + ESP_LOGD(TAG, "Reconfiguring I2C driver on port %d", dev->port); + i2c_config_t temp; + memcpy(&temp, &dev->cfg, sizeof(i2c_config_t)); + temp.mode = I2C_MODE_MASTER; + + // Driver reinstallation + if (states[dev->port].installed) + { + i2c_driver_delete(dev->port); + states[dev->port].installed = false; + } +#if HELPER_TARGET_IS_ESP32 +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) + // See https://github.com/espressif/esp-idf/issues/10163 + if ((res = i2c_driver_install(dev->port, temp.mode, 0, 0, 0)) != ESP_OK) + return res; + if ((res = i2c_param_config(dev->port, &temp)) != ESP_OK) + return res; +#else + if ((res = i2c_param_config(dev->port, &temp)) != ESP_OK) + return res; + if ((res = i2c_driver_install(dev->port, temp.mode, 0, 0, 0)) != ESP_OK) + return res; +#endif +#endif +#if HELPER_TARGET_IS_ESP8266 + // Clock Stretch time, depending on CPU frequency + temp.clk_stretch_tick = dev->timeout_ticks ? dev->timeout_ticks : I2CDEV_MAX_STRETCH_TIME; + if ((res = i2c_driver_install(dev->port, temp.mode)) != ESP_OK) + return res; + if ((res = i2c_param_config(dev->port, &temp)) != ESP_OK) + return res; +#endif + states[dev->port].installed = true; + + memcpy(&states[dev->port].config, &temp, sizeof(i2c_config_t)); + ESP_LOGD(TAG, "I2C driver successfully reconfigured on port %d", dev->port); + } +#if HELPER_TARGET_IS_ESP32 + int t; + if ((res = i2c_get_timeout(dev->port, &t)) != ESP_OK) + return res; + // Timeout cannot be 0 + uint32_t ticks = dev->timeout_ticks ? dev->timeout_ticks : I2CDEV_MAX_STRETCH_TIME; + if ((ticks != t) && (res = i2c_set_timeout(dev->port, ticks)) != ESP_OK) + return res; + ESP_LOGD(TAG, "Timeout: ticks = %" PRIu32 " (%" PRIu32 " usec) on port %d", dev->timeout_ticks, dev->timeout_ticks / 80, dev->port); +#endif + + return ESP_OK; +} + +esp_err_t i2c_dev_probe(const i2c_dev_t *dev, i2c_dev_type_t operation_type) +{ + if (!dev) return ESP_ERR_INVALID_ARG; + + SEMAPHORE_TAKE(dev->port); + + esp_err_t res = i2c_setup_port(dev); + if (res == ESP_OK) + { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, dev->addr << 1 | (operation_type == I2C_DEV_READ ? 1 : 0), true); + i2c_master_stop(cmd); + + res = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)); + + i2c_cmd_link_delete(cmd); + } + + SEMAPHORE_GIVE(dev->port); + + return res; +} + +esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, size_t out_size, void *in_data, size_t in_size) +{ + if (!dev || !in_data || !in_size) return ESP_ERR_INVALID_ARG; + + SEMAPHORE_TAKE(dev->port); + + esp_err_t res = i2c_setup_port(dev); + if (res == ESP_OK) + { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + if (out_data && out_size) + { + i2c_master_start(cmd); + i2c_master_write_byte(cmd, dev->addr << 1, true); + i2c_master_write(cmd, (void *)out_data, out_size, true); + } + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (dev->addr << 1) | 1, true); + i2c_master_read(cmd, in_data, in_size, I2C_MASTER_LAST_NACK); + i2c_master_stop(cmd); + + res = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)); + if (res != ESP_OK) + ESP_LOGE(TAG, "Could not read from device [0x%02x at %d]: %d (%s)", dev->addr, dev->port, res, esp_err_to_name(res)); + + i2c_cmd_link_delete(cmd); + } + + SEMAPHORE_GIVE(dev->port); + return res; +} + +esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, size_t out_reg_size, const void *out_data, size_t out_size) +{ + if (!dev || !out_data || !out_size) return ESP_ERR_INVALID_ARG; + + SEMAPHORE_TAKE(dev->port); + + esp_err_t res = i2c_setup_port(dev); + if (res == ESP_OK) + { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, dev->addr << 1, true); + if (out_reg && out_reg_size) + i2c_master_write(cmd, (void *)out_reg, out_reg_size, true); + i2c_master_write(cmd, (void *)out_data, out_size, true); + i2c_master_stop(cmd); + res = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)); + if (res != ESP_OK) + ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->addr, dev->port, res, esp_err_to_name(res)); + i2c_cmd_link_delete(cmd); + } + + SEMAPHORE_GIVE(dev->port); + return res; +} + +esp_err_t i2c_dev_read_reg(const i2c_dev_t *dev, uint8_t reg, void *in_data, size_t in_size) +{ + return i2c_dev_read(dev, ®, 1, in_data, in_size); +} + +esp_err_t i2c_dev_write_reg(const i2c_dev_t *dev, uint8_t reg, const void *out_data, size_t out_size) +{ + return i2c_dev_write(dev, ®, 1, out_data, out_size); +} diff --git a/components/i2cdev/i2cdev.h b/components/i2cdev/i2cdev.h new file mode 100644 index 0000000..ce972a6 --- /dev/null +++ b/components/i2cdev/i2cdev.h @@ -0,0 +1,251 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ruslan V. Uss + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file i2cdev.h + * @defgroup i2cdev i2cdev + * @{ + * + * ESP-IDF I2C master thread-safe functions for communication with I2C slave + * + * Copyright (c) 2018 Ruslan V. Uss + * + * MIT Licensed as described in the file LICENSE + */ +#ifndef __I2CDEV_H__ +#define __I2CDEV_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if HELPER_TARGET_IS_ESP8266 + +#define I2CDEV_MAX_STRETCH_TIME 0xffffffff + +#else + +#include +#if defined(I2C_TIME_OUT_VALUE_V) +#define I2CDEV_MAX_STRETCH_TIME I2C_TIME_OUT_VALUE_V +#elif defined(I2C_TIME_OUT_REG_V) +#define I2CDEV_MAX_STRETCH_TIME I2C_TIME_OUT_REG_V +#else +#define I2CDEV_MAX_STRETCH_TIME 0x00ffffff +#endif + +#endif /* HELPER_TARGET_IS_ESP8266 */ + +/** + * I2C device descriptor + */ +typedef struct +{ + i2c_port_t port; //!< I2C port number + i2c_config_t cfg; //!< I2C driver configuration + uint8_t addr; //!< Unshifted address + SemaphoreHandle_t mutex; //!< Device mutex + uint32_t timeout_ticks; /*!< HW I2C bus timeout (stretch time), in ticks. 80MHz APB clock + ticks for ESP-IDF, CPU ticks for ESP8266. + When this value is 0, I2CDEV_MAX_STRETCH_TIME will be used */ +} i2c_dev_t; + +/** + * I2C transaction type + */ +typedef enum { + I2C_DEV_WRITE = 0, /**< Write operation */ + I2C_DEV_READ /**< Read operation */ +} i2c_dev_type_t; + +/** + * @brief Init library + * + * The function must be called before any other + * functions of this library. + * + * @return ESP_OK on success + */ +esp_err_t i2cdev_init(); + +/** + * @brief Finish work with library + * + * Uninstall i2c drivers. + * + * @return ESP_OK on success + */ +esp_err_t i2cdev_done(); + +/** + * @brief Create mutex for device descriptor + * + * This function does nothing if option CONFIG_I2CDEV_NOLOCK is enabled. + * + * @param dev Device descriptor + * @return ESP_OK on success + */ +esp_err_t i2c_dev_create_mutex(i2c_dev_t *dev); + +/** + * @brief Delete mutex for device descriptor + * + * This function does nothing if option CONFIG_I2CDEV_NOLOCK is enabled. + * + * @param dev Device descriptor + * @return ESP_OK on success + */ +esp_err_t i2c_dev_delete_mutex(i2c_dev_t *dev); + +/** + * @brief Take device mutex + * + * This function does nothing if option CONFIG_I2CDEV_NOLOCK is enabled. + * + * @param dev Device descriptor + * @return ESP_OK on success + */ +esp_err_t i2c_dev_take_mutex(i2c_dev_t *dev); + +/** + * @brief Give device mutex + * + * This function does nothing if option CONFIG_I2CDEV_NOLOCK is enabled. + * + * @param dev Device descriptor + * @return ESP_OK on success + */ +esp_err_t i2c_dev_give_mutex(i2c_dev_t *dev); + +/** + * @brief Check the availability of the device + * + * Issue an operation of \p operation_type to the I2C device then stops. + * + * @param dev Device descriptor + * @param operation_type Operation type + * @return ESP_OK if device is available + */ +esp_err_t i2c_dev_probe(const i2c_dev_t *dev, i2c_dev_type_t operation_type); + +/** + * @brief Read from slave device + * + * Issue a send operation of \p out_data register address, followed by reading \p in_size bytes + * from slave into \p in_data . + * Function is thread-safe. + * + * @param dev Device descriptor + * @param out_data Pointer to data to send if non-null + * @param out_size Size of data to send + * @param[out] in_data Pointer to input data buffer + * @param in_size Number of byte to read + * @return ESP_OK on success + */ +esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, + size_t out_size, void *in_data, size_t in_size); + +/** + * @brief Write to slave device + * + * Write \p out_size bytes from \p out_data to slave into \p out_reg register address. + * Function is thread-safe. + * + * @param dev Device descriptor + * @param out_reg Pointer to register address to send if non-null + * @param out_reg_size Size of register address + * @param out_data Pointer to data to send + * @param out_size Size of data to send + * @return ESP_OK on success + */ +esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, + size_t out_reg_size, const void *out_data, size_t out_size); + +/** + * @brief Read from register with an 8-bit address + * + * Shortcut to ::i2c_dev_read(). + * + * @param dev Device descriptor + * @param reg Register address + * @param[out] in_data Pointer to input data buffer + * @param in_size Number of byte to read + * @return ESP_OK on success + */ +esp_err_t i2c_dev_read_reg(const i2c_dev_t *dev, uint8_t reg, + void *in_data, size_t in_size); + +/** + * @brief Write to register with an 8-bit address + * + * Shortcut to ::i2c_dev_write(). + * + * @param dev Device descriptor + * @param reg Register address + * @param out_data Pointer to data to send + * @param out_size Size of data to send + * @return ESP_OK on success + */ +esp_err_t i2c_dev_write_reg(const i2c_dev_t *dev, uint8_t reg, + const void *out_data, size_t out_size); + +#define I2C_DEV_TAKE_MUTEX(dev) do { \ + esp_err_t __ = i2c_dev_take_mutex(dev); \ + if (__ != ESP_OK) return __;\ + } while (0) + +#define I2C_DEV_GIVE_MUTEX(dev) do { \ + esp_err_t __ = i2c_dev_give_mutex(dev); \ + if (__ != ESP_OK) return __;\ + } while (0) + +#define I2C_DEV_CHECK(dev, X) do { \ + esp_err_t ___ = X; \ + if (___ != ESP_OK) { \ + I2C_DEV_GIVE_MUTEX(dev); \ + return ___; \ + } \ + } while (0) + +#define I2C_DEV_CHECK_LOGE(dev, X, msg, ...) do { \ + esp_err_t ___ = X; \ + if (___ != ESP_OK) { \ + I2C_DEV_GIVE_MUTEX(dev); \ + ESP_LOGE(TAG, msg, ## __VA_ARGS__); \ + return ___; \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* __I2CDEV_H__ */ diff --git a/components/qmi8658c/.eil.yml b/components/qmi8658c/.eil.yml new file mode 100644 index 0000000..682e809 --- /dev/null +++ b/components/qmi8658c/.eil.yml @@ -0,0 +1,21 @@ +description: Driver for QMI8658C 6-axis IMU sensor +version: 0.5.0 +groups: + - imu +code_owners: xyzroe +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp32c3 + - esp8266 + - esp32s2 + - esp32c3 + - esp32c6 +license: BSD-3 +copyrights: + - name: xyzroe + year: 2024 \ No newline at end of file diff --git a/components/qmi8658c/CMakeLists.txt b/components/qmi8658c/CMakeLists.txt new file mode 100644 index 0000000..88688eb --- /dev/null +++ b/components/qmi8658c/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS qmi8658c.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) \ No newline at end of file diff --git a/components/qmi8658c/LICENSE b/components/qmi8658c/LICENSE new file mode 100644 index 0000000..b5a571d --- /dev/null +++ b/components/qmi8658c/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2024 xyzroe + +Based on https://github.com/ALICHOUCHENE/Qmi8658c + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +1. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +1. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/qmi8658c/component.mk b/components/qmi8658c/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/qmi8658c/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/qmi8658c/qmi8658c.c b/components/qmi8658c/qmi8658c.c new file mode 100644 index 0000000..6787a01 --- /dev/null +++ b/components/qmi8658c/qmi8658c.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include "qmi8658c.h" + +#define I2C_FREQ_HZ 400000 + +static const char *TAG = "qmi8658c"; + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) + +static qmi_ctx_t qmi_ctx; + +inline static esp_err_t send_command_nolock(i2c_dev_t *dev, uint8_t reg, uint8_t value) +{ + uint8_t data[2] = {reg, value}; + return i2c_dev_write(dev, NULL, 0, data, 2); +} + +static esp_err_t send_command(i2c_dev_t *dev, uint8_t reg, uint8_t value) +{ + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, send_command_nolock(dev, reg, value)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +#define REPLY_DELAY_MS 25 + +static esp_err_t read_register(i2c_dev_t *dev, uint8_t reg, uint8_t *value) +{ + I2C_DEV_TAKE_MUTEX(dev); + + I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, reg, value, 1)); + + vTaskDelay(pdMS_TO_TICKS(REPLY_DELAY_MS)); + + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +esp_err_t qmi8658c_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->port = port; + dev->addr = addr; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + return i2c_dev_create_mutex(dev); +} + +esp_err_t qmi8658c_free_desc(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + return i2c_dev_delete_mutex(dev); + /* + uint8_t ctrl7, ctrl1; + + // Read QMI8658_CTRL7 register + CHECK(read_register(dev, QMI8658_CTRL7, &ctrl7)); + + // Disable accelerometer, gyroscope, magnetometer and attitude engine + ctrl7 &= 0xF0; + CHECK(send_command(dev, QMI8658_CTRL7, ctrl7)); + + // Disable sensor by turning off the internal 2 MHz oscillator + CHECK(read_register(dev, QMI8658_CTRL1, &ctrl1)); + ctrl1 |= (1 << 0); + CHECK(send_command(dev, QMI8658_CTRL1, ctrl1)); + + // Read these two registers again to verify + CHECK(read_register(dev, QMI8658_CTRL7, &ctrl7)); + CHECK(read_register(dev, QMI8658_CTRL1, &ctrl1)); + + // Verify if the sensor is properly disabled + if (!(ctrl7 & 0x0F) && (ctrl1 & 0x01)) + { + return i2c_dev_delete_mutex(dev); + } + else + { + return ESP_FAIL; + } + */ +} + +esp_err_t qmi8658c_reset(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return send_command(dev, QMI8658_RESET, 0xB0); +} + +/* Accelerometer sensitivity table */ +uint16_t acc_scale_sensitivity_table[4] = { + ACC_SCALE_SENSITIVITY_2G, // Sensitivity for ±2g range. + ACC_SCALE_SENSITIVITY_4G, // Sensitivity for ±4g range. + ACC_SCALE_SENSITIVITY_8G, // Sensitivity for ±8g range. + ACC_SCALE_SENSITIVITY_16G // Sensitivity for ±16g range. +}; + +/* Gyroscope sensitivity table */ +uint16_t gyro_scale_sensitivity_table[8] = { + GYRO_SCALE_SENSITIVITY_16DPS, // Sensitivity for ±16 degrees per second range. + GYRO_SCALE_SENSITIVITY_32DPS, // Sensitivity for ±32 degrees per second range. + GYRO_SCALE_SENSITIVITY_64DPS, // Sensitivity for ±64 degrees per second range. + GYRO_SCALE_SENSITIVITY_128DPS, // Sensitivity for ±128 degrees per second range. + GYRO_SCALE_SENSITIVITY_256DPS, // Sensitivity for ±256 degrees per second range. + GYRO_SCALE_SENSITIVITY_512DPS, // Sensitivity for ±512 degrees per second range. + GYRO_SCALE_SENSITIVITY_1024DPS, // Sensitivity for ±1024 degrees per second range. + GYRO_SCALE_SENSITIVITY_2048DPS // Sensitivity for ±2048 degrees per second range. +}; + +esp_err_t qmi8658c_setup(i2c_dev_t *dev, qmi8658c_config_t *config) +{ + CHECK_ARG(dev && config); + + // reset device + qmi8658c_reset(dev); + + // set mode + uint8_t ctrl7; + CHECK(read_register(dev, QMI8658_CTRL7, &ctrl7)); + ctrl7 = (ctrl7 & 0xFC) | config->mode; + CHECK(send_command(dev, QMI8658_CTRL7, ctrl7)); + + // set accelerometr scale and ODR + uint8_t ctrl2; + CHECK(read_register(dev, QMI8658_CTRL2, &ctrl2)); + ctrl2 = (ctrl2 & 0xF0) | config->acc_odr; + ctrl2 = (ctrl2 & 0x8F) | (config->acc_scale << 4); + CHECK(send_command(dev, QMI8658_CTRL2, ctrl2)); + + // set accelerometer scale and sensitivity + qmi_ctx.acc_scale = config->acc_scale; + qmi_ctx.acc_sensitivity = acc_scale_sensitivity_table[config->acc_scale]; + + // set gyroscope scale and ODR + uint8_t ctrl3; + CHECK(read_register(dev, QMI8658_CTRL3, &ctrl3)); + ctrl3 = (ctrl3 & 0xF0) | config->gyro_odr; + ctrl3 = (ctrl3 & 0x8F) | (config->gyro_scale << 4); + CHECK(send_command(dev, QMI8658_CTRL3, ctrl3)); + + // set gyroscope scale and sensitivity + qmi_ctx.gyro_scale = config->gyro_scale; + qmi_ctx.gyro_sensitivity = gyro_scale_sensitivity_table[config->gyro_scale]; + + // read device ID and revision ID + CHECK(read_register(dev, QMI8658_WHO_AM_I, &qmi_ctx.who_am_i)); + CHECK(read_register(dev, QMI8658_REVISION, &qmi_ctx.revision)); + + ESP_LOGW(TAG, "device ID: 0x%02X, revision: 0x%02X", qmi_ctx.who_am_i, qmi_ctx.revision); + + // Verify mode setting + uint8_t qmi8658_ctrl7; + CHECK(read_register(dev, QMI8658_CTRL7, &qmi8658_ctrl7)); + if ((qmi8658_ctrl7 & 0x03) != config->mode) + { + ESP_LOGE(TAG, "Mode setting verification failed"); + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t qmi8658c_read_data(i2c_dev_t *dev, qmi8658c_data_t *data) +{ + CHECK_ARG(dev && data); + + // Read accelerometer data + uint8_t acc_x_l, acc_x_h, acc_y_l, acc_y_h, acc_z_l, acc_z_h; + CHECK(read_register(dev, QMI8658_ACC_X_L, &acc_x_l)); + CHECK(read_register(dev, QMI8658_ACC_X_H, &acc_x_h)); + CHECK(read_register(dev, QMI8658_ACC_Y_L, &acc_y_l)); + CHECK(read_register(dev, QMI8658_ACC_Y_H, &acc_y_h)); + CHECK(read_register(dev, QMI8658_ACC_Z_L, &acc_z_l)); + CHECK(read_register(dev, QMI8658_ACC_Z_H, &acc_z_h)); + + // ESP_LOGE(TAG, "acc_x_l: %d, acc_x_h: %d, acc_y_l: %d, acc_y_h: %d, acc_z_l: %d, acc_z_h: %d", acc_x_l, acc_x_h, acc_y_l, acc_y_h, acc_z_l, acc_z_h); + + int16_t acc_x = (int16_t)((acc_x_h << 8) | acc_x_l); + int16_t acc_y = (int16_t)((acc_y_h << 8) | acc_y_l); + int16_t acc_z = (int16_t)((acc_z_h << 8) | acc_z_l); + + // ESP_LOGW(TAG, "acc_x: %d, acc_y: %d, acc_z: %d", acc_x, acc_y, acc_z); + + data->acc.x = (float)acc_x / qmi_ctx.acc_sensitivity; + data->acc.y = (float)acc_y / qmi_ctx.acc_sensitivity; + data->acc.z = (float)acc_z / qmi_ctx.acc_sensitivity; + + // Read gyroscope data + uint8_t gyr_x_l, gyr_x_h, gyr_y_l, gyr_y_h, gyr_z_l, gyr_z_h; + CHECK(read_register(dev, QMI8658_GYR_X_L, &gyr_x_l)); + CHECK(read_register(dev, QMI8658_GYR_X_H, &gyr_x_h)); + CHECK(read_register(dev, QMI8658_GYR_Y_L, &gyr_y_l)); + CHECK(read_register(dev, QMI8658_GYR_Y_H, &gyr_y_h)); + CHECK(read_register(dev, QMI8658_GYR_Z_L, &gyr_z_l)); + CHECK(read_register(dev, QMI8658_GYR_Z_H, &gyr_z_h)); + + // ESP_LOGE(TAG, "gyr_x_l: %d, gyr_x_h: %d, gyr_y_l: %d, gyr_y_h: %d, gyr_z_l: %d, gyr_z_h: %d", gyr_x_l, gyr_x_h, gyr_y_l, gyr_y_h, gyr_z_l, gyr_z_h); + + int16_t gyr_x = (int16_t)((gyr_x_h << 8) | gyr_x_l); + int16_t gyr_y = (int16_t)((gyr_y_h << 8) | gyr_y_l); + int16_t gyr_z = (int16_t)((gyr_z_h << 8) | gyr_z_l); + + // ESP_LOGW(TAG, "gyr_x: %d, gyr_y: %d, gyr_z: %d", gyr_x, gyr_y, gyr_z); + + data->gyro.x = (float)gyr_x / qmi_ctx.gyro_sensitivity; + data->gyro.y = (float)gyr_y / qmi_ctx.gyro_sensitivity; + data->gyro.z = (float)gyr_z / qmi_ctx.gyro_sensitivity; + + // Read temperature data + uint8_t temp_l, temp_h; + CHECK(read_register(dev, QMI8658_TEMP_L, &temp_l)); + CHECK(read_register(dev, QMI8658_TEMP_H, &temp_h)); + + // ESP_LOGE(TAG, "temp_l: %d, temp_h: %d", temp_l, temp_h); + + int16_t temp = (int16_t)((temp_h << 8) | temp_l); + // ESP_LOGW(TAG, "temp: %d", temp); + + data->temperature = (float)temp / TEMPERATURE_SENSOR_RESOLUTION; + + // ESP_LOGW(TAG, "Acc: x=%f, y=%f, z=%f; Gyro: x=%f, y=%f, z=%f; Temp: %f", + // data->acc.x, data->acc.y, data->acc.z, data->gyro.x, data->gyro.y, data->gyro.z, data->temperature); + + return ESP_OK; +} \ No newline at end of file diff --git a/components/qmi8658c/qmi8658c.h b/components/qmi8658c/qmi8658c.h new file mode 100644 index 0000000..630e8f1 --- /dev/null +++ b/components/qmi8658c/qmi8658c.h @@ -0,0 +1,167 @@ +#ifndef __QMI8658C_H__ +#define __QMI8658C_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEFAUL_QMI8658C_ADDR 0x6B //!< I2C address for QMI8658C + +/* General purpose registers */ +#define QMI8658_WHO_AM_I 0x00 // WHO_AM_I register address. +#define QMI8658_REVISION 0x01 // REVISION register address. + +/* Setup and control registers */ +#define QMI8658_CTRL1 0x02 // Control register 1 address. +#define QMI8658_CTRL2 0x03 // Control register 2 address. +#define QMI8658_CTRL3 0x04 // Control register 3 address. +#define QMI8658_CTRL4 0x05 // Control register 4 address. +#define QMI8658_CTRL5 0x06 // Control register 5 address. +#define QMI8658_CTRL6 0x07 // Control register 6 address. +#define QMI8658_CTRL7 0x08 // Control register 7 address. +#define QMI8658_CTRL9 0x0A // Control register 9 address. + +/* Data output registers */ + +// Accelerometer +#define QMI8658_ACC_X_L 0x35 // Accelerometer X-axis low byte. +#define QMI8658_ACC_X_H 0x36 // Accelerometer X-axis high byte. +#define QMI8658_ACC_Y_L 0x37 // Accelerometer Y-axis low byte. +#define QMI8658_ACC_Y_H 0x38 // Accelerometer Y-axis high byte. +#define QMI8658_ACC_Z_L 0x39 // Accelerometer Z-axis low byte. +#define QMI8658_ACC_Z_H 0x3A // Accelerometer Z-axis high byte. + +// Gyroscope +#define QMI8658_GYR_X_L 0x3B // Gyroscope X-axis low byte. +#define QMI8658_GYR_X_H 0x3C // Gyroscope X-axis high byte. +#define QMI8658_GYR_Y_L 0x3D // Gyroscope Y-axis low byte. +#define QMI8658_GYR_Y_H 0x3E // Gyroscope Y-axis high byte. +#define QMI8658_GYR_Z_L 0x3F // Gyroscope Z-axis low byte. +#define QMI8658_GYR_Z_H 0x40 // Gyroscope Z-axis high byte. + +// Temperature sensor +#define QMI8658_TEMP_L 0x33 // Temperature sensor low byte. +#define QMI8658_TEMP_H 0x34 // Temperature sensor high byte. + +/* Soft reset register */ +#define QMI8658_RESET 0x60 // Soft reset register address. + +/* define scale sensitivity */ +/* Accelerometer scale sensitivity values for different gravity ranges */ +#define ACC_SCALE_SENSITIVITY_2G (1 << 14) // Sensitivity for ±2g range. +#define ACC_SCALE_SENSITIVITY_4G (1 << 13) // Sensitivity for ±4g range. +#define ACC_SCALE_SENSITIVITY_8G (1 << 12) // Sensitivity for ±8g range. +#define ACC_SCALE_SENSITIVITY_16G (1 << 11) // Sensitivity for ±16g range. + +/* Gyroscope scale sensitivity values for different degrees per second ranges */ +#define GYRO_SCALE_SENSITIVITY_16DPS (1 << 11) // Sensitivity for ±16 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_32DPS (1 << 10) // Sensitivity for ±32 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_64DPS (1 << 9 ) // Sensitivity for ±64 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_128DPS (1 << 8 ) // Sensitivity for ±128 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_256DPS (1 << 7 ) // Sensitivity for ±256 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_512DPS (1 << 6 ) // Sensitivity for ±512 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_1024DPS (1 << 5 ) // Sensitivity for ±1024 degrees per second range. +#define GYRO_SCALE_SENSITIVITY_2048DPS (1 << 4 ) // Sensitivity for ±2048 degrees per second range. + +typedef enum { + QMI8658C_MODE_ACC_ONLY = 1, + QMI8658C_MODE_GYRO_ONLY, + QMI8658C_MODE_DUAL, +} qmi8658c_mode_t; + +typedef enum { + QMI8658C_ACC_ODR_8000, + QMI8658C_ACC_ODR_4000, + QMI8658C_ACC_ODR_2000, + QMI8658C_ACC_ODR_1000, + QMI8658C_ACC_ODR_500, + QMI8658C_ACC_ODR_250, + QMI8658C_ACC_ODR_125, + QMI8658C_ACC_ODR_62_5, + QMI8658C_ACC_ODR_31_25, + QMI8658C_ACC_ODR_128 = 12, + QMI8658C_ACC_ODR_21, + QMI8658C_ACC_ODR_11, + QMI8658C_ACC_ODR_3, +} qmi8658c_acc_odr_t; + +typedef enum { + QMI8658C_GYRO_ODR_8000, + QMI8658C_GYRO_ODR_4000, + QMI8658C_GYRO_ODR_2000, + QMI8658C_GYRO_ODR_1000, + QMI8658C_GYRO_ODR_500, + QMI8658C_GYRO_ODR_250, + QMI8658C_GYRO_ODR_125, + QMI8658C_GYRO_ODR_62_5, + QMI8658C_GYRO_ODR_31_25, +} qmi8658c_gyro_odr_t; + +typedef enum { + QMI8658C_ACC_SCALE_2G, + QMI8658C_ACC_SCALE_4G, + QMI8658C_ACC_SCALE_8G, + QMI8658C_ACC_SCALE_16G, +} qmi8658c_acc_scale_t; + +typedef enum { + QMI8658C_GYRO_SCALE_16DPS, + QMI8658C_GYRO_SCALE_32DPS, + QMI8658C_GYRO_SCALE_64DPS, + QMI8658C_GYRO_SCALE_128DPS, + QMI8658C_GYRO_SCALE_256DPS, + QMI8658C_GYRO_SCALE_512DPS, + QMI8658C_GYRO_SCALE_1024DPS, + QMI8658C_GYRO_SCALE_2048DPS, +} qmi8658c_gyro_scale_t; + +#define TEMPERATURE_SENSOR_RESOLUTION (1 << 8 ) // Telperature sensor resolution (ADC) + +typedef struct { + float x; + float y; + float z; +} qmi8658c_axes_t; + + +typedef struct { + uint16_t acc_sensitivity; // Sensitivity value for the accelerometer. + uint8_t acc_scale; // Scale setting for the accelerometer. + uint16_t gyro_sensitivity; // Sensitivity value for the gyroscope. + uint8_t gyro_scale; // Scale setting for the gyroscope. + uint8_t who_am_i; + uint8_t revision; +} qmi_ctx_t; + + +typedef struct { + qmi8658c_axes_t acc; + qmi8658c_axes_t gyro; + float temperature; +} qmi8658c_data_t; + + +typedef struct { + qmi8658c_mode_t mode; + qmi8658c_acc_scale_t acc_scale; + qmi8658c_acc_odr_t acc_odr; + qmi8658c_gyro_scale_t gyro_scale; + qmi8658c_gyro_odr_t gyro_odr; +} qmi8658c_config_t; + +esp_err_t qmi8658c_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); +esp_err_t qmi8658c_free_desc(i2c_dev_t *dev); +esp_err_t qmi8658c_power_on(i2c_dev_t *dev); +esp_err_t qmi8658c_power_down(i2c_dev_t *dev); +esp_err_t qmi8658c_setup(i2c_dev_t *dev, qmi8658c_config_t *config); +esp_err_t qmi8658c_read_data(i2c_dev_t *dev, qmi8658c_data_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* __QMI8658C_H__ */ \ No newline at end of file diff --git a/components/scd4x/.eil.yml b/components/scd4x/.eil.yml new file mode 100644 index 0000000..54b7065 --- /dev/null +++ b/components/scd4x/.eil.yml @@ -0,0 +1,23 @@ +name: scd4x +description: Driver for SCD40/SCD41 miniature CO₂ sensor +version: 1.0.0 +groups: + - gas + - air-quality +code_owners: UncleRus +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: BSD-3 +copyrights: + - name: UncleRus + year: 2021 + - name: Sensirion + year: 2021 diff --git a/components/scd4x/CMakeLists.txt b/components/scd4x/CMakeLists.txt new file mode 100644 index 0000000..a7ca697 --- /dev/null +++ b/components/scd4x/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS scd4x.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) diff --git a/components/scd4x/LICENSE b/components/scd4x/LICENSE new file mode 100644 index 0000000..1629eff --- /dev/null +++ b/components/scd4x/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2021, Sensirion AG +Copyright (c) 2021 Ruslan V. Uss + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/scd4x/component.mk b/components/scd4x/component.mk new file mode 100644 index 0000000..a3610e8 --- /dev/null +++ b/components/scd4x/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/scd4x/scd4x.c b/components/scd4x/scd4x.c new file mode 100644 index 0000000..ddc9a8f --- /dev/null +++ b/components/scd4x/scd4x.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2021, Sensirion AG + * Copyright (c) 2021 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file scd4x.c + * + * ESP-IDF driver for SCD4x CO2 sensor. + * + * Ported from https://github.com/Sensirion/raspberry-pi-i2c-scd4x + * + * Copyright (c) 2021, Sensirion AG + * Copyright (c) 2021 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include +#include "scd4x.h" + +#define I2C_FREQ_HZ 100000 // 100kHz + +static const char *TAG = "scd4x"; + +#define CMD_START_PERIODIC_MEASUREMENT (0x21B1) +#define CMD_READ_MEASUREMENT (0xEC05) +#define CMD_STOP_PERIODIC_MEASUREMENT (0x3F86) +#define CMD_SET_TEMPERATURE_OFFSET (0x241D) +#define CMD_GET_TEMPERATURE_OFFSET (0x2318) +#define CMD_SET_SENSOR_ALTITUDE (0x2427) +#define CMD_GET_SENSOR_ALTITUDE (0x2322) +#define CMD_SET_AMBIENT_PRESSURE (0xE000) +#define CMD_PERFORM_FORCED_RECALIBRATION (0x362F) +#define CMD_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED (0x2416) +#define CMD_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED (0x2313) +#define CMD_START_LOW_POWER_PERIODIC_MEASUREMENT (0x21AC) +#define CMD_GET_DATA_READY_STATUS (0xE4B8) +#define CMD_PERSIST_SETTINGS (0x3615) +#define CMD_GET_SERIAL_NUMBER (0x3682) +#define CMD_PERFORM_SELF_TEST (0x3639) +#define CMD_PERFORM_FACTORY_RESET (0x3632) +#define CMD_REINIT (0x3646) +#define CMD_MEASURE_SINGLE_SHOT (0x219D) +#define CMD_MEASURE_SINGLE_SHOT_RHT_ONLY (0x2196) +#define CMD_POWER_DOWN (0x36E0) +#define CMD_WAKE_UP (0x36F6) + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } while (0) + +static uint8_t crc8(const uint8_t *data, size_t count) +{ + uint8_t res = 0xff; + + for (size_t i = 0; i < count; ++i) + { + res ^= data[i]; + for (uint8_t bit = 8; bit > 0; --bit) + { + if (res & 0x80) + res = (res << 1) ^ 0x31; + else + res = (res << 1); + } + } + return res; +} + +static inline uint16_t swap(uint16_t v) +{ + return (v << 8) | (v >> 8); +} + +static esp_err_t send_cmd(i2c_dev_t *dev, uint16_t cmd, uint16_t *data, size_t words) +{ + uint8_t buf[2 + words * 3]; + // add command + *(uint16_t *)buf = swap(cmd); + if (data && words) + // add arguments + for (size_t i = 0; i < words; i++) + { + uint8_t *p = buf + 2 + i * 3; + *(uint16_t *)p = swap(data[i]); + *(p + 2) = crc8(p, 2); + } + + ESP_LOGV(TAG, "Sending buffer:"); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, sizeof(buf), ESP_LOG_VERBOSE); + + return i2c_dev_write(dev, NULL, 0, buf, sizeof(buf)); +} + +static esp_err_t read_resp(i2c_dev_t *dev, uint16_t *data, size_t words) +{ + uint8_t buf[words * 3]; + CHECK(i2c_dev_read(dev, NULL, 0, buf, sizeof(buf))); + + ESP_LOGV(TAG, "Received buffer:"); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, sizeof(buf), ESP_LOG_VERBOSE); + + for (size_t i = 0; i < words; i++) + { + uint8_t *p = buf + i * 3; + uint8_t crc = crc8(p, 2); + if (crc != *(p + 2)) + { + ESP_LOGE(TAG, "Invalid CRC 0x%02x, expected 0x%02x", crc, *(p + 2)); + return ESP_ERR_INVALID_CRC; + } + data[i] = swap(*(uint16_t *)p); + } + return ESP_OK; +} + +static esp_err_t execute_cmd(i2c_dev_t *dev, uint16_t cmd, uint32_t timeout_ms, + uint16_t *out_data, size_t out_words, uint16_t *in_data, size_t in_words) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, send_cmd(dev, cmd, out_data, out_words)); + if (timeout_ms) + { + if (timeout_ms > 10) + vTaskDelay(pdMS_TO_TICKS(timeout_ms)); + else + ets_delay_us(timeout_ms * 1000); + } + if (in_data && in_words) + I2C_DEV_CHECK(dev, read_resp(dev, in_data, in_words)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +esp_err_t scd4x_init_desc(i2c_dev_t *dev, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->port = port; + dev->addr = SCD4X_I2C_ADDR; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(dev); +} + +esp_err_t scd4x_free_desc(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(dev); +} + +esp_err_t scd4x_start_periodic_measurement(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_START_PERIODIC_MEASUREMENT, 1, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_read_measurement_ticks(i2c_dev_t *dev, uint16_t *co2, uint16_t *temperature, uint16_t *humidity) +{ + CHECK_ARG(co2 || temperature || humidity); + + uint16_t buf[3]; + CHECK(execute_cmd(dev, CMD_READ_MEASUREMENT, 1, NULL, 0, buf, 3)); + if (co2) + *co2 = buf[0]; + if (temperature) + *temperature = buf[1]; + if (humidity) + *humidity = buf[2]; + + return ESP_OK; +} + +esp_err_t scd4x_read_measurement(i2c_dev_t *dev, uint16_t *co2, float *temperature, float *humidity) +{ + CHECK_ARG(co2 || temperature || humidity); + uint16_t t_raw, h_raw; + + CHECK(scd4x_read_measurement_ticks(dev, co2, &t_raw, &h_raw)); + if (temperature) + *temperature = (float)t_raw * 175.0f / 65536.0f - 45.0f; + if (humidity) + *humidity = (float)h_raw * 100.0f / 65536.0f; + + return ESP_OK; +} + +esp_err_t scd4x_stop_periodic_measurement(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_STOP_PERIODIC_MEASUREMENT, 500, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_get_temperature_offset_ticks(i2c_dev_t *dev, uint16_t *t_offset) +{ + CHECK_ARG(t_offset); + + return execute_cmd(dev, CMD_GET_TEMPERATURE_OFFSET, 1, NULL, 0, t_offset, 1); +} + +esp_err_t scd4x_get_temperature_offset(i2c_dev_t *dev, float *t_offset) +{ + CHECK_ARG(t_offset); + uint16_t raw; + + CHECK(scd4x_get_temperature_offset_ticks(dev, &raw)); + + *t_offset = (float)raw * 175.0f / 65536.0f; + + return ESP_OK; +} + +esp_err_t scd4x_set_temperature_offset_ticks(i2c_dev_t *dev, uint16_t t_offset) +{ + return execute_cmd(dev, CMD_SET_TEMPERATURE_OFFSET, 1, &t_offset, 1, NULL, 0); +} + +esp_err_t scd4x_set_temperature_offset(i2c_dev_t *dev, float t_offset) +{ + uint16_t raw = (uint16_t)(t_offset * 65536.0f / 175.0f + 0.5f); + return scd4x_set_temperature_offset_ticks(dev, raw); +} + +esp_err_t scd4x_get_sensor_altitude(i2c_dev_t *dev, uint16_t *altitude) +{ + CHECK_ARG(altitude); + + return execute_cmd(dev, CMD_GET_SENSOR_ALTITUDE, 1, NULL, 0, altitude, 1); +} + +esp_err_t scd4x_set_sensor_altitude(i2c_dev_t *dev, uint16_t altitude) +{ + return execute_cmd(dev, CMD_SET_SENSOR_ALTITUDE, 1, &altitude, 1, NULL, 0); +} + +esp_err_t scd4x_set_ambient_pressure(i2c_dev_t *dev, uint16_t pressure) +{ + return execute_cmd(dev, CMD_SET_AMBIENT_PRESSURE, 1, &pressure, 1, NULL, 0); +} + +esp_err_t scd4x_perform_forced_recalibration(i2c_dev_t *dev, uint16_t target_co2_concentration, + uint16_t *frc_correction) +{ + CHECK_ARG(frc_correction); + + return execute_cmd(dev, CMD_PERFORM_FORCED_RECALIBRATION, 400, + &target_co2_concentration, 1, frc_correction, 1); +} + +esp_err_t scd4x_get_automatic_self_calibration(i2c_dev_t *dev, bool *enabled) +{ + CHECK_ARG(enabled); + + return execute_cmd(dev, CMD_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED, 1, NULL, 0, (uint16_t *)enabled, 1); +} + +esp_err_t scd4x_set_automatic_self_calibration(i2c_dev_t *dev, bool enabled) +{ + return execute_cmd(dev, CMD_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED, 1, (uint16_t *)&enabled, 1, NULL, 0); +} + +esp_err_t scd4x_start_low_power_periodic_measurement(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_START_LOW_POWER_PERIODIC_MEASUREMENT, 0, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_get_data_ready_status(i2c_dev_t *dev, bool *data_ready) +{ + CHECK_ARG(data_ready); + + uint16_t status; + CHECK(execute_cmd(dev, CMD_GET_DATA_READY_STATUS, 1, NULL, 0, &status, 1)); + *data_ready = (status & 0x7ff) != 0; + + return ESP_OK; +} + +esp_err_t scd4x_persist_settings(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_PERSIST_SETTINGS, 800, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_get_serial_number(i2c_dev_t *dev, uint16_t *serial0, uint16_t *serial1, uint16_t *serial2) +{ + CHECK_ARG(serial0 && serial1 && serial2); + + uint16_t buf[3]; + CHECK(execute_cmd(dev, CMD_GET_SERIAL_NUMBER, 1, NULL, 0, buf, 3)); + *serial0 = buf[0]; + *serial1 = buf[1]; + *serial2 = buf[2]; + + return ESP_OK; +} + +esp_err_t scd4x_perform_self_test(i2c_dev_t *dev, bool *malfunction) +{ + CHECK_ARG(malfunction); + + return execute_cmd(dev, CMD_PERFORM_SELF_TEST, 10000, NULL, 0, (uint16_t *)malfunction, 1); +} + +esp_err_t scd4x_perform_factory_reset(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_PERFORM_FACTORY_RESET, 800, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_reinit(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_REINIT, 20, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_measure_single_shot(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_MEASURE_SINGLE_SHOT, 5000, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_measure_single_shot_rht_only(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_MEASURE_SINGLE_SHOT_RHT_ONLY, 50, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_power_down(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_POWER_DOWN, 1, NULL, 0, NULL, 0); +} + +esp_err_t scd4x_wake_up(i2c_dev_t *dev) +{ + return execute_cmd(dev, CMD_WAKE_UP, 20, NULL, 0, NULL, 0); +} diff --git a/components/scd4x/scd4x.h b/components/scd4x/scd4x.h new file mode 100644 index 0000000..3589654 --- /dev/null +++ b/components/scd4x/scd4x.h @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2021, Sensirion AG + * Copyright (c) 2021 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file scd4x.h + * @defgroup scd4x scd4x + * @{ + * + * ESP-IDF driver for SCD4x CO2 sensor. + * + * Ported from https://github.com/Sensirion/raspberry-pi-i2c-scd4x + * + * Copyright (c) 2021, Sensirion AG + * Copyright (c) 2021 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#ifndef __SCD4X_H__ +#define __SCD4X_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SCD4X_I2C_ADDR 0x62 + + /** + * @brief Initialize device descriptor. + * + * @param dev Device descriptor + * @param port I2C port + * @param sda_gpio SDA GPIO + * @param scl_gpio SCL GPIO + * @return `ESP_OK` on success + */ + esp_err_t scd4x_init_desc(i2c_dev_t *dev, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + + /** + * @brief Free device descriptor. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_free_desc(i2c_dev_t *dev); + + /** + * @brief Start periodic measurement. + * + * Signal update interval is 5 seconds. + * + * @note This command is only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_start_periodic_measurement(i2c_dev_t *dev); + + /** + * @brief Read sensor output. + * + * The measurement data can only be read out once per signal update interval + * as the buffer is emptied upon read-out. If no data is available in the + * buffer, the sensor returns a NACK. To avoid a NACK response the + * ::scd4x_get_data_ready_status() can be called to check data status. + * + * @note This command is only available in measurement mode. The firmware + * updates the measurement values depending on the measurement mode. + * + * @param dev Device descriptor + * @param co2 CO₂ concentration in ppm + * @param temperature Convert value to °C by: -45 °C + 175 °C * value/2^16 + * @param humidity Convert value to %RH by: 100%RH * value/2^16 + * @return `ESP_OK` on success + */ + esp_err_t scd4x_read_measurement_ticks(i2c_dev_t *dev, uint16_t *co2, uint16_t *temperature, uint16_t *humidity); + + /** + * @brief Read sensor output and convert. + * + * See ::scd4x_read_measurement_ticks() for more details. + * + * @note This command is only available in measurement mode. The firmware + * updates the measurement values depending on the measurement mode. + * + * @param dev Device descriptor + * @param co2 CO₂ concentration in ppm + * @param temperature Temperature in degrees Celsius (°C) + * @param humidity Relative humidity in percent RH + * @return `ESP_OK` on success + */ + esp_err_t scd4x_read_measurement(i2c_dev_t *dev, uint16_t *co2, float *temperature, float *humidity); + + /** + * @brief Stop periodic measurement. + * + * Stop periodic measurement and return to idle mode for sensor configuration + * or to safe energy. + * + * @note This command is only available in measurement mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_stop_periodic_measurement(i2c_dev_t *dev); + + /** + * @brief Get temperature offset in ticks. + * + * The temperature offset represents the difference between the measured + * temperature by the SCD4x and the actual ambient temperature. Per default, + * the temperature offset is set to 4°C. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @param t_offset Temperature offset. + * Convert value to °C by: 175 * value / 2^16 + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_temperature_offset_ticks(i2c_dev_t *dev, uint16_t *t_offset); + + /** + * @brief Get temperature offset in °C. + * + * See ::scd4x_get_temperature_offset_ticks() for more details. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @param t_offset Temperature offset in degrees Celsius (°C) + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_temperature_offset(i2c_dev_t *dev, float *t_offset); + + /** + * @brief Set temperature offset in ticks. + * + * Setting the temperature offset of the SCD4x inside the customer device + * correctly allows the user to leverage the RH and T output signal. Note + * that the temperature offset can depend on various factors such as the + * SCD4x measurement mode, self-heating of close components, the ambient + * temperature and air flow. Thus, the SCD4x temperature offset should be + * determined inside the customer device under its typical operation and in + * thermal equilibrium. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @param t_offset Temperature offset. + * Convert °C to value by: T * 2^16 / 175 + * @return `ESP_OK` on success + */ + esp_err_t scd4x_set_temperature_offset_ticks(i2c_dev_t *dev, uint16_t t_offset); + + /** + * @brief Set temperature offset in °C. + * + * See ::scd4x_set_temperature_offset_ticks() for more details. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @param t_offset Temperature offset in degrees Celsius (°C) + * @return `ESP_OK` on success + */ + esp_err_t scd4x_set_temperature_offset(i2c_dev_t *dev, float t_offset); + + /** + * @brief Get configured sensor altitude. + * + * Get configured sensor altitude in meters above sea level. Per default, the + * sensor altitude is set to 0 meter above sea-level. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor. + * @param altitude Sensor altitude in meters. + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_sensor_altitude(i2c_dev_t *dev, uint16_t *altitude); + + /** + * @brief Set sensor altitude in meters above sea level. + * + * Note that setting a sensor altitude to the sensor overrides any pressure + * compensation based on a previously set ambient pressure. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor. + * @param altitude Sensor altitude in meters. + * @return `ESP_OK` on success + */ + esp_err_t scd4x_set_sensor_altitude(i2c_dev_t *dev, uint16_t altitude); + + /** + * @brief Set ambient pressure. + * + * The set_ambient_pressure command can be sent during periodic measurements + * to enable continuous pressure compensation. Note that setting an ambient + * pressure to the sensor overrides any pressure compensation based on a + * previously set sensor altitude. + * + * @note Available during measurements. + * + * @param dev Device descriptor. + * @param pressure Ambient pressure in hPa. + * Convert value to Pa by: value * 100 + * @return `ESP_OK` on success + */ + esp_err_t scd4x_set_ambient_pressure(i2c_dev_t *dev, uint16_t pressure); + + /** + * @brief Perform forced recalibration. + * + * To successfully conduct an accurate forced recalibration, the following + * steps need to be carried out: + * - Operate the SCD4x in a periodic measurement mode for > 3 minutes in an + * environment with homogenous and constant CO₂ concentration. + * - Stop periodic measurement. Wait 500 ms. + * - Subsequently call scd4x_perform_forced_recalibration() and optionally + * read out the baseline correction. A return value of 0xffff indicates + * that the forced recalibration failed. + * + * @param dev Device descriptor. + * @param target_co2_concentration Target CO₂ concentration in ppm. + * @param frc_correction FRC correction value in CO₂ ppm or 0xFFFF + * if the command failed. + * @return `ESP_OK` on success + */ + esp_err_t scd4x_perform_forced_recalibration(i2c_dev_t *dev, + uint16_t target_co2_concentration, uint16_t *frc_correction); + + /** + * @brief Get automatic self calibration (ASC) state. + * + * By default, the ASC is enabled. + * + * @param dev Device descriptor. + * @param enabled true if ASC is enabled, false otherwise + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_automatic_self_calibration(i2c_dev_t *dev, bool *enabled); + + /** + * @brief Enable or disable automatic self calibration (ASC). + * + * By default, the ASC is enabled. + * + * @param dev Device descriptor. + * @param enabled true to enable ASC, false to disable ASC + * @return `ESP_OK` on success + */ + esp_err_t scd4x_set_automatic_self_calibration(i2c_dev_t *dev, bool enabled); + + /** + * @brief Start low power periodic measurement. + * + * Signal update interval is 30 seconds. + * + * @note This command is only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_start_low_power_periodic_measurement(i2c_dev_t *dev); + + /** + * @brief Check whether new measurement data is available for read-out. + * + * @param dev Device descriptor + * @param data_ready true if data is ready, false otherwise + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_data_ready_status(i2c_dev_t *dev, bool *data_ready); + + /** + * @brief Store current configuration in EEPROM. + * + * Configuration settings such as the temperature offset, sensor altitude and + * the ASC enabled/disabled parameter are by default stored in the volatile + * memory (RAM) only and will be lost after a power-cycle. This funciton + * stores the current configuration in the EEPROM of the SCD4x, making them + * resistant to power-cycling. To avoid unnecessary wear of the EEPROM, + * function should only be called when persistence is required and if actual + * changes to the configuration have been made. Note that field calibration + * history (i.e. FRC and ASC) is stored in the EEPROM automatically. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_persist_settings(i2c_dev_t *dev); + + /** + * @brief Read serial number. + * + * Reading out the serial number can be used to identify the chip and to verify + * the presence of the sensor. Function returns 3 words. Together, the 3 words + * constitute a unique serial number with a length of 48 bits (big endian format). + * + * @param dev Device descriptor + * @param serial0 First word of the 48 bit serial number + * @param serial1 Second word of the 48 bit serial number + * @param serial2 Third word of the 48 bit serial number + * @return `ESP_OK` on success + */ + esp_err_t scd4x_get_serial_number(i2c_dev_t *dev, uint16_t *serial0, uint16_t *serial1, uint16_t *serial2); + + /** + * @brief Perform self-test. + * + * This function can be used as an end-of-line test to confirm sensor + * functionality. + * + * @param dev Device descriptor + * @param malfunction true if malfunction detected, false if device is OK + * @return `ESP_OK` on success + */ + esp_err_t scd4x_perform_self_test(i2c_dev_t *dev, bool *malfunction); + + /** + * @brief Factory reset sensor. + * + * Initiates the reset of all configurations stored in the EEPROM and erases the + * FRC and ASC algorithm history. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_perform_factory_reset(i2c_dev_t *dev); + + /** + * @brief Reinitialize sensor. + * + * The reinit command reinitializes the sensor by reloading user settings from + * EEPROM. Before sending the reinit command, the stop measurement command must + * be issued. If reinit command does not trigger the desired re-initialization, + * a power-cycle should be applied to the SCD4x. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_reinit(i2c_dev_t *dev); + + /** + * @brief Perform single measurement. + * + * On-demand measurement of CO₂ concentration, relative humidity and temperature. + * The sensor output is read with the ::scd4x_read_measurement() function. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_measure_single_shot(i2c_dev_t *dev); + + /** + * @brief Perform single measurement of of relative humidity and temperature + * only. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_measure_single_shot_rht_only(i2c_dev_t *dev); + + /** + * @brief Put the sensor from idle to sleep mode. + * + * Call this function to reduce current consumption. + * + * @note Only available in idle mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_power_down(i2c_dev_t *dev); + + /** + * @brief Wake up sensor from sleep mode to idle mode. + * + * @note Only available in sleep mode. + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ + esp_err_t scd4x_wake_up(i2c_dev_t *dev); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* __SCD4X_H__ */ diff --git a/external_converter/q.js b/external_converter/q.js new file mode 100644 index 0000000..bcbca49 --- /dev/null +++ b/external_converter/q.js @@ -0,0 +1,120 @@ +const {Zcl} = require('zigbee-herdsman'); + +const fz = require('zigbee-herdsman-converters/converters/fromZigbee'); +const tz = require('zigbee-herdsman-converters/converters/toZigbee'); +const exposes = require('zigbee-herdsman-converters/lib/exposes'); +const reporting = require('zigbee-herdsman-converters/lib/reporting'); +const ota = require('zigbee-herdsman-converters/lib/ota'); +const utils = require('zigbee-herdsman-converters/lib/utils'); +const globalStore = require('zigbee-herdsman-converters/lib/store'); +const e = exposes.presets; +const ea = exposes.access; + +const { + deviceEndpoints, + iasZoneAlarm, + temperature, + humidity, + pressure, + co2, + illuminance, + numeric, + identify, + enumLookup, +} = require('zigbee-herdsman-converters/lib/modernExtend'); + +const defaultReporting = {min: 30, max: 300, change: 0}; + +const definition = { + zigbeeModel: ['Q_sensor'], + model: 'Q_sensor', + vendor: 'xyzroe', + description: 'Multi-functional Zigbee Air Quality Sensor', + ota: ota.zigbeeOTA, + extend: [ + deviceEndpoints({endpoints: {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13}}), + iasZoneAlarm({zoneType: 'occupancy', zoneAttributes: ['alarm_1', 'tamper']}), + temperature({endpointNames: ['1', '2', '3', '4']}), + humidity({endpointNames: ['2', '4']}), + pressure({endpointNames: ['3']}), + co2({endpointNames: ['4']}), + illuminance({endpointNames: ['5']}), + identify(), + numeric({ + name: 'voc', + unit: 'points', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'VOC index', + access: 'STATE_GET', + endpointNames: ['6'], + reporting: defaultReporting, + }), + numeric({ + name: 'adc1', + unit: 'mV', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'ADC1 value', + access: 'STATE_GET', + endpointNames: ['7'], + reporting: defaultReporting, + }), + numeric({ + name: 'adc2', + unit: 'mV', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'ADC2 value', + access: 'STATE_GET', + endpointNames: ['8'], + reporting: defaultReporting, + }), + enumLookup({ + name: 'possition', + lookup: {Incorrect: 0, Horizontal: 1, Vertical: 2}, + cluster: 'genMultistateValue', + attribute: 'presentValue', + description: 'Device position', + access: 'STATE_GET', + endpointNames: ['10'], + reporting: defaultReporting, + }), + numeric({ + name: 'pitch', + unit: '°', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'Pitch value', + access: 'STATE_GET', + endpointNames: ['11'], + reporting: defaultReporting, + precision: 6, + }), + numeric({ + name: 'roll', + unit: '°', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'Roll value', + access: 'STATE_GET', + endpointNames: ['12'], + reporting: defaultReporting, + precision: 6, + }), + numeric({ + name: 'yaw', + unit: '°', + cluster: 'genAnalogInput', + attribute: 'presentValue', + description: 'Yaw value', + access: 'STATE_GET', + endpointNames: ['13'], + reporting: defaultReporting, + precision: 6, + }), + ], + meta: {multiEndpoint: true}, +}; + +module.exports = definition; diff --git a/images/1.png b/images/1.png new file mode 100644 index 0000000..2274986 Binary files /dev/null and b/images/1.png differ diff --git a/images/z2m.png b/images/z2m.png new file mode 100644 index 0000000..ae90efb Binary files /dev/null and b/images/z2m.png differ diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..f65bfd7 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,3 @@ +FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/main/*.*) + +idf_component_register(SRCS ${app_sources}) diff --git a/main/const.h b/main/const.h new file mode 100644 index 0000000..6df84a4 --- /dev/null +++ b/main/const.h @@ -0,0 +1,83 @@ +#ifndef CONST_H +#define CONST_H + +/* Text constants */ +#define T_STATUS_FAILED "Failed!" +#define T_STATUS_DONE "Done" + +/* Number constants */ +#define LED_ON_STATE 0 +#define LED_OFF_STATE 1 + +/* Zigbee configuration */ +#define OTA_UPGRADE_MANUFACTURER 0x3443 /* The attribute indicates the value for the manufacturer of the device */ +#define OTA_UPGRADE_IMAGE_TYPE 0x1011 /* The attribute indicates the type of the image */ +#define OTA_UPGRADE_HW_VERSION 0x0101 /* The parameter indicates the version of hardware */ +#define OTA_UPGRADE_MAX_DATA_SIZE 64 /* The parameter indicates the maximum data size of query block image */ + +#define MAX_CHILDREN 10 /* the max amount of connected devices */ +#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ +#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ + +#define SRC_BINDING_TABLE_SIZE 64 +#define DST_BINDING_TABLE_SIZE 64 + +#define HW_MANUFACTURER "xyzroe" /* The parameter indicates the manufacturer of the device */ +#define HW_MODEL "Q_sensor" /* The parameter indicates the model of the device */ + +#define DEVICE_ENDPOINT 1 /* the endpoint number for the device */ +#define AHT20_ENDPOINT 2 /* the endpoint number for the AHT20 sensor */ +#define BMP280_ENDPOINT 3 /* the endpoint number for the BMP280 sensor */ +#define SCD40_ENDPOINT 4 /* the endpoint number for the SCD40 sensor */ +#define BH1750_ENDPOINT 5 /* the endpoint number for the BH1750 sensor */ +#define AGS10_ENDPOINT 6 /* the endpoint number for the AGS10 sensor */ +#define ADC1_ENDPOINT 7 /* the endpoint number for the ADC1 sensor */ +#define ADC2_ENDPOINT 8 /* the endpoint number for the ADC2 sensor */ + +#define IMU_BASE_ENDPOINT 10 /* the first endpoint number for the QMI8658C sensor */ + +// #define TVOC_CLUSTER 0xfc81 // 64641 // 0xfc81 // heimanSpecificAirQuality +// #define TVOC_ATTR 0xf004 // 61444 // 0xf004 // tvocMeasuredValue +// #define TVOC_CLUSTER 0x042b // msFormaldehyde +// #define TVOC_ATTR 0x0000 // measuredValue + +#define ESP_ZB_ZCL_CLUSTER_ID_MULTISTATE_VALUE 0x0014 +// #define ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_STATE_TEXT_ID 0x000E // ERROR while CREATE +#define ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_PRESENT_VALUE_ID 0x0055 // OK // +#define ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_NUMBER_OF_STATES_ID 0x004A // OK +#define ESP_ZB_ZCL_ATTR_MULTISTATE_DESCRIPTION_ID 0x001C // OK + +#define OTA_FW_VERSION 0x00000016 /* The attribute indicates the version of the firmware */ +#define FW_BUILD_DATE "20241023" /* The parameter indicates the build date of the firmware */ + +/* GPIO configuration */ +#define BTN_GPIO 10 /* Button */ + +#define ALARM_GPIO 4 /* Radar pin */ +#define LED_GPIO 5 /* blue LED */ + +#define ADC_1_GPIO 2 /* ADC1 */ +#define ADC_2_GPIO 0 /* ADC2 */ + +#define I2C_SDA_GPIO 6 /* I2C SDA */ +#define I2C_SCL_GPIO 7 /* I2C SCL */ + +/* Time constants */ + +#define LONG_PRESS_TIME 5000 /* to make factory reset */ +#define SHORT_PRESS_TIME 150 /* to toggle USB power */ +#define UPDATE_ATTRIBUTE_INTERVAL 600000 /* 10 minutes to FORCE update all states */ +#define WAIT_BEFORE_FIRST_UPDATE 15000 /* 15 seconds to wait before first update */ + +#define DEBUG_TASK_INTERVAL 10000 /* Debug task interval */ + +#define CPU_TEMP_INTERVAL 15000 /* CPU temp task interval */ +#define ADC_INTERVAL 10000 /* ADC task interval */ +#define AHT_TASK_INTERVAL 10000 /* AHT task interval */ +#define BMP280_TASK_INTERVAL 10000 /* BMP280 task interval */ +#define SCD4X_TASK_INTERVAL 10000 /* SCD4X task interval */ +#define BH1750_TASK_INTERVAL 10000 /* BH1750 task interval */ +#define QMI8658C_TASK_INTERVAL 5000 /* QMI8658C task interval */ +#define AGS10_TASK_INTERVAL 10000 /* AGS10 task interval */ + +#endif // CONST_H diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..453a888 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,9 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/button: "^3.2.0" + espressif/esp-zboss-lib: "1.5.1" + espressif/esp-zigbee-lib: "1.5.1" + ## espressif/zlib: "1.3.0" + ## Required IDF version + idf: + version: "5.3.1" diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..d2a9733 --- /dev/null +++ b/main/main.c @@ -0,0 +1,86 @@ + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "string.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "zcl/esp_zigbee_zcl_common.h" +#include "i2cdev.h" +// #include "ina219.h" +#include +#include + +#include "ha/esp_zigbee_ha_standard.h" +#include "esp_timer.h" +#include "esp_ota_ops.h" +#include "zboss_api.h" +#include "zcl/esp_zigbee_zcl_command.h" +#include "zcl/zb_zcl_common.h" + +#include "main.h" +#include "const.h" +#include "tools.h" +#include "perf.h" +#include "zigbee.h" + +/*------ Global definitions -----------*/ +float led_hz = 2; +char strftime_buf[64]; +DataStructure data; + +uint16_t manuf_id = OTA_UPGRADE_MANUFACTURER; +char manufacturer[16]; +char model[16]; +char firmware_version[16]; +char firmware_date[16]; +bool time_updated = false; +bool connected = false; + +// uint16_t power = 0; +// uint16_t voltage = 0; +// uint16_t current = 0; +// uint16_t chip_temp = 0; +// uint16_t uptime = 0; +// float ina_bus_voltage = 0; +// float ina_shunt_voltage = 0; +// float ina_current = 0; +// float ina_power = 0; + +TaskHandle_t ledTaskHandle = NULL; + +void app_main(void) +{ + + ESP_LOGW(__func__, "FW verison 0x%x (%d) date: %s", OTA_FW_VERSION, OTA_FW_VERSION, FW_BUILD_DATE); + + setup_NVS(); + + init_outputs(); + + print_chip_info(); + + register_button(BTN_GPIO); + + register_alarm_input(); + + data.led_mode = read_NVS("led_mode"); + // data.ext_led_mode = read_NVS("ext_led_mode"); + // data.USB_state = read_NVS("USB_state"); + // data.start_up_on_off = read_NVS("start_up_on_off"); + + ESP_ERROR_CHECK(i2cdev_init()); + + run_sensors(); + + led_blink(500); + + zigbee_setup(); + + xTaskCreate(led_task, "led_task", 4096, NULL, 5, &ledTaskHandle); + // xTaskCreate(force_update_task, "force_update_task", 4096, NULL, 4, NULL); + + // xTaskCreate(test_task, "test_task", 4096, NULL, 2, NULL); + // xTaskCreate(debug_task, "debug_task", 4096, NULL, 3, NULL); +} diff --git a/main/main.h b/main/main.h new file mode 100644 index 0000000..98e8fcc --- /dev/null +++ b/main/main.h @@ -0,0 +1,65 @@ +#ifndef ZIGUSB_H +#define ZIGUSB_H + +#include +#include +#include "driver/gpio.h" +#include "esp_zigbee_core.h" + +typedef struct +{ + // bool USB_state; + // bool ext_led_mode; + int old_identify_time; + bool led_mode; + bool radar_state; + // int start_up_on_off; + uint16_t chip_temp; + uint16_t aht_temp; + uint16_t aht_hum; + uint16_t bmp_temp; + uint16_t bmp_press; + uint16_t scd_co2; + uint16_t scd_temp; + uint16_t scd_hum; + uint16_t lux; + uint16_t voc; + uint16_t imu_pos; + int32_t imu_pitch; + int32_t imu_roll; + int32_t imu_yaw; + uint16_t adc1; + uint16_t adc2; + uint8_t zone_status; +} DataStructure; + +extern float led_hz; +extern char strftime_buf[64]; +extern DataStructure data; + +extern uint16_t manuf_id; +extern char manufacturer[16]; +extern char model[16]; +extern char firmware_version[16]; +extern char firmware_date[16]; +extern bool time_updated; +extern bool connected; + +extern TaskHandle_t ledTaskHandle; + +typedef enum +{ + ATTRIBUTE_ALL, + ATTRIBUTE_CHIP_TEMP, + ATTRIBUTE_AHT, + ATTRIBUTE_BMP, + ATTRIBUTE_SCD, + ATTRIBUTE_LUX, + ATTRIBUTE_VOC, + ATTRIBUTE_IMU, + ATTRIBUTE_ADC, +} attribute_t; + +void app_main(void); + +#endif // ZIGUSB_H diff --git a/main/perf.c b/main/perf.c new file mode 100644 index 0000000..49a3f7f --- /dev/null +++ b/main/perf.c @@ -0,0 +1,275 @@ +#include "driver/gpio.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "iot_button.h" +#include "i2cdev.h" +#include "string.h" + +#include "main.h" +#include "const.h" +#include "perf.h" +#include "tools.h" +#include "zigbee.h" + +#include "sensors/adc/sensor_adc.h" +#include "sensors/chip_temp/sensor_chip_temp.h" +#include "sensors/aht/sensor_aht.h" +#include "sensors/bmp280/sensor_bmp280.h" +#include "sensors/scd4x/sensor_scd4x.h" +#include "sensors/ags10/sensor_ags10.h" +#include "sensors/bh1750/sensor_bh1750.h" +#include "sensors/qmi8658c/sensor_qmi8658c.h" + +void init_outputs() +{ + ESP_LOGI(__func__, "setup LED gpio"); + gpio_reset_pin(LED_GPIO); + gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT); + gpio_pulldown_en(LED_GPIO); + gpio_set_level(LED_GPIO, LED_OFF_STATE); + + /* + gpio_reset_pin(INT_LED_GPIO); + gpio_set_direction(INT_LED_GPIO, GPIO_MODE_OUTPUT); + gpio_pulldown_en(INT_LED_GPIO); + gpio_set_level(INT_LED_GPIO, LED_OFF_STATE); + + ESP_LOGI(__func__, "setup USB gpio"); + gpio_reset_pin(USB_GPIO); + gpio_set_direction(USB_GPIO, GPIO_MODE_OUTPUT); + gpio_pullup_en(USB_GPIO); + */ + /* + switch (data.start_up_on_off) + { + case 0: + usb_driver_set_power(0); + break; + case 1: + usb_driver_set_power(1); + break; + case 2: + usb_driver_set_power(!data.USB_state); + break; + case 255: + usb_driver_set_power(data.USB_state); + break; + default: + break; + } + */ +} + +/*(void init_pullup_i2c_pins() +{ + ESP_LOGI(__func__, "setup I2C_SDA_GPIO"); + gpio_reset_pin(I2C_SDA_GPIO); + gpio_pullup_en(I2C_SDA_GPIO); + ESP_LOGI(__func__, "setup I2C_SCL_GPIO"); + gpio_reset_pin(I2C_SCL_GPIO); + gpio_pullup_en(I2C_SCL_GPIO); +}*/ + +/* +void usb_driver_set_power(bool state) +{ + gpio_set_level(USB_GPIO, state); + ext_led_action(state); + ESP_LOGI(__func__, "Setting USB power to %d", state); + data.USB_state = state; + if (data.start_up_on_off > 1) + { + write_NVS("USB_state", state); + } +} +*/ + +void led_task(void *pvParameters) +{ + ESP_LOGI(__func__, "starting"); + // led_hz = 1; + while (1) + { + if (led_hz > 0) + { + led_blink(150); + vTaskDelay(pdMS_TO_TICKS(1000 / led_hz)); + } + else + { + // LED disabled + + vTaskDelay(pdMS_TO_TICKS(100)); + } + } +} + +void led_blink(int delay) +{ + if (data.led_mode) + { + gpio_set_level(LED_GPIO, LED_ON_STATE); + vTaskDelay(pdMS_TO_TICKS(delay)); + gpio_set_level(LED_GPIO, LED_OFF_STATE); + } +} + +void register_alarm_input() +{ + button_config_t gpio_alarm_cfg = { + .type = BUTTON_TYPE_GPIO, + .gpio_button_config = { + .gpio_num = ALARM_GPIO, + .active_level = 0, + }, + }; + + button_handle_t gpio_alarm = iot_button_create(&gpio_alarm_cfg); + if (NULL == gpio_alarm) + { + ESP_LOGE(__func__, "Alarm input create failed"); + } +#define NO_MOTION 0 +#define MOTION 1 + iot_button_register_cb(gpio_alarm, NO_MOTION, radar_deactive_cb, NULL); + iot_button_register_cb(gpio_alarm, MOTION, radar_active_cb, NULL); +} + +static void radar_active_cb(void *arg, void *usr_data) +{ + ESP_LOGI(__func__, "motion detected"); + + send_zone_1_state(0, 1); +} + +static void radar_deactive_cb(void *arg, void *usr_data) +{ + ESP_LOGI(__func__, "no motion detected"); + + send_zone_1_state(0, 0); +} + +void register_button(int pin) +{ + button_config_t gpio_btn_cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = LONG_PRESS_TIME, + .short_press_time = SHORT_PRESS_TIME, + .gpio_button_config = { + .gpio_num = pin, + .active_level = 0, + }, + }; + + button_handle_t gpio_btn = iot_button_create(&gpio_btn_cfg); + if (NULL == gpio_btn) + { + ESP_LOGE(__func__, "Button on pin %d create failed", pin); + } + + iot_button_register_cb(gpio_btn, BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(gpio_btn, BUTTON_LONG_PRESS_START, button_long_press_cb, NULL); + ESP_LOGI(__func__, "Button on pin %d registered", pin); +} + +static void button_single_click_cb(void *arg, void *usr_data) +{ + ESP_LOGI(__func__, "single click"); + force_update(); +} + +static void button_long_press_cb(void *arg, void *usr_data) +{ + ESP_LOGI(__func__, "long press - leave & reset"); + // data.ext_led_mode = 1; // Force turn LED ON + for (int i = 0; i < 5; i++) + { + led_blink(150); + vTaskDelay(pdMS_TO_TICKS(400)); + } + esp_zb_bdb_reset_via_local_action(); + esp_zb_factory_reset(); +} + +void test_task(void *pvParameters) +{ + + ESP_LOGI(__func__, "starting test task"); + while (1) + { + float ina_bus_voltage = round_to_decimals(random_float(4.5, 5.5), 4); + float ina_current = round_to_decimals(random_float(0.0, 2.0), 4); + float ina_power = round_to_decimals((ina_bus_voltage * ina_current), 4); + + ESP_LOGW(__func__, "VBUS: %.04f V, IBUS: %.04f A, PBUS: %.04f W", + ina_bus_voltage, ina_current, ina_power); + + // ZCL must be V,A,W = uint16. But we need more accuaracy - so use *100. + // voltage = (float)(ina_bus_voltage * 100); + // current = (float)(ina_current * 100); + // power = (float)(ina_power * 100); + + // update_attributes(ATTRIBUTE_ELECTRO); + + vTaskDelay(pdMS_TO_TICKS(CPU_TEMP_INTERVAL)); + } +} + +void run_sensors() +{ + scan_i2c_bus(I2C_SDA_GPIO, I2C_SCL_GPIO); + + ESP_LOGI(__func__, "starting sensors tasks"); + + sensor_adc(); + + sensor_chip_temp(); + + sensor_aht(); + + sensor_bmp280(); + + sensor_ags10(); + + sensor_bh1750(); + + sensor_qmi8658c(); + + sensor_scd4x(); +} + +void identify_task(void *pvParameters) +{ + int time = (int)pvParameters; + + float old_led_hz = led_hz; + bool old_led_mode = data.led_mode; + data.led_mode = 1; + led_hz = 2; + + if (ledTaskHandle != NULL) + { + vTaskDelete(ledTaskHandle); + ledTaskHandle = NULL; + } + xTaskCreate(led_task, "led_task", 4096, NULL, 3, &ledTaskHandle); + + vTaskDelay(time * 1000 / portTICK_PERIOD_MS); + + if (ledTaskHandle != NULL) + { + vTaskDelete(ledTaskHandle); + ledTaskHandle = NULL; + } + led_hz = old_led_hz; + led_blink(10); + + data.led_mode = old_led_mode; + + data.old_identify_time = 0; + + ESP_LOGI(__func__, "Identify exit"); + vTaskDelete(NULL); +} \ No newline at end of file diff --git a/main/perf.h b/main/perf.h new file mode 100644 index 0000000..14de5aa --- /dev/null +++ b/main/perf.h @@ -0,0 +1,28 @@ +#ifndef PERF_H +#define PERF_H + +void init_outputs(); +// void init_pullup_i2c_pins(); + +// void usb_driver_set_power(bool state); + +void led_task(void *pvParameters); +void led_blink(int delay); + +void register_alarm_input(); +static void radar_active_cb(void *arg, void *usr_data); +static void radar_deactive_cb(void *arg, void *usr_data); + +void register_button(); +static void button_single_click_cb(void *arg, void *usr_data); +static void button_long_press_cb(void *arg, void *usr_data); + +void chip_temp_task(void *pvParameters); + +void test_task(void *pvParameters); + +void run_sensors(); + +void identify_task(void *pvParameters); + +#endif // PERF_H \ No newline at end of file diff --git a/main/sensors/adc/sensor_adc.c b/main/sensors/adc/sensor_adc.c new file mode 100644 index 0000000..178bb09 --- /dev/null +++ b/main/sensors/adc/sensor_adc.c @@ -0,0 +1,169 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" + +#include "string.h" + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +#define EXAMPLE_ADC1_CHAN0 ADC_CHANNEL_0 +#define EXAMPLE_ADC1_CHAN1 ADC_CHANNEL_2 +#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12 + +static int adc_raw[2][10]; +static int voltage3[2][10]; +static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle); +static void example_adc_calibration_deinit(adc_cali_handle_t handle); + +void adc_task(void *pvParameters) +{ + ESP_LOGI(__func__, "initializing ADC sensor"); + + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC1 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = EXAMPLE_ADC_ATTEN, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config)); + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config)); + + //-------------ADC1 Calibration Init---------------// + adc_cali_handle_t adc1_cali_chan0_handle = NULL; + adc_cali_handle_t adc1_cali_chan1_handle = NULL; + bool do_calibration1_chan0 = example_adc_calibration_init(ADC_UNIT_1, EXAMPLE_ADC1_CHAN0, EXAMPLE_ADC_ATTEN, &adc1_cali_chan0_handle); + bool do_calibration1_chan1 = example_adc_calibration_init(ADC_UNIT_1, EXAMPLE_ADC1_CHAN1, EXAMPLE_ADC_ATTEN, &adc1_cali_chan1_handle); + + ESP_LOGI(__func__, "starting the loop"); + while (1) + { + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0])); + if (do_calibration1_chan0) + { + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_chan0_handle, adc_raw[0][0], &voltage3[0][0])); + } + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[0][1])); + if (do_calibration1_chan1) + { + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_chan1_handle, adc_raw[0][1], &voltage3[0][1])); + } + + ESP_LOGI(__func__, "ADC%d Channel[%d] Cali Voltage: %d mV, Channel[%d] Cali Voltage: %d mV", + ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage3[0][0], EXAMPLE_ADC1_CHAN1, voltage3[0][1]); + + uint16_t new_adc1 = voltage3[0][0]; + uint16_t new_adc2 = voltage3[0][1]; + + if ((new_adc1 != data.adc1 || new_adc2 != data.adc2) && connected) + { + data.adc1 = new_adc1; + data.adc2 = new_adc2; + update_attributes(ATTRIBUTE_ADC); + } + + /* + uint16_t new_aht_temp = (float)(temperature * 100); + uint16_t new_aht_hum = (float)(humidity * 100); + + if ((new_aht_temp != data.aht_temp || new_aht_hum != data.aht_hum) && connected) + { + data.aht_temp = new_aht_temp; + data.aht_hum = new_aht_hum; + update_attributes(ATTRIBUTE_AHT); + } + */ + + vTaskDelay(pdMS_TO_TICKS(ADC_INTERVAL)); + } +} + +void sensor_adc() +{ + ESP_LOGW(__func__, "ADC sensor task started"); + xTaskCreate(adc_task, "adc_task", 4096, NULL, 3, NULL); +} + +static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle) +{ + adc_cali_handle_t handle = NULL; + esp_err_t ret = ESP_FAIL; + bool calibrated = false; + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + if (!calibrated) + { + ESP_LOGI(__func__, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .chan = channel, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); + if (ret == ESP_OK) + { + calibrated = true; + } + } +#endif + +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + if (!calibrated) + { + ESP_LOGI(__func__, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); + if (ret == ESP_OK) + { + calibrated = true; + } + } +#endif + + *out_handle = handle; + if (ret == ESP_OK) + { + ESP_LOGI(__func__, "Calibration Success"); + } + else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) + { + ESP_LOGW(__func__, "eFuse not burnt, skip software calibration"); + } + else + { + ESP_LOGE(__func__, "Invalid arg or no memory"); + } + + return calibrated; +} + +static void example_adc_calibration_deinit(adc_cali_handle_t handle) +{ +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + ESP_LOGI(__func__, "deregister %s calibration scheme", "Curve Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle)); + +#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + ESP_LOGI(__func__, "deregister %s calibration scheme", "Line Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle)); +#endif +} \ No newline at end of file diff --git a/main/sensors/adc/sensor_adc.h b/main/sensors/adc/sensor_adc.h new file mode 100644 index 0000000..0a61c23 --- /dev/null +++ b/main/sensors/adc/sensor_adc.h @@ -0,0 +1 @@ +void sensor_adc(); \ No newline at end of file diff --git a/main/sensors/ags10/sensor_ags10.c b/main/sensors/ags10/sensor_ags10.c new file mode 100644 index 0000000..8476efb --- /dev/null +++ b/main/sensors/ags10/sensor_ags10.c @@ -0,0 +1,93 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" + +#include "string.h" +#include "../../const.h" +#include "../../main.h" +#include "../../zigbee.h" + +#include "ags10.h" + +static const char *TAG = "sensor_ags10"; + +static void sensor_ags10_task(void *pvParameters) +{ + + gpio_num_t param_pin_SCL = I2C_SCL_GPIO; + gpio_num_t param_pin_SDA = I2C_SDA_GPIO; + + int I2C_ADDRESS_int = 0x1A; + + i2c_dev_t dev; + esp_err_t init_err = ags10_init_desc(&dev, I2C_NUM_0, I2C_ADDRESS_int, param_pin_SDA, param_pin_SCL); + if (init_err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to initialize AGS10: %s", esp_err_to_name(init_err)); + vTaskDelete(NULL); + } + + uint8_t version; + esp_err_t ver_err = ags10_read_version(&dev, &version); + if (ver_err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to read AGS10 version: %s", esp_err_to_name(init_err)); + vTaskDelete(NULL); + } + ESP_LOGW(TAG, "AGS10 version: v%d", version); + + uint32_t tvoc; + // uint32_t resistance; + + vTaskDelay(pdMS_TO_TICKS(1000)); // Wait for the device to boot + + /* + esp_err_t res = ags10_set_zero_point_with_factory_defaults(&dev); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Could not set zero point with factory defaults: %d (%s)", res, esp_err_to_name(res)); + } + else + { + ESP_LOGI(TAG, "Zero point set with factory defaults"); + } + */ + while (1) + { + esp_err_t res = ags10_read_tvoc(&dev, &tvoc); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Could not read TVOC: %d (%s)", res, esp_err_to_name(res)); + } + else + { + ESP_LOGI(TAG, "TVOC: %lu", tvoc); + data.voc = tvoc; + update_attributes(ATTRIBUTE_VOC); + } + + /* + res = ags10_read_resistance(&dev, &resistance); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Could not read resistance: %d (%s)", res, esp_err_to_name(res)); + } + else + { + ESP_LOGI(TAG, "Resistance: %lu", resistance); + } + */ + + vTaskDelay(pdMS_TO_TICKS(AGS10_TASK_INTERVAL)); + } + + ags10_free_desc(&dev); +} + +void sensor_ags10() +{ + ESP_LOGW(__func__, "AGS10 sensor task started"); + xTaskCreate(sensor_ags10_task, "sensor_ags10_task", 4096, NULL, 5, NULL); +} diff --git a/main/sensors/ags10/sensor_ags10.h b/main/sensors/ags10/sensor_ags10.h new file mode 100644 index 0000000..f5453c1 --- /dev/null +++ b/main/sensors/ags10/sensor_ags10.h @@ -0,0 +1 @@ +void sensor_ags10(); \ No newline at end of file diff --git a/main/sensors/aht/sensor_aht.c b/main/sensors/aht/sensor_aht.c new file mode 100644 index 0000000..2c36429 --- /dev/null +++ b/main/sensors/aht/sensor_aht.c @@ -0,0 +1,86 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "string.h" + +#include "sensor_aht.h" +#include "aht.h" + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +#ifndef APP_CPU_NUM +#define APP_CPU_NUM PRO_CPU_NUM +#endif + +#define AHT_TYPE_AHT1x AHT_TYPE + +static void sensor_aht_task(void *pvParameters) +{ + + gpio_num_t pin_SCL = I2C_SCL_GPIO; + gpio_num_t pin_SDA = I2C_SDA_GPIO; + + int I2C_ADDRESS_int = AHT_I2C_ADDRESS_GND; + + aht_t dev = {0}; + dev.mode = AHT_MODE_NORMAL; + dev.type = AHT_TYPE_AHT20; + + esp_err_t init_desc_err = aht_init_desc(&dev, I2C_ADDRESS_int, 0, pin_SDA, pin_SCL); + if (init_desc_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize device descriptor: %s", esp_err_to_name(init_desc_err)); + vTaskDelete(NULL); + } + + esp_err_t init_err = aht_init(&dev); + if (init_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize AHT: %s", esp_err_to_name(init_err)); + vTaskDelete(NULL); + } + + bool calibrated; + ESP_ERROR_CHECK(aht_get_status(&dev, NULL, &calibrated)); + if (calibrated) + ESP_LOGI(__func__, "Sensor calibrated"); + else + ESP_LOGW(__func__, "Sensor not calibrated!"); + + float temperature, humidity; + + while (1) + { + + if (aht_get_data(&dev, &temperature, &humidity) == ESP_OK) + { + ESP_LOGI(__func__, "Temperature: %.2f °C, Humidity: %.2f %%", temperature, humidity); + + uint16_t new_aht_temp = (float)(temperature * 100); + uint16_t new_aht_hum = (float)(humidity * 100); + + if ((new_aht_temp != data.aht_temp || new_aht_hum != data.aht_hum) && connected) + { + data.aht_temp = new_aht_temp; + data.aht_hum = new_aht_hum; + update_attributes(ATTRIBUTE_AHT); + } + } + else + { + ESP_LOGE(__func__, "Could not read data from sensor AHT"); + } + + vTaskDelay(pdMS_TO_TICKS(AHT_TASK_INTERVAL)); + } +} + +void sensor_aht() +{ + ESP_LOGW(__func__, "AHT sensor task started"); + xTaskCreate(sensor_aht_task, "sensor_aht_task", 4096, NULL, 5, NULL); +} diff --git a/main/sensors/aht/sensor_aht.h b/main/sensors/aht/sensor_aht.h new file mode 100644 index 0000000..7001a10 --- /dev/null +++ b/main/sensors/aht/sensor_aht.h @@ -0,0 +1,2 @@ + +void sensor_aht(); diff --git a/main/sensors/bh1750/sensor_bh1750.c b/main/sensors/bh1750/sensor_bh1750.c new file mode 100644 index 0000000..513a9c1 --- /dev/null +++ b/main/sensors/bh1750/sensor_bh1750.c @@ -0,0 +1,70 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "string.h" + +#include "bh1750.h" + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +static void sensor_bh1750_task(void *pvParameters) +{ + + gpio_num_t pin_SCL = I2C_SCL_GPIO; + gpio_num_t pin_SDA = I2C_SDA_GPIO; + + int I2C_ADDRESS_int = BH1750_ADDR_LO; + + i2c_dev_t dev; + memset(&dev, 0, sizeof(i2c_dev_t)); + + esp_err_t init_desc_err = bh1750_init_desc(&dev, I2C_ADDRESS_int, 0, pin_SDA, pin_SCL); + if (init_desc_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize device descriptor: %s", esp_err_to_name(init_desc_err)); + vTaskDelete(NULL); + } + + esp_err_t setup_err = bh1750_setup(&dev, BH1750_MODE_CONTINUOUS, BH1750_RES_HIGH2); + if (setup_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to setup BH1750: %s", esp_err_to_name(setup_err)); + vTaskDelete(NULL); + } + + vTaskDelay(pdMS_TO_TICKS(1000)); // Wait for the device to boot + + while (1) + { + uint16_t lux; + esp_err_t res = bh1750_read(&dev, &lux); + if (res != ESP_OK) + { + ESP_LOGE(__func__, "Could not read lux data: %d (%s)", res, esp_err_to_name(res)); + } + else + { + ESP_LOGI(__func__, "Lux: %d", lux); + + uint16_t new_bh1750_lux = 10000.0 * log10(lux) + 1; + + if ((new_bh1750_lux != data.lux) && connected) + { + data.lux = new_bh1750_lux; + update_attributes(ATTRIBUTE_LUX); + } + } + + vTaskDelay(pdMS_TO_TICKS(BH1750_TASK_INTERVAL)); + } +} + +void sensor_bh1750() +{ + ESP_LOGW(__func__, "Task: BH1750 created."); + xTaskCreate(sensor_bh1750_task, "sensor_bh1750_task", 4096, NULL, 5, NULL); +} diff --git a/main/sensors/bh1750/sensor_bh1750.h b/main/sensors/bh1750/sensor_bh1750.h new file mode 100644 index 0000000..9be01f1 --- /dev/null +++ b/main/sensors/bh1750/sensor_bh1750.h @@ -0,0 +1 @@ +void sensor_bh1750(); \ No newline at end of file diff --git a/main/sensors/bmp280/sensor_bmp280.c b/main/sensors/bmp280/sensor_bmp280.c new file mode 100644 index 0000000..14d1f64 --- /dev/null +++ b/main/sensors/bmp280/sensor_bmp280.c @@ -0,0 +1,80 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "string.h" + +#include "sensor_bmp280.h" +#include "bmp280.h" + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +#ifndef APP_CPU_NUM +#define APP_CPU_NUM PRO_CPU_NUM +#endif + +static void sensor_bmp280_task(void *pvParameters) +{ + + gpio_num_t pin_SCL = I2C_SCL_GPIO; + gpio_num_t pin_SDA = I2C_SDA_GPIO; + + int I2C_ADDRESS_int = 0x77; + + bmp280_params_t params_bmp280; + bmp280_init_default_params(¶ms_bmp280); + bmp280_t dev; + memset(&dev, 0, sizeof(bmp280_t)); + + esp_err_t init_desc_err = bmp280_init_desc(&dev, I2C_ADDRESS_int, 0, pin_SDA, pin_SCL); + if (init_desc_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize device descriptor: %s", esp_err_to_name(init_desc_err)); + vTaskDelete(NULL); + } + + esp_err_t init_err = bmp280_init(&dev, ¶ms_bmp280); + if (init_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize BMP280: %s", esp_err_to_name(init_err)); + vTaskDelete(NULL); + } + + bool bme280p = dev.id == BME280_CHIP_ID; + + float pressure, temperature, humidity; + + while (1) + { + + if (bmp280_read_float(&dev, &temperature, &pressure, &humidity) == ESP_OK) + { + + ESP_LOGI(__func__, "Temperature: %.1f °C, Pressure: %.1f Pa (%.1fmm)", temperature, pressure, pressure / 1333.224); + + uint16_t new_bmp_temp = (float)(temperature * 100); + uint16_t new_bmp_press = (float)(pressure / 100); + + if ((new_bmp_temp != data.bmp_temp || new_bmp_press != data.bmp_press) && connected) + { + data.bmp_temp = new_bmp_temp; + data.bmp_press = new_bmp_press; + update_attributes(ATTRIBUTE_BMP); + } + } + else + { + ESP_LOGE(__func__, "Could not read data from sensor bmp280"); + } + vTaskDelay(pdMS_TO_TICKS(BMP280_TASK_INTERVAL)); + } +} + +void sensor_bmp280() +{ + ESP_LOGW(__func__, "BMP280 sensor task started"); + xTaskCreate(sensor_bmp280_task, "sensor_bmp280_task", 4096, NULL, 5, NULL); +} diff --git a/main/sensors/bmp280/sensor_bmp280.h b/main/sensors/bmp280/sensor_bmp280.h new file mode 100644 index 0000000..11da145 --- /dev/null +++ b/main/sensors/bmp280/sensor_bmp280.h @@ -0,0 +1 @@ +void sensor_bmp280(); \ No newline at end of file diff --git a/main/sensors/chip_temp/sensor_chip_temp.c b/main/sensors/chip_temp/sensor_chip_temp.c new file mode 100644 index 0000000..8fcc705 --- /dev/null +++ b/main/sensors/chip_temp/sensor_chip_temp.c @@ -0,0 +1,52 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" + +#include "string.h" +#include "driver/temperature_sensor.h" +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +void chip_temp_task(void *pvParameters) +{ + ESP_LOGI(__func__, "initializing temperature sensor"); + temperature_sensor_handle_t temp_handle = NULL; + temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 60); + ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor_config, &temp_handle)); + + ESP_LOGI(__func__, "starting the loop"); + while (1) + { + // Enable temperature sensor + ESP_ERROR_CHECK(temperature_sensor_enable(temp_handle)); + + // Get converted sensor data + float tsens_out; + uint16_t new_chip_temp; + ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &tsens_out)); + + ESP_LOGI(__func__, "Temperature in %f °C", tsens_out); + + // Disable the temperature sensor if it is not needed and save the power + ESP_ERROR_CHECK(temperature_sensor_disable(temp_handle)); + + new_chip_temp = (float)(tsens_out * 100); + + if ((new_chip_temp != data.chip_temp) && connected) + { + data.chip_temp = new_chip_temp; + update_attributes(ATTRIBUTE_CHIP_TEMP); + } + + vTaskDelay(pdMS_TO_TICKS(CPU_TEMP_INTERVAL)); + } +} + +void sensor_chip_temp() +{ + ESP_LOGW(__func__, "CPU temperature sensor task started"); + xTaskCreate(chip_temp_task, "chip_temp_task", 4096, NULL, 3, NULL); +} \ No newline at end of file diff --git a/main/sensors/chip_temp/sensor_chip_temp.h b/main/sensors/chip_temp/sensor_chip_temp.h new file mode 100644 index 0000000..5de2779 --- /dev/null +++ b/main/sensors/chip_temp/sensor_chip_temp.h @@ -0,0 +1 @@ +void sensor_chip_temp(); \ No newline at end of file diff --git a/main/sensors/qmi8658c/sensor_qmi8658c.c b/main/sensors/qmi8658c/sensor_qmi8658c.c new file mode 100644 index 0000000..cb20b24 --- /dev/null +++ b/main/sensors/qmi8658c/sensor_qmi8658c.c @@ -0,0 +1,162 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "string.h" + +#include "qmi8658c.h" +#include + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +void calculate_angles(qmi8658c_data_t *data, float *pitch, float *roll, float *yaw) +{ + *pitch = atan2(-data->acc.x, sqrt(data->acc.y * data->acc.y + data->acc.z * data->acc.z)) * 180 / M_PI; + *roll = atan2(data->acc.y, data->acc.z) * 180 / M_PI; + *yaw = atan2(data->gyro.z, sqrt(data->gyro.x * data->gyro.x + data->gyro.y * data->gyro.y)) * 180 / M_PI; +} + +bool is_stable(qmi8658c_data_t *data, float threshold) +{ + return fabs(data->gyro.x) < threshold && fabs(data->gyro.y) < threshold && fabs(data->gyro.z) < threshold; +} + +typedef enum +{ + POSITION_INCORRECT, + POSITION_HORIZONTAL, + POSITION_VERTICAL +} device_position_t; + +#define PITCH_TOLERANCE 10.0 +#define ROLL_TOLERANCE 25.0 + +device_position_t determine_position(float pitch, float roll) +{ + float table_pitch = 0; + float table_roll = 0; + + float wall_pitch = 90; + float wall_roll = 180; + + if (fabs(pitch - table_pitch) < PITCH_TOLERANCE && fabs(roll - table_roll) < ROLL_TOLERANCE) + { + return POSITION_HORIZONTAL; + } + else if (fabs(pitch - wall_pitch) < PITCH_TOLERANCE && fabs(roll - wall_roll) < ROLL_TOLERANCE) + { + return POSITION_VERTICAL; + } + else + { + return POSITION_INCORRECT; + } +} + +static void sensor_qmi8658c_task(void *pvParameters) +{ + + gpio_num_t pin_SCL = I2C_SCL_GPIO; + gpio_num_t pin_SDA = I2C_SDA_GPIO; + + int I2C_ADDRESS_int = 0x6B; + + i2c_dev_t dev; + memset(&dev, 0, sizeof(i2c_dev_t)); + + esp_err_t init_desc_err = qmi8658c_init_desc(&dev, I2C_ADDRESS_int, 0, pin_SDA, pin_SCL); + if (init_desc_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize device descriptor: %s", esp_err_to_name(init_desc_err)); + vTaskDelete(NULL); + } + + qmi8658c_config_t config = { + .mode = QMI8658C_MODE_DUAL, + .acc_scale = QMI8658C_ACC_SCALE_4G, + .acc_odr = QMI8658C_ACC_ODR_1000, + .gyro_scale = QMI8658C_GYRO_SCALE_64DPS, + .gyro_odr = QMI8658C_GYRO_ODR_8000, + }; // Dual, 4G, 1000, 64DPS, 8000 + + esp_err_t setup_err = qmi8658c_setup(&dev, &config); + if (setup_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to setup QMI8658C: %s", esp_err_to_name(setup_err)); + vTaskDelete(NULL); + } + + vTaskDelay(pdMS_TO_TICKS(1000)); // Wait for the device to boot + int runs = 0; + while (1) + { + qmi8658c_data_t imu_data; + esp_err_t res = qmi8658c_read_data(&dev, &imu_data); + if (res != ESP_OK) + { + ESP_LOGE(__func__, "Could not read sensor data: %d (%s)", res, esp_err_to_name(res)); + } + else + { + bool stable = is_stable(&imu_data, 15); // Threshold for stability + send_zone_1_state(2, !stable); // send as tamper state + ESP_LOGW(__func__, "Device is %s", stable ? "stable" : "not stable"); + + // ESP_LOGI(__func__, "Acc: x=%f, y=%f, z=%f; Gyro: x=%f, y=%f, z=%f; Temp: %f", + // imu_data.acc.x, imu_data.acc.y, imu_data.acc.z, imu_data.gyro.x, imu_data.gyro.y, imu_data.gyro.z, imu_data.temperature); + + if (runs == 2) + { + runs = 0; + } + if (runs == 0) + { + float pitch, roll, yaw; + calculate_angles(&imu_data, &pitch, &roll, &yaw); + + ESP_LOGI(__func__, "Pitch: %f, Roll: %f, Yaw: %f", pitch, roll, yaw); + + device_position_t position = determine_position(pitch, roll); + + switch (position) + { + case POSITION_HORIZONTAL: + ESP_LOGW(__func__, "horizontal"); + break; + case POSITION_VERTICAL: + ESP_LOGW(__func__, "vertical"); + break; + default: + ESP_LOGW(__func__, "position is incorrect"); + break; + } + + uint16_t new_imu_pos = (uint16_t)position; + int32_t new_imu_pitch = (int32_t)(pitch * 1000000); + int32_t new_imu_roll = (int32_t)(roll * 1000000); + int32_t new_imu_yaw = (int32_t)(yaw * 1000000); + + if ((new_imu_pos != data.imu_pos || new_imu_pitch != data.imu_pitch || new_imu_roll != data.imu_roll || new_imu_yaw != data.imu_yaw) && connected) + { + data.imu_pos = new_imu_pos; + data.imu_pitch = new_imu_pitch; + data.imu_roll = new_imu_roll; + data.imu_yaw = new_imu_yaw; + update_attributes(ATTRIBUTE_IMU); + } + } + runs++; + } + + vTaskDelay(pdMS_TO_TICKS(QMI8658C_TASK_INTERVAL)); + } +} + +void sensor_qmi8658c() +{ + ESP_LOGW(__func__, "QMI8658C sensor task started"); + xTaskCreate(sensor_qmi8658c_task, "sensor_qmi8658c_task", 4096, NULL, 5, NULL); +} \ No newline at end of file diff --git a/main/sensors/qmi8658c/sensor_qmi8658c.h b/main/sensors/qmi8658c/sensor_qmi8658c.h new file mode 100644 index 0000000..4b6e56a --- /dev/null +++ b/main/sensors/qmi8658c/sensor_qmi8658c.h @@ -0,0 +1 @@ +void sensor_qmi8658c(); diff --git a/main/sensors/scd4x/sensor_scd4x.c b/main/sensors/scd4x/sensor_scd4x.c new file mode 100644 index 0000000..c6faf1e --- /dev/null +++ b/main/sensors/scd4x/sensor_scd4x.c @@ -0,0 +1,140 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" +#include "string.h" + +#include "scd4x.h" + +#include "../../const.h" +#include "../../zigbee.h" +#include "../../main.h" + +static void sensor_scd4x_task(void *pvParameters) +{ + + gpio_num_t pin_SCL = I2C_SCL_GPIO; + gpio_num_t pin_SDA = I2C_SDA_GPIO; + + i2c_dev_t dev; + memset(&dev, 0, sizeof(i2c_dev_t)); + + esp_err_t init_desc_err = scd4x_init_desc(&dev, 0, pin_SDA, pin_SCL); + if (init_desc_err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to initialize device descriptor: %s", esp_err_to_name(init_desc_err)); + vTaskDelete(NULL); + } + + ESP_LOGI(__func__, "Initializing sensor..."); + + if (scd4x_wake_up(&dev) != ESP_OK) + { + ESP_LOGW(__func__, "Failed to wake up sensor. Maybe it's already awake?"); + } + + if (scd4x_stop_periodic_measurement(&dev) != ESP_OK) + { + ESP_LOGE(__func__, "Failed to stop periodic measurement"); + vTaskDelete(NULL); + } + + if (scd4x_reinit(&dev) != ESP_OK) + { + ESP_LOGE(__func__, "Failed to reinit sensor. Need to power cycle the device"); + } + + uint16_t serial[3]; + if (scd4x_get_serial_number(&dev, serial, serial + 1, serial + 2) != ESP_OK) + { + ESP_LOGE(__func__, "Failed to get sensor serial number"); + } + else + { + ESP_LOGI(__func__, "Sensor serial number: 0x%04x%04x%04x", serial[0], serial[1], serial[2]); + } + + if (scd4x_start_periodic_measurement(&dev) != ESP_OK) + { + ESP_LOGE(__func__, "Failed to start periodic measurement"); + vTaskDelete(NULL); + } + + uint16_t co2; + float temperature, humidity; + + while (1) + { + // bool com_ok = false; + // int retries1 = 0; + // while (!com_ok && retries1 < 3) + //{ + // esp_err_t res1 = scd4x_measure_single_shot(&dev); + // retries1++; + /*if (res1 != ESP_OK) + { + ESP_LOGE(__func__, "Error asking results %d (%s) retries: %d", res1, esp_err_to_name(res1), retries1); + vTaskDelay(pdMS_TO_TICKS(2000)); + continue; + }*/ + //} + // Wait for data to be ready + uint16_t pressure = data.bmp_press; + if (pressure != 0) + { + if (scd4x_set_ambient_pressure(&dev, pressure) != ESP_OK) + { + ESP_LOGE(__func__, "Failed to set ambient pressure"); + } + } + + bool data_ready = false; + int retries = 0; + while (!data_ready && retries < 10) + { + vTaskDelay(pdMS_TO_TICKS(2000)); // Poll every 100ms + esp_err_t res2 = scd4x_get_data_ready_status(&dev, &data_ready); + retries++; + if (res2 != ESP_OK) + { + ESP_LOGE(__func__, "Error polling results %d (%s) retries: %d", res2, esp_err_to_name(res2), retries); + continue; + } + } + + esp_err_t res = scd4x_read_measurement(&dev, &co2, &temperature, &humidity); + if (res != ESP_OK) + { + ESP_LOGE(__func__, "Error reading results %d (%s)", res, esp_err_to_name(res)); + continue; + } + + if (co2 == 0) + { + ESP_LOGW(__func__, "Invalid sample detected, skipping"); + continue; + } + + ESP_LOGI(__func__, "CO2: %u ppm, Temperature: %.2f °C, Humidity: %.2f %%", co2, temperature, humidity); + + uint16_t new_scd4x_co2 = (uint16_t)(co2); + uint16_t new_scd4x_temp = (uint16_t)(temperature * 100); + uint16_t new_scd4x_hum = (uint16_t)(humidity * 100); + + if ((new_scd4x_co2 != data.scd_co2 || new_scd4x_temp != data.scd_temp || new_scd4x_hum != data.scd_hum) && connected) + { + data.scd_co2 = new_scd4x_co2; + data.scd_temp = new_scd4x_temp; + data.scd_hum = new_scd4x_hum; + update_attributes(ATTRIBUTE_SCD); + } + vTaskDelay(pdMS_TO_TICKS(SCD4X_TASK_INTERVAL)); + } +} + +void sensor_scd4x() +{ + ESP_LOGW(__func__, "SCD4x sensor task started"); + xTaskCreate(sensor_scd4x_task, "sensor_scd4x_task", 4096, NULL, 5, NULL); +} \ No newline at end of file diff --git a/main/sensors/scd4x/sensor_scd4x.h b/main/sensors/scd4x/sensor_scd4x.h new file mode 100644 index 0000000..41ab724 --- /dev/null +++ b/main/sensors/scd4x/sensor_scd4x.h @@ -0,0 +1 @@ +void sensor_scd4x(); diff --git a/main/tools.c b/main/tools.c new file mode 100644 index 0000000..8e01d1f --- /dev/null +++ b/main/tools.c @@ -0,0 +1,340 @@ + +#include "nvs_flash.h" +#include "esp_log.h" +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "esp_system.h" +#include "esp_mac.h" +#include +#include "string.h" +#include "i2cdev.h" + +#include "main.h" +#include "tools.h" +#include "const.h" +#include "zigbee.h" + +void get_rtc_time() +{ + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%a %H:%M:%S", &timeinfo); +} + +bool int_to_bool(int32_t value) +{ + return (value != 0); +} + +void setup_NVS() +{ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + // NVS partition was truncated and needs to be erased + // Retry nvs_flash_init + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + nvs_handle_t my_handle; + err = nvs_open("storage", NVS_READWRITE, &my_handle); + ESP_LOGI(__func__, "Opening Non-Volatile Storage (NVS) handle... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + if (err == ESP_OK) + { + + // Read + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_counter", &restart_counter); + ESP_LOGI(__func__, "Reading restart counter from NVS ... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + switch (err) + { + case ESP_OK: + ESP_LOGI(__func__, "Restart counter = %" PRIu32, restart_counter); + break; + case ESP_ERR_NVS_NOT_FOUND: + ESP_LOGI(__func__, "The value is not initialized yet!"); + break; + default: + ESP_LOGI(__func__, "Error (%s) reading!", esp_err_to_name(err)); + } + + // Write + restart_counter++; + err = nvs_set_i32(my_handle, "restart_counter", restart_counter); + ESP_LOGI(__func__, "Updating restart counter in NVS ... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + err = nvs_commit(my_handle); + ESP_LOGI(__func__, "Committing updates in NVS ... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + + // Close + nvs_close(my_handle); + } +} + +int read_NVS(const char *nvs_key) +{ + nvs_handle_t my_handle; + esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle); + + // Read + // ESP_LOGI(__func__, "Reading restart counter from NVS ... "); + // int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + int32_t value = 0; + err = nvs_get_i32(my_handle, nvs_key, &value); + switch (err) + { + case ESP_OK: + ESP_LOGI(__func__, "%s is %ld ", nvs_key, value); + break; + case ESP_ERR_NVS_NOT_FOUND: + ESP_LOGE(__func__, "The value is not initialized yet!"); + int value = 1; + + /*char *substring = "_led_mode"; + if (strstr(nvs_key, substring) != NULL) + { + value = 1; + }*/ + err = nvs_set_i32(my_handle, nvs_key, value); + ESP_LOGW(__func__, "Updating %s in NVS ... %s", nvs_key, (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + break; + default: + ESP_LOGE(__func__, "Error (%s) reading!", esp_err_to_name(err)); + } + // Close + nvs_close(my_handle); + if (err != ESP_OK) + { + return false; + } + return value; +} + +bool write_NVS(const char *nvs_key, int value) +{ + nvs_handle_t my_handle; + esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle); + err = nvs_set_i32(my_handle, nvs_key, value); + ESP_LOGI(__func__, "Write value... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + err = nvs_commit(my_handle); + ESP_LOGI(__func__, "Commit updates... %s", (err != ESP_OK) ? T_STATUS_FAILED : T_STATUS_DONE); + + // Close + nvs_close(my_handle); + + if (err != ESP_OK) + { + return false; + } + return true; +} + +const char *get_endpoint_name(int endpoint) +{ + switch (endpoint) + { + case DEVICE_ENDPOINT: + return "DEVICE"; + case AHT20_ENDPOINT: + return "AHT20"; + case BMP280_ENDPOINT: + return "BMP280"; + case SCD40_ENDPOINT: + return "SCD40"; + case BH1750_ENDPOINT: + return "BH1750"; + case AGS10_ENDPOINT: + return "AGS10"; + case IMU_BASE_ENDPOINT: + return "IMU_FIRST"; + default: + return "Unknown"; + } +} + +float random_float(float min, float max) +{ + return min + (max - min) * ((float)rand() / RAND_MAX); +} + +float round_to_decimals(float value, int decimals) +{ + float multiplier = powf(10.0f, decimals); + return roundf(value * multiplier) / multiplier; +} + +void set_zcl_string(char *buffer, char *value) +{ + buffer[0] = (char)strlen(value); + memcpy(buffer + 1, value, buffer[0]); +} + +void set_bit(uint8_t *byte, uint8_t bit_index, bool value) +{ + if (bit_index >= 8) + { + ESP_LOGE(__func__, "Invalid bit index: %d", bit_index); + return; + } + + if (value) + { + *byte |= (1 << bit_index); + } + else + { + *byte &= ~(1 << bit_index); + } +} + +void print_chip_info() +{ + esp_chip_info_t chip_info; + uint32_t flash_size; + uint8_t mac[6]; + + esp_chip_info(&chip_info); + + ESP_LOGW(__func__, "This is %s chip with %d CPU core(s), %s%s%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", + (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", + (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); + + unsigned major_rev = chip_info.revision / 100; + unsigned minor_rev = chip_info.revision % 100; + ESP_LOGW(__func__, "Silicon revision v%d.%d", major_rev, minor_rev); + + if (esp_flash_get_size(NULL, &flash_size) != ESP_OK) + { + ESP_LOGE(__func__, "Get flash size failed"); + return; + } + + ESP_LOGW(__func__, "%" PRIu32 "MB %s flash", + flash_size / (uint32_t)(1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + ESP_LOGW(__func__, "Minimum free heap size: %" PRIu32 " bytes", esp_get_minimum_free_heap_size()); + + if (esp_read_mac(mac, ESP_MAC_WIFI_STA) == ESP_OK) + { + ESP_LOGW(__func__, "Base MAC (WiFi STA): %02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else if (esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP) == ESP_OK) + { + ESP_LOGW(__func__, "Base MAC (WiFi SoftAP): %02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else if (esp_read_mac(mac, ESP_MAC_BT) == ESP_OK) + { + ESP_LOGW(__func__, "Base MAC (Bluetooth): %02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else if (esp_read_mac(mac, ESP_MAC_ETH) == ESP_OK) + { + ESP_LOGW(__func__, "Base MAC (Ethernet): %02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else + { + ESP_LOGE(__func__, "Failed to get any MAC address"); + } +} + +void heap_stats() +{ + multi_heap_info_t heap_info; + heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT); + + size_t total_heap_size = heap_caps_get_total_size(MALLOC_CAP_8BIT); + size_t free_heap_size = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t largest_free_block = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + size_t minimum_free_size = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); + + float frag_heap_percentage = 0.0; + if (free_heap_size > 0) + { + frag_heap_percentage = (1.0 - ((float)largest_free_block / (float)free_heap_size)) * 100.0; + } + + float free_heap_percentage = ((float)free_heap_size / (float)total_heap_size) * 100.0; + + ESP_LOGI(__func__, "total: %d, free: %d, largest free block: %d, minimum free size: %d", + total_heap_size, + free_heap_size, + largest_free_block, + minimum_free_size); + + ESP_LOGE(__func__, "free: %.2f%% (%d bytes), fragmentation: %.2f%%", + free_heap_percentage, + free_heap_size, + frag_heap_percentage); +} + +void debug_task(void *pvParameters) +{ + ESP_LOGW(__func__, "started"); + while (1) + { + heap_stats(); + if (connected) + { + if (!time_updated) + { + ESP_LOGE(__func__, "Time not updated yet"); + } + } + vTaskDelay(pdMS_TO_TICKS(DEBUG_TASK_INTERVAL)); + } +} + +void scan_i2c_bus(gpio_num_t sda_pin, gpio_num_t scl_pin) +{ + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = sda_pin; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = scl_pin; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = 100000; + conf.clk_flags = 0; + + ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0)); + + ESP_LOGI(__func__, "Scanning I2C bus..."); + + for (uint8_t addr = 1; addr < 127; addr++) + { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_stop(cmd); + + esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(1000)); + i2c_cmd_link_delete(cmd); + + if (ret == ESP_OK) + { + ESP_LOGI(__func__, "Found device at address 0x%02x", addr); + } + } + + ESP_ERROR_CHECK(i2c_driver_delete(I2C_NUM_0)); +} \ No newline at end of file diff --git a/main/tools.h b/main/tools.h new file mode 100644 index 0000000..addcf48 --- /dev/null +++ b/main/tools.h @@ -0,0 +1,28 @@ +#ifndef TOOLS_H +#define TOOLS_H + +#include +#include + +void get_rtc_time(); +bool int_to_bool(int32_t value); + +void setup_NVS(); +int read_NVS(const char *nvs_key); +bool write_NVS(const char *nvs_key, int value); + +const char *get_endpoint_name(int endpoint); +float random_float(float min, float max); +float round_to_decimals(float value, int decimals); + +void set_zcl_string(char *buffer, char *value); +void set_bit(uint8_t *byte, uint8_t bit_index, bool value); + +void print_chip_info(); +void heap_stats(); + +void debug_task(void *pvParameters); + +void scan_i2c_bus(gpio_num_t sda_pin, gpio_num_t scl_pin); + +#endif // TOOLS_H \ No newline at end of file diff --git a/main/zigbee.c b/main/zigbee.c new file mode 100644 index 0000000..3f95bc5 --- /dev/null +++ b/main/zigbee.c @@ -0,0 +1,1171 @@ + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "string.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "zcl/esp_zigbee_zcl_common.h" +#include +#include + +#include "ha/esp_zigbee_ha_standard.h" +#include "esp_timer.h" +#include "esp_ota_ops.h" +#include "zboss_api.h" +#include "zcl/esp_zigbee_zcl_command.h" +#include "zcl/zb_zcl_common.h" + +#include "iot_button.h" + +#include "const.h" +#include "main.h" +#include "perf.h" +#include "tools.h" +#include "zigbee.h" + +/*------ Global definitions -----------*/ + +static const esp_partition_t *s_ota_partition = NULL; +static esp_ota_handle_t s_ota_handle = 0; + +static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) +{ + ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); +} + +/* Manual reporting atribute to coordinator */ +static void reportAttribute(uint8_t endpoint, uint16_t clusterID, uint16_t attributeID, void *value, uint8_t value_length) +{ + esp_zb_zcl_report_attr_cmd_t cmd = { + .zcl_basic_cmd = { + .dst_addr_u.addr_short = 0x0000, + .dst_endpoint = endpoint, + .src_endpoint = endpoint, + }, + .address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT, + .clusterID = clusterID, + .attributeID = attributeID, + .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + }; + esp_zb_zcl_attr_t *value_r = esp_zb_zcl_get_attribute(endpoint, clusterID, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, attributeID); + memcpy(value_r->data_p, value, value_length); + esp_zb_zcl_report_attr_cmd_req(&cmd); +} + +static void update_attribute_value(uint8_t endpoint, uint16_t cluster_id, uint8_t role, uint16_t attr_id, void *value, const char *attr_name) +{ + // uint16_t val = *((uint16_t *)value); + // ESP_LOGW(__func__, "Value: %d, val = %d", *((uint16_t *)value), val); + ESP_LOGW(__func__, "Setting on endpoint %d, cluster 0x%04x, attribute 0x%04x, value %d", endpoint, cluster_id, attr_id, *((uint16_t *)value)); // val); + + esp_zb_zcl_status_t status = esp_zb_zcl_set_attribute_val(endpoint, cluster_id, role, attr_id, value, false); //&val, false); + if (status != ESP_ZB_ZCL_STATUS_SUCCESS) + { + ESP_LOGE(__func__, "Setting %s attribute failed, with status %d. Value: %d", attr_name, status, *((uint16_t *)value)); // val); + } +} + +void update_attributes(attribute_t attribute) +{ + ESP_LOGI(__func__, "updating %d", attribute); + + if (attribute == ATTRIBUTE_CHIP_TEMP || attribute == ATTRIBUTE_ALL) + { + update_attribute_value(DEVICE_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &data.chip_temp, "temperature"); + } + + if (attribute == ATTRIBUTE_AHT || attribute == ATTRIBUTE_ALL) + { + update_attribute_value(AHT20_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &data.aht_temp, "aht temperature"); + update_attribute_value(AHT20_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &data.aht_hum, "aht humidity"); + } + + if (attribute == ATTRIBUTE_BMP || attribute == ATTRIBUTE_ALL) + { + update_attribute_value(BMP280_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &data.bmp_temp, "bmp temperature"); + update_attribute_value(BMP280_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, &data.bmp_press, "bmp pressure"); + } + + if (attribute == ATTRIBUTE_SCD || attribute == ATTRIBUTE_ALL) + { + float scd_co2_value = (float)data.scd_co2 / 1000000.0f; + update_attribute_value(SCD40_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, &scd_co2_value, "scd co2"); + update_attribute_value(SCD40_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &data.scd_temp, "scd temperature"); + update_attribute_value(SCD40_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &data.scd_hum, "scd humidity"); + } + + if (attribute == ATTRIBUTE_LUX || attribute == ATTRIBUTE_ALL) + { + update_attribute_value(BH1750_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID, &data.lux, "lux"); + } + + if (attribute == ATTRIBUTE_VOC || attribute == ATTRIBUTE_ALL) + { + // update_attribute_value(AGS10_ENDPOINT, TVOC_CLUSTER, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, TVOC_ATTR, &data.voc, "VOC"); + + float voc_value = data.voc * 1.0f; + update_attribute_value(AGS10_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &voc_value, "VOC"); + } + + if (attribute == ATTRIBUTE_IMU || attribute == ATTRIBUTE_ALL) + { + /* + char imu_txt[99]; + char zb_imu_str[100]; + + snprintf(imu_txt, sizeof(imu_txt), "P: %.3f R: %.3f Y: %.3f", + data.imu_pitch / 1000.0, data.imu_roll / 1000.0, data.imu_yaw / 1000.0); + + set_zcl_string(zb_imu_str, imu_txt); + + update_attribute_value(IMU_BASE_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_MULTISTATE_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_MULTISTATE_DESCRIPTION_ID, &zb_imu_str, "imu txt"); + */ + + update_attribute_value(IMU_BASE_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_MULTISTATE_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_PRESENT_VALUE_ID, &data.imu_pos, "imu pos"); + + float imu_pos_value = data.imu_pos * 1.0f; + update_attribute_value(IMU_BASE_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &imu_pos_value, "imu position"); + + float pitch = (data.imu_pitch / 1000000.0f); + ESP_LOGW(__func__, "Pitch: %f", pitch); + update_attribute_value(IMU_BASE_ENDPOINT + 1, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &pitch, "pitch"); + + float roll = (data.imu_roll / 1000000.0f); + ESP_LOGW(__func__, "Roll: %f", roll); + update_attribute_value(IMU_BASE_ENDPOINT + 2, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &roll, "roll"); + + float yaw = (data.imu_yaw / 1000000.0f); + ESP_LOGW(__func__, "Yaw: %f", yaw); + update_attribute_value(IMU_BASE_ENDPOINT + 3, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &yaw, "yaw"); + } + + if (attribute == ATTRIBUTE_ADC || attribute == ATTRIBUTE_ALL) + { + float adc1_value = data.adc1 * 1.0f; + float adc2_value = data.adc2 * 1.0f; + update_attribute_value(ADC1_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &adc1_value, "adc 1"); + update_attribute_value(ADC2_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &adc2_value, "adc 2"); + } +} + +/* Task for update all values */ +void force_update_task() +{ + while (1) + { + vTaskDelay(WAIT_BEFORE_FIRST_UPDATE / portTICK_PERIOD_MS); + force_update(); + vTaskDelay((UPDATE_ATTRIBUTE_INTERVAL - WAIT_BEFORE_FIRST_UPDATE) / portTICK_PERIOD_MS); + } +} + +/* Function to update all values */ +void force_update() +{ + + if (connected) + { + led_blink(500); + + // send_bin_cfg_option(DEVICE_ENDPOINT, data.USB_state); + // send_bin_cfg_option(INT_LED_ENDPOINT, data.led_mode); + // send_bin_cfg_option(EXT_LED_ENDPOINT, data.ext_led_mode); + // send_bin_cfg_option(INV_USB_ENDPOINT, 0); + + send_zone_1_state(0, 2); + + update_attributes(ATTRIBUTE_ALL); + } +} + +static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(message, ESP_FAIL, __func__, "Empty message"); + ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, __func__, "Received message: error status(%d)", + message->info.status); + ESP_LOGI(__func__, "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", message->info.dst_endpoint, message->info.cluster, + message->attribute.id, message->attribute.data.size); + if (message->info.dst_endpoint == DEVICE_ENDPOINT) + { + switch (message->info.cluster) + { + case ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY: + + int time = *(int *)message->attribute.data.value; + if (time > data.old_identify_time) + { + data.old_identify_time = time; + + ESP_LOGI(__func__, "Identify pressed, time: %ds", time); + + if (time < 3) // Minimum time is 3 seconds + { + ESP_LOGW(__func__, "Identify time is too short, setting to 3 seconds"); + time = 3; + } + + xTaskCreate(identify_task, "identify_task", 4096, (void *)time, 3, NULL); + } + + break; + case ESP_ZB_ZCL_CLUSTER_ID_ON_OFF: + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_START_UP_ON_OFF) + { + int value = *(int *)message->attribute.data.value; + if (value == 0 || value == 1 || value == 2 || value == 255) + { + ESP_LOGW(__func__, "Power-on behavior %d", value); + // data.start_up_on_off = value; + // write_NVS("start_up_on_off", data.start_up_on_off); + } + else + { + ESP_LOGE(__func__, "Invalid power-on behavior value: %d", value); + } + } + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_TIME) + { + ESP_LOGI(__func__, "On time %d", *(int *)message->attribute.data.value); + } + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_OFF_WAIT_TIME) + { + ESP_LOGI(__func__, "Off wait time %d", *(int *)message->attribute.data.value); + } + break; + default: + ESP_LOGI(__func__, "Message data: cluster(0x%x), attribute(0x%x) ", message->info.cluster, message->attribute.id); + } + } + // bool usb_state = 0; + /*if (message->info.dst_endpoint == HA_ONOFF_SWITCH_ENDPOINT) + { + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) + { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) + { + usb_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : usb_state; + ESP_LOGI(__func__, "USB sets to %s", usb_state ? "On" : "Off"); + usb_driver_set_power(usb_state); + } + } + }*/ + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) + { + // ESP_LOGI(__func__, "Message data: cluster(0x%x), attribute(0x%x) ", message->info.cluster, message->attribute.id); + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) + { + /* + if (message->info.dst_endpoint == DEVICE_ENDPOINT) + { + bool usb_state = + message->attribute.data.value ? *(bool *)message->attribute.data.value : 0; + ESP_LOGI(__func__, "USB sets to %s", usb_state ? "On" : "Off"); + // usb_driver_set_power(usb_state); + } + else + { + bool switch_state = + message->attribute.data.value ? *(bool *)message->attribute.data.value : 0; + ESP_LOGI(__func__, "Endpoint %d, sets to %s", message->info.dst_endpoint, switch_state ? "On" : "Off"); + + if (message->info.dst_endpoint == INT_LED_ENDPOINT) + { + if (switch_state == 0) + { + gpio_set_level(INT_LED_GPIO, LED_OFF_STATE); + } + data.led_mode = switch_state; + write_NVS("led_mode", switch_state); + } + else if (message->info.dst_endpoint == EXT_LED_ENDPOINT) + { + if (switch_state == 0) + { + ESP_LOGI(__func__, "cmd is OFF, so EXT_LED_GPIO (1)"); + gpio_set_level(EXT_LED_GPIO, 1); + } + else if (data.USB_state == 1) + { + ESP_LOGI(__func__, "USB is ON, so EXT_LED_GPIO (0)"); + gpio_set_level(EXT_LED_GPIO, 0); + } + data.ext_led_mode = switch_state; + write_NVS("ext_led_mode", switch_state); + } + else if (message->info.dst_endpoint == INV_USB_ENDPOINT) + { + // inverted logic to make possible onWithOff work + bool new_state = !(switch_state); + usb_driver_set_power(new_state); + send_bin_cfg_option(DEVICE_ENDPOINT, new_state); + } + } + */ + } + } + return ret; +} + +static esp_err_t zb_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message) +{ + + ESP_RETURN_ON_FALSE(message, ESP_FAIL, __func__, "Empty message"); + ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, __func__, "Received message: error status(%d)", + message->info.status); + + esp_zb_zcl_read_attr_resp_variable_t *variable = message->variables; + while (variable) + { + ESP_LOGI(__func__, "Read attribute response: status(%d), cluster(0x%x), attribute(0x%x), type(0x%x), value(%d)", variable->status, + message->info.cluster, variable->attribute.id, variable->attribute.data.type, + variable->attribute.data.value ? *(uint8_t *)variable->attribute.data.value : 0); + + if (message->info.dst_endpoint == DEVICE_ENDPOINT) + { + switch (message->info.cluster) + { + case ESP_ZB_ZCL_CLUSTER_ID_TIME: + ESP_LOGW(__func__, "Server time recieved %lu", *(uint32_t *)variable->attribute.data.value); + struct timeval tv; + tv.tv_sec = *(uint32_t *)variable->attribute.data.value + 946684800; + settimeofday(&tv, NULL); + time_updated = true; + + uint32_t boot_time = *(uint32_t *)variable->attribute.data.value; + ESP_LOGI(__func__, "Write new boot time %lu", boot_time); + esp_zb_zcl_status_t state_boot_time = esp_zb_zcl_set_attribute_val(DEVICE_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_LAST_SET_TIME_ID, &boot_time, false); + if (state_boot_time != ESP_ZB_ZCL_STATUS_SUCCESS) + { + ESP_LOGE(__func__, "Setting boot time attribute failed!"); + } + + break; + default: + ESP_LOGI(__func__, "Message data: cluster(0x%x), attribute(0x%x) ", message->info.cluster, variable->attribute.id); + } + } + + variable = variable->next; + } + + return ESP_OK; +} + +size_t ota_data_len_; +size_t ota_header_len_; +bool ota_upgrade_subelement_; +uint8_t ota_header_[6]; + +static esp_err_t zb_ota_upgrade_status_handler(esp_zb_zcl_ota_upgrade_value_message_t message) +{ + static uint32_t total_size = 0; + static uint32_t offset = 0; + static int64_t start_time = 0; + esp_err_t ret = ESP_OK; + + if (message.info.status == ESP_ZB_ZCL_STATUS_SUCCESS) + { + switch (message.upgrade_status) + { + case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_START: + ESP_LOGI(__func__, "-- OTA upgrade start"); + start_time = esp_timer_get_time(); + s_ota_partition = esp_ota_get_next_update_partition(NULL); + assert(s_ota_partition); + ret = esp_ota_begin(s_ota_partition, 0, &s_ota_handle); + ESP_RETURN_ON_ERROR(ret, __func__, "Failed to begin OTA partition, status: %s", esp_err_to_name(ret)); + break; + case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_RECEIVE: + size_t payload_size = message.payload_size; + const uint8_t *payload = message.payload; + + total_size = message.ota_header.image_size; + offset += payload_size; + + ESP_LOGI(__func__, "-- OTA Client receives data: progress [%ld/%ld]", offset, total_size); + + /* Read and process the first sub-element, ignoring everything else */ + while (ota_header_len_ < 6 && payload_size > 0) + { + ota_header_[ota_header_len_] = payload[0]; + ota_header_len_++; + payload++; + payload_size--; + } + + if (!ota_upgrade_subelement_ && ota_header_len_ == 6) + { + if (ota_header_[0] == 0 && ota_header_[1] == 0) + { + ota_upgrade_subelement_ = true; + ota_data_len_ = + (((int)ota_header_[5] & 0xFF) << 24) | (((int)ota_header_[4] & 0xFF) << 16) | (((int)ota_header_[3] & 0xFF) << 8) | ((int)ota_header_[2] & 0xFF); + ESP_LOGD(__func__, "OTA sub-element size %zu", ota_data_len_); + } + else + { + ESP_LOGE(__func__, "OTA sub-element type %02x%02x not supported", ota_header_[0], ota_header_[1]); + return ESP_FAIL; + } + } + + if (ota_data_len_) + { + payload_size = fmin(ota_data_len_, payload_size); + ota_data_len_ -= payload_size; + + if (message.payload_size && message.payload) + { + ret = esp_ota_write(s_ota_handle, payload, payload_size); + ESP_RETURN_ON_ERROR(ret, __func__, "Failed to write OTA data to partition, status: %s", esp_err_to_name(ret)); + } + } + break; + case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_APPLY: + ESP_LOGI(__func__, "-- OTA upgrade apply"); + break; + case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_CHECK: + ret = offset == total_size ? ESP_OK : ESP_FAIL; + ESP_LOGI(__func__, "-- OTA upgrade check status: %s", esp_err_to_name(ret)); + break; + case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_FINISH: + ESP_LOGI(__func__, "-- OTA Finish"); + ESP_LOGI(__func__, "-- OTA Information: version: 0x%lx, manufacturer code: 0x%x, image type: 0x%x, total size: %ld bytes, cost time: %lld ms,", + message.ota_header.file_version, message.ota_header.manufacturer_code, message.ota_header.image_type, + message.ota_header.image_size, (esp_timer_get_time() - start_time) / 1000); + ret = esp_ota_end(s_ota_handle); + ESP_RETURN_ON_ERROR(ret, __func__, "Failed to end OTA partition, status: %s", esp_err_to_name(ret)); + ret = esp_ota_set_boot_partition(s_ota_partition); + ESP_RETURN_ON_ERROR(ret, __func__, "Failed to set OTA boot partition, status: %s", esp_err_to_name(ret)); + ESP_LOGW(__func__, "Prepare to restart system"); + esp_restart(); + break; + default: + ESP_LOGI(__func__, "OTA status: %d", message.upgrade_status); + break; + } + } + return ret; +} + +static esp_err_t zb_ota_upgrade_query_image_resp_handler(esp_zb_zcl_ota_upgrade_query_image_resp_message_t message) +{ + esp_err_t ret = ESP_OK; + if (message.info.status == ESP_ZB_ZCL_STATUS_SUCCESS) + { + ESP_LOGI(__func__, "Queried OTA image from address: 0x%04hx, endpoint: %d", message.server_addr.u.short_addr, message.server_endpoint); + ESP_LOGI(__func__, "Image version: 0x%lx, manufacturer code: 0x%x, image size: %ld", message.file_version, message.manufacturer_code, + message.image_size); + } + if (ret == ESP_OK) + { + ESP_LOGI(__func__, "Approving OTA image upgrade"); + } + else + { + ESP_LOGI(__func__, "Rejecting OTA image upgrade, status: %s", esp_err_to_name(ret)); + } + return ret; +} + +static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) +{ + esp_err_t ret = ESP_OK; + switch (callback_id) + { + // case ESP_ZB_CORE_IDENTIFY_EFFECT_CB_ID: + // ret = esp_zb_zcl_identify_cmd_req((esp_zb_zcl_identify_cmd_t *)message); + // ESP_LOGW(__func__, "ESP_ZB_CORE_IDENTIFY_EFFECT_CB_ID"); + // break; + case ESP_ZB_CORE_CMD_WRITE_ATTR_RESP_CB_ID: + ESP_LOGW(__func__, "ESP_ZB_CORE_CMD_WRITE_ATTR_RESP_CB_ID"); + break; + case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: + ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message); + ESP_LOGW(__func__, "CORE_SET_ATTR_VALUE_CB action(0x%x) callback", callback_id); + break; + case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID: + ret = zb_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message); + ESP_LOGW(__func__, "CORE_CMD_READ_ATTR_RESP_CB action(0x%x) callback", callback_id); + break; + case ESP_ZB_CORE_OTA_UPGRADE_VALUE_CB_ID: + ret = zb_ota_upgrade_status_handler(*(esp_zb_zcl_ota_upgrade_value_message_t *)message); + break; + case ESP_ZB_CORE_OTA_UPGRADE_SRV_QUERY_IMAGE_CB_ID: + ret = zb_ota_upgrade_query_image_resp_handler(*(esp_zb_zcl_ota_upgrade_query_image_resp_message_t *)message); + break; + default: + ESP_LOGD(__func__, "Receive Zigbee action(0x%x) callback", callback_id); + break; + } + return ret; +} + +void read_server_time() +{ + esp_zb_zcl_read_attr_cmd_t read_req; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_LOCAL_TIME_ID}; + + read_req.attr_number = sizeof(attributes) / sizeof(uint16_t); + read_req.attr_field = attributes; + + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME; + + read_req.zcl_basic_cmd.dst_endpoint = 1; // Coordinator + read_req.zcl_basic_cmd.src_endpoint = DEVICE_ENDPOINT; // Device main endpoint + read_req.zcl_basic_cmd.dst_addr_u.addr_short = 0x0000; + esp_zb_zcl_read_attr_cmd_req(&read_req); +} + +void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) +{ + uint32_t *p_sg_p = signal_struct->p_app_signal; + esp_err_t err_status = signal_struct->esp_err_status; + esp_zb_app_signal_type_t sig_type = *p_sg_p; + esp_zb_zdo_signal_leave_params_t *leave_params = NULL; + switch (sig_type) + { + case ESP_ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY: + esp_zb_set_node_descriptor_manufacturer_code(manuf_id); + break; + case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: + case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: + case ESP_ZB_BDB_SIGNAL_STEERING: + if (err_status != ESP_OK) + { + connected = false; + led_hz = 2; + ESP_LOGW(__func__, "Stack %s failure with %s status, steering", esp_zb_zdo_signal_to_string(sig_type), esp_err_to_name(err_status)); + esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000); + } + else + { + /* device auto start successfully and on a formed network */ + connected = true; + led_hz = 0; + esp_zb_ieee_addr_t extended_pan_id; + esp_zb_get_extended_pan_id(extended_pan_id); + ESP_LOGI(__func__, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)", + extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], + extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], + esp_zb_get_pan_id(), esp_zb_get_current_channel()); + read_server_time(); + } + break; + case ESP_ZB_ZDO_SIGNAL_LEAVE: + leave_params = (esp_zb_zdo_signal_leave_params_t *)esp_zb_app_signal_get_params(p_sg_p); + if (leave_params->leave_type == ESP_ZB_NWK_LEAVE_TYPE_RESET) + { + ESP_LOGI(__func__, "Reset device"); + esp_zb_factory_reset(); + } + break; + default: + ESP_LOGI(__func__, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, + esp_err_to_name(err_status)); + break; + } +} + +void print_custom_attributes(const esp_zb_attribute_list_t *attr_list) +{ + const esp_zb_attribute_list_t *current = attr_list; + int index = 0; + + while (current != NULL) + { + ESP_LOGI(__func__, "Attribute %d: Cluster ID=0x%04x, Attribute ID=0x%04x, Type=0x%02x, Access=0x%02x, Manuf Code=0x%04x", + index, current->cluster_id, current->attribute.id, current->attribute.type, current->attribute.access, current->attribute.manuf_code); + + // Вывод значения атрибута в зависимости от его типа + switch (current->attribute.type) + { + case ZB_ZCL_ATTR_TYPE_U8: + ESP_LOGI(__func__, "Value: %u", *(uint8_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_U16: + ESP_LOGI(__func__, "Value: %u", *(uint16_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_U32: + ESP_LOGI(__func__, "Value: %lu", *(uint32_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_S8: + ESP_LOGI(__func__, "Value: %d", *(int8_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_S16: + ESP_LOGI(__func__, "Value: %d", *(int16_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_S32: + ESP_LOGI(__func__, "Value: %li", *(int32_t *)current->attribute.data_p); + break; + case ZB_ZCL_ATTR_TYPE_CHAR_STRING: + ESP_LOGI(__func__, "Value: %s", (char *)current->attribute.data_p); + break; + default: + ESP_LOGI(__func__, "Value: (unknown type)"); + break; + } + + current = current->next; + index++; + } +} + +static void zigbee_config_endpoints_attributes() +{ + uint16_t undefined_value; + undefined_value = 0x8000; + + uint16_t hundred_value = 10000; + uint16_t one_value = 1; + uint16_t zero_value = 0; + + float undefined_float = 0; + float float_zero = 0; + float float_one = 1; + + uint16_t cluster_id; + uint16_t attr_id; + uint8_t attr_type = ESP_ZB_ZCL_ATTR_TYPE_U16; + uint8_t attr_access = ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING; + + esp_zb_ep_list_t *esp_zb_ep_list = esp_zb_ep_list_create(); + + // DEVICE_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list1 = esp_zb_zcl_cluster_list_create(); + + // Basic cluster start + set_zcl_string(manufacturer, HW_MANUFACTURER); + set_zcl_string(model, HW_MODEL); + char ota_upgrade_file_version[10]; + sprintf(ota_upgrade_file_version, "%d", OTA_FW_VERSION); + set_zcl_string(firmware_version, ota_upgrade_file_version); + set_zcl_string(firmware_date, FW_BUILD_DATE); + uint8_t power_source = 4; /**< DC source. */ + + esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC); + esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, manufacturer); + esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, model); + esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &power_source); + esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_SW_BUILD_ID, firmware_version); + esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_DATE_CODE_ID, firmware_date); + + esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list1, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Basic cluster end + + // Identify cluster start + uint16_t identify_id = 0; + esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY); + esp_zb_identify_cluster_add_attr(esp_zb_identify_cluster, ESP_ZB_ZCL_CMD_IDENTIFY_IDENTIFY_ID, &identify_id); + + esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list1, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Identify cluster end + + // Time cluster start + esp_zb_attribute_list_t *esp_zb_server_time_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TIME); + + esp_zb_attribute_list_t *esp_zb_client_time_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TIME); + esp_zb_time_cluster_add_attr(esp_zb_client_time_cluster, ESP_ZB_ZCL_ATTR_TIME_LAST_SET_TIME_ID, &undefined_value); + + esp_zb_cluster_list_add_time_cluster(esp_zb_cluster_list1, esp_zb_server_time_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + esp_zb_cluster_list_add_time_cluster(esp_zb_cluster_list1, esp_zb_client_time_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Time cluster end + + // OTA cluster start + /** Create ota client cluster with attributes. + * Manufacturer code, image type and file version should match with configured values for server. + * If the client values do not match with configured values then it shall discard the command and + * no further processing shall continue. + */ + esp_zb_ota_cluster_cfg_t ota_cluster_cfg = { + .ota_upgrade_file_version = OTA_FW_VERSION, // OTA_UPGRADE_RUNNING_FILE_VERSION, + .ota_upgrade_downloaded_file_ver = OTA_FW_VERSION, // OTA_UPGRADE_DOWNLOADED_FILE_VERSION, + .ota_upgrade_manufacturer = manuf_id, + .ota_upgrade_image_type = OTA_UPGRADE_IMAGE_TYPE, + }; + esp_zb_attribute_list_t *esp_zb_ota_client_cluster = esp_zb_ota_cluster_create(&ota_cluster_cfg); + + /** add client parameters to ota client cluster */ + esp_zb_zcl_ota_upgrade_client_variable_t variable_config = { + .timer_query = ESP_ZB_ZCL_OTA_UPGRADE_QUERY_TIMER_COUNT_DEF, + .hw_version = OTA_UPGRADE_HW_VERSION, + .max_data_size = OTA_UPGRADE_MAX_DATA_SIZE, + }; + + uint16_t ota_upgrade_server_addr = 0xffff; + uint8_t ota_upgrade_server_ep = 0xff; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create(); + esp_zb_endpoint_config_t endpoint_config = { + .endpoint = 1, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_TEST_DEVICE_ID, + .app_device_version = 0, + }; + + /* create cluster list with ota cluster */ + esp_zb_ota_cluster_add_attr(esp_zb_ota_client_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_CLIENT_DATA_ID, (void *)&variable_config); + esp_zb_ota_cluster_add_attr(esp_zb_ota_client_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ADDR_ID, (void *)&ota_upgrade_server_addr); + esp_zb_ota_cluster_add_attr(esp_zb_ota_client_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ENDPOINT_ID, (void *)&ota_upgrade_server_ep); + + esp_zb_cluster_list_add_ota_cluster(esp_zb_cluster_list1, esp_zb_ota_client_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + // OTA cluster end + + // IAS cluster start + esp_zb_ias_zone_cluster_cfg_t ias_cluster_cfg = { + .zone_type = ESP_ZB_ZCL_IAS_ZONE_ZONETYPE_STANDARD_CIE, + .zone_state = ESP_ZB_ZCL_IAS_ZONE_ZONESTATE_NOT_ENROLLED, + .zone_status = ESP_ZB_ZCL_IAS_ZONE_ZONE_STATUS_ALARM1, + .ias_cie_addr = ESP_ZB_ZCL_ZONE_IAS_CIE_ADDR_DEFAULT, + .zone_id = 0, + }; + esp_zb_attribute_list_t *esp_zb_ias_zone_cluster = esp_zb_ias_zone_cluster_create(&ias_cluster_cfg); + + esp_zb_cluster_list_add_ias_zone_cluster(esp_zb_cluster_list1, esp_zb_ias_zone_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // IAS cluster end + + // Temperature cluster start + esp_zb_attribute_list_t *esp_zb_temperature_meas_cluster1 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster1, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster1, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster1, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list1, esp_zb_temperature_meas_cluster1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Temperature cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config1 = { + .endpoint = DEVICE_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_OUTPUT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list1, endpoint_config1); + // Endpoint config end + // DEVICE_ENDPOINT end + + // AHT20_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list2 = esp_zb_zcl_cluster_list_create(); + + // Temperature cluster start + esp_zb_attribute_list_t *esp_zb_temperature_meas_cluster2 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster2, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster2, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster2, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list2, esp_zb_temperature_meas_cluster2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Temperature cluster end + + // Humidity cluster start + esp_zb_attribute_list_t *esp_zb_humidity_meas_cluster2 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster2, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster2, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MIN_VALUE_ID, &zero_value); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster2, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_humidity_meas_cluster(esp_zb_cluster_list2, esp_zb_humidity_meas_cluster2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Humidity cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config2 = { + .endpoint = AHT20_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list2, endpoint_config2); + // Endpoint config end + // AHT20_ENDPOINT end + + // BME280_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list3 = esp_zb_zcl_cluster_list_create(); + + /* + // On/Off cluster start + esp_zb_on_off_cluster_cfg_t on_off_cfg3 = {}; + esp_zb_attribute_list_t *esp_zb_on_off_cluster3 = esp_zb_on_off_cluster_create(&on_off_cfg3); + + esp_zb_cluster_list_add_on_off_cluster(esp_zb_cluster_list3, esp_zb_on_off_cluster3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // On/Off cluster end + */ + + // Temperature cluster start + esp_zb_attribute_list_t *esp_zb_temperature_meas_cluster3 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster3, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster3, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster3, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list3, esp_zb_temperature_meas_cluster3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Temperature cluster end + + // Pressure cluster start + esp_zb_attribute_list_t *esp_zb_press_meas_cluster3 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT); + esp_zb_pressure_meas_cluster_add_attr(esp_zb_press_meas_cluster3, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_pressure_meas_cluster_add_attr(esp_zb_press_meas_cluster3, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MIN_VALUE_ID, &undefined_value); + esp_zb_pressure_meas_cluster_add_attr(esp_zb_press_meas_cluster3, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_pressure_meas_cluster(esp_zb_cluster_list3, esp_zb_press_meas_cluster3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Pressure cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config3 = { + .endpoint = BMP280_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list3, endpoint_config3); + // Endpoint config end + // BME280_ENDPOINT end + + // SCD40_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list4 = esp_zb_zcl_cluster_list_create(); + + /* + // On/Off cluster start + esp_zb_on_off_cluster_cfg_t on_off_cfg4 = {}; + esp_zb_attribute_list_t *esp_zb_on_off_cluster4 = esp_zb_on_off_cluster_create(&on_off_cfg4); + esp_zb_on_off_cluster_add_attr(esp_zb_on_off_cluster4, ESP_ZB_ZCL_ATTR_ON_OFF_ON_TIME, &zero_value); + esp_zb_on_off_cluster_add_attr(esp_zb_on_off_cluster4, ESP_ZB_ZCL_ATTR_ON_OFF_OFF_WAIT_TIME, &zero_value); + + esp_zb_cluster_list_add_on_off_cluster(esp_zb_cluster_list4, esp_zb_on_off_cluster4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // On/Off cluster end + */ + + // CarbonDioxide cluster start + esp_zb_attribute_list_t *esp_zb_carbon_dioxide_measurement_cluster4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT); + esp_zb_carbon_dioxide_measurement_cluster_add_attr(esp_zb_carbon_dioxide_measurement_cluster4, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, &undefined_float); + esp_zb_carbon_dioxide_measurement_cluster_add_attr(esp_zb_carbon_dioxide_measurement_cluster4, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MIN_MEASURED_VALUE_ID, &float_zero); // https://github.com/espressif/esp-zigbee-sdk/issues/147#issuecomment-1820778678 + esp_zb_carbon_dioxide_measurement_cluster_add_attr(esp_zb_carbon_dioxide_measurement_cluster4, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MAX_MEASURED_VALUE_ID, &float_one); + // esp_zb_carbon_dioxide_measurement_cluster_add_attr(esp_zb_carbon_dioxide_measurement_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_TOLERANCE_ID, &undefined_value); + + esp_zb_cluster_list_add_carbon_dioxide_measurement_cluster(esp_zb_cluster_list4, esp_zb_carbon_dioxide_measurement_cluster4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // CarbonDioxide cluster end + + // Temperature cluster start + esp_zb_attribute_list_t *esp_zb_temperature_meas_cluster4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster4, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster4, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, &undefined_value); + esp_zb_temperature_meas_cluster_add_attr(esp_zb_temperature_meas_cluster4, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list4, esp_zb_temperature_meas_cluster4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Temperature cluster end + + // Humidity cluster start + esp_zb_attribute_list_t *esp_zb_humidity_meas_cluster4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster4, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &undefined_value); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster4, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MIN_VALUE_ID, &zero_value); + esp_zb_humidity_meas_cluster_add_attr(esp_zb_humidity_meas_cluster4, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MAX_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_humidity_meas_cluster(esp_zb_cluster_list4, esp_zb_humidity_meas_cluster4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Humidity cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config4 = { + .endpoint = SCD40_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_OUTPUT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list4, endpoint_config4); + // Endpoint config end + // SCD40_ENDPOINT end + + // BH1750_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list5 = esp_zb_zcl_cluster_list_create(); + + // Illuminance cluster start + esp_zb_attribute_list_t *esp_zb_illuminance_meas_cluster5 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT); + esp_zb_illuminance_meas_cluster_add_attr(esp_zb_illuminance_meas_cluster5, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID, &undefined_value); + esp_zb_illuminance_meas_cluster_add_attr(esp_zb_illuminance_meas_cluster5, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MIN_MEASURED_VALUE_ID, &undefined_value); + esp_zb_illuminance_meas_cluster_add_attr(esp_zb_illuminance_meas_cluster5, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MAX_MEASURED_VALUE_ID, &undefined_value); + + esp_zb_cluster_list_add_illuminance_meas_cluster(esp_zb_cluster_list5, esp_zb_illuminance_meas_cluster5, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Illuminance cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config5 = { + .endpoint = BH1750_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list5, endpoint_config5); + // Endpoint config end + // BH1750_ENDPOINT end + + // AGS10_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list6 = esp_zb_zcl_cluster_list_create(); + + /* + // Custom cluster for TVOC start + cluster_id = TVOC_CLUSTER; // if TVOC - 0xfc81 // heimanSpecificAirQuality no attributes can be readed. but no errors. but if use 0x101 - error (Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhandled.) + attr_id = TVOC_ATTR; + // attr_type = ESP_ZB_ZCL_ATTR_TYPE_U16; + // attr_access = ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING; + + esp_zb_attribute_list_t *custom_tvoc_attributes_list6 = esp_zb_zcl_attr_list_create(cluster_id); + esp_err_t err; + + err = esp_zb_cluster_add_attr(custom_tvoc_attributes_list6, cluster_id, attr_id, attr_type, attr_access, &undefined_value); + if (err != ESP_OK) + { + ESP_LOGE(__func__, "Failed to add custom attribute 1: %s", esp_err_to_name(err)); + } + else + { + ESP_LOGI(__func__, "Successfully added custom attribute 1"); + } + + // print_custom_attributes(custom_tvoc_attributes_list6); + + esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list6, custom_tvoc_attributes_list6, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Custom cluster for TVOC end + */ + + // Analog Input cluster for TVOC start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster6 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster6, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list6, esp_zb_analog_input_cluster6, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster for TVOC end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config6 = { + .endpoint = AGS10_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list6, endpoint_config6); + // Endpoint config end + // AGS10_ENDPOINT end + + // ADC1_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list7 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster7 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster7, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list7, esp_zb_analog_input_cluster7, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config7 = { + .endpoint = ADC1_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list7, endpoint_config7); + // Endpoint config end + // ADC1_ENDPOINT end + + // ADC2_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list8 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster8 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster8, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list8, esp_zb_analog_input_cluster8, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config8 = { + .endpoint = ADC2_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list8, endpoint_config8); + // Endpoint config end + // ADC2_ENDPOINT end + + // IMU_BASE_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list10 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster10 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster10, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list10, esp_zb_analog_input_cluster10, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Multistate Value cluster start + esp_zb_attribute_list_t *esp_zb_multistate_value_cluster10 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_MULTISTATE_VALUE); + // esp_zb_multistate_value_cluster_add_attr(esp_zb_multistate_value_cluster10, ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_PRESENT_VALUE_ID, &undefined_value); + // esp_zb_multistate_value_cluster_add_attr(esp_zb_multistate_value_cluster11, ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_NUMBER_OF_STATES_ID, &undefined_value); + + // esp_zb_multistate_value_cluster_add_attr(esp_zb_multistate_value_cluster7, ESP_ZB_ZCL_ATTR_MULTISTATE_DESCRIPTION_ID, &undefined_value); + + cluster_id = ESP_ZB_ZCL_CLUSTER_ID_MULTISTATE_VALUE; + attr_id = ESP_ZB_ZCL_ATTR_MULTISTATE_VALUE_PRESENT_VALUE_ID; + esp_zb_cluster_add_attr(esp_zb_multistate_value_cluster10, cluster_id, attr_id, attr_type, attr_access, &zero_value); + + esp_zb_cluster_list_add_multistate_value_cluster(esp_zb_cluster_list10, esp_zb_multistate_value_cluster10, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Multistate Value cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config10 = { + .endpoint = IMU_BASE_ENDPOINT, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list10, endpoint_config10); + // Endpoint config end + // IMU_BASE_ENDPOINT end + + // IMU_FIRST_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list11 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster11 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster11, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list11, esp_zb_analog_input_cluster11, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config11 = { + .endpoint = IMU_BASE_ENDPOINT + 1, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list11, endpoint_config11); + // Endpoint config end + // IMU_FIRST_ENDPOINT end + + // IMU_SECOND_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list12 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster12 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster12, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list12, esp_zb_analog_input_cluster12, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config12 = { + .endpoint = IMU_BASE_ENDPOINT + 2, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list12, endpoint_config12); + // Endpoint config end + // IMU_SECOND_ENDPOINT end + + // IMU_THIRD_ENDPOINT start + esp_zb_cluster_list_t *esp_zb_cluster_list13 = esp_zb_zcl_cluster_list_create(); + + // Analog Input cluster start + esp_zb_attribute_list_t *esp_zb_analog_input_cluster13 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster13, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &undefined_value); + esp_zb_cluster_list_add_analog_input_cluster(esp_zb_cluster_list13, esp_zb_analog_input_cluster13, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + // Analog Input cluster end + + // Endpoint config start + esp_zb_endpoint_config_t endpoint_config13 = { + .endpoint = IMU_BASE_ENDPOINT + 3, + .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, + .app_device_version = 0}; + esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list13, endpoint_config13); + // Endpoint config end + // IMU_THIRD_ENDPOINT end + + esp_zb_device_register(esp_zb_ep_list); +} + +static void esp_zb_task(void *pvParameters) +{ + /* initialize Zigbee stack */ + esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZR_CONFIG(); + + esp_zb_init(&zb_nwk_cfg); + + zigbee_config_endpoints_attributes(); + + esp_zb_core_action_handler_register(zb_action_handler); + + esp_zb_set_primary_network_channel_set(ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK); + + ESP_ERROR_CHECK(esp_zb_start(true)); + + esp_zb_main_loop_iteration(); +} + +void send_bin_cfg_option(int endpoint, bool value) +{ + if (connected) + { + const char *endpoint_name = get_endpoint_name(endpoint); + ESP_LOGI(__func__, "attribute to %d on %s (endpoint %d)", value, endpoint_name, endpoint); + + esp_zb_zcl_status_t state_tmp = esp_zb_zcl_set_attribute_val(endpoint, + ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, + ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, + &value, + false); + + if (state_tmp != ESP_ZB_ZCL_STATUS_SUCCESS) + { + ESP_LOGE(__func__, "Setting cfg option On/Off attribute failed! error %d", state_tmp); + } + } + else + { + ESP_LOGW(__func__, "no connection! attribute to %d", value); + } +} + +void send_zone_1_state(uint8_t bit_index, uint8_t value) +{ + bool should_send = false; + + if (value < 2) + { + uint8_t old_zone_status = data.zone_status; + set_bit(&data.zone_status, bit_index, value); + ESP_LOGI(__func__, "new zone status: 0x%02x", data.zone_status); + + if (data.zone_status != old_zone_status) + { + should_send = true; + } + } + else + { + should_send = true; + } + + if (should_send && connected) + { + esp_zb_zcl_ias_zone_status_change_notif_cmd_t cmd = { + .zcl_basic_cmd = { + .dst_addr_u.addr_short = 0x0000, + .dst_endpoint = 1, + .src_endpoint = 1, + }, + .address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT, + .zone_status = data.zone_status, + .zone_id = 0, + .delay = 0, + }; + + esp_zb_zcl_ias_zone_status_change_notif_cmd_req(&cmd); + } + else if (!connected) + { + ESP_LOGW(__func__, "no connection! zone status: 0x%02x", data.zone_status); + } +} + +void zigbee_setup() +{ + ESP_LOGI("Zigbee", "Start Zigbee stack"); + + esp_zb_platform_config_t config = { + .radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(), + .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(), + }; + + ESP_ERROR_CHECK(esp_zb_platform_config(&config)); + + esp_zb_aps_src_binding_table_size_set(SRC_BINDING_TABLE_SIZE); + esp_zb_aps_dst_binding_table_size_set(DST_BINDING_TABLE_SIZE); + + xTaskCreate(esp_zb_task, "esp_zb_task", 4096, NULL, 5, NULL); +} \ No newline at end of file diff --git a/main/zigbee.h b/main/zigbee.h new file mode 100644 index 0000000..b0038a3 --- /dev/null +++ b/main/zigbee.h @@ -0,0 +1,70 @@ +#ifndef ZIGBEE_H +#define ZIGBEE_H + +#include "esp_zigbee_core.h" +#include "const.h" +#include "main.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define ESP_ZB_ZR_CONFIG() \ + { \ + .esp_zb_role = ESP_ZB_DEVICE_TYPE_ROUTER, \ + .install_code_policy = INSTALLCODE_POLICY_ENABLE, \ + .nwk_cfg.zczr_cfg = { \ + .max_children = MAX_CHILDREN, \ + }, \ + } + +#define ESP_ZB_DEFAULT_RADIO_CONFIG() \ + { \ + .radio_mode = ZB_RADIO_MODE_NATIVE, \ + } + +#define ESP_ZB_DEFAULT_HOST_CONFIG() \ + { \ + .host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE, \ + } + +#if !defined CONFIG_ZB_ZCZR +#error Define ZB_ZCZR in idf.py menuconfig to compile light (Router) source code. +#endif + + extern char strftime_buf[64]; + extern uint16_t manuf_id; + extern char manufacturer[16]; + extern char model[16]; + extern char firmware_version[16]; + extern char firmware_date[16]; + extern bool time_updated; + extern bool connected; + + void zigbee_setup(); + + void update_attributes(attribute_t attribute); + void send_bin_cfg_option(int endpoint, bool value); + void send_zone_1_state(uint8_t bit_index, uint8_t value); + void force_update_task(); + void force_update(); + void read_server_time(); + + static void esp_zb_task(void *pvParameters); + static void update_attribute_value(uint8_t endpoint, uint16_t cluster_id, uint8_t role, uint16_t attr_id, void *value, const char *attr_name); + + void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct); + static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask); + + static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message); + static esp_err_t zb_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message); + static esp_err_t zb_ota_upgrade_status_handler(esp_zb_zcl_ota_upgrade_value_message_t message); + static esp_err_t zb_ota_upgrade_query_image_resp_handler(esp_zb_zcl_ota_upgrade_query_image_resp_message_t message); + static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message); + +#ifdef __cplusplus +} +#endif + +#endif // ZIGBEE_H \ No newline at end of file diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..089eac0 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,11 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, , 0x6000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +zb_storage, data, fat, , 16K, +zb_fct, data, fat, , 1K, +ota_0, app, ota_0, , 1700K, +ota_1, app, ota_1, , 1700K, +storage, data, spiffs, , 500K, + diff --git a/sdkconfig b/sdkconfig new file mode 100644 index 0000000..3cb03fe --- /dev/null +++ b/sdkconfig @@ -0,0 +1,2157 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Configuration +# +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y +CONFIG_SOC_UART_SUPPORTED=y +CONFIG_SOC_GDMA_SUPPORTED=y +CONFIG_SOC_AHB_GDMA_SUPPORTED=y +CONFIG_SOC_GPTIMER_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_ETM_SUPPORTED=y +CONFIG_SOC_PARLIO_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_IEEE802154_SUPPORTED=y +CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y +CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y +CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y +CONFIG_SOC_PHY_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_LP_CORE_SUPPORTED=y +CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y +CONFIG_SOC_EFUSE_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_GPSPI_SUPPORTED=y +CONFIG_SOC_LEDC_SUPPORTED=y +CONFIG_SOC_I2C_SUPPORTED=y +CONFIG_SOC_SYSTIMER_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_HMAC_SUPPORTED=y +CONFIG_SOC_DIG_SIGN_SUPPORTED=y +CONFIG_SOC_ECC_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_BOD_SUPPORTED=y +CONFIG_SOC_APM_SUPPORTED=y +CONFIG_SOC_APM_CTRL_FILTER_SUPPORTED=y +CONFIG_SOC_PMU_SUPPORTED=y +CONFIG_SOC_PAU_SUPPORTED=y +CONFIG_SOC_LP_TIMER_SUPPORTED=y +CONFIG_SOC_LP_AON_SUPPORTED=y +CONFIG_SOC_LP_PERIPHERALS_SUPPORTED=y +CONFIG_SOC_LP_I2C_SUPPORTED=y +CONFIG_SOC_ULP_LP_UART_SUPPORTED=y +CONFIG_SOC_CLK_TREE_SUPPORTED=y +CONFIG_SOC_ASSIST_DEBUG_SUPPORTED=y +CONFIG_SOC_WDT_SUPPORTED=y +CONFIG_SOC_SPI_FLASH_SUPPORTED=y +CONFIG_SOC_RNG_SUPPORTED=y +CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y +CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y +CONFIG_SOC_MODEM_CLOCK_SUPPORTED=y +CONFIG_SOC_PM_SUPPORTED=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_AES_SUPPORT_DMA=y +CONFIG_SOC_AES_GDMA=y +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y +CONFIG_SOC_ADC_MONITOR_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=1 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=7 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=1 +CONFIG_SOC_ADC_PATT_LEN_MAX=8 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_IIR_FILTER_NUM=2 +CONFIG_SOC_ADC_DIGI_MONITOR_NUM=2 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=83333 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=611 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_CALIBRATION_V1_SUPPORTED=y +CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y +CONFIG_SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED=y +CONFIG_SOC_ADC_TEMPERATURE_SHARE_INTR=y +CONFIG_SOC_ADC_SHARED_POWER=y +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y +CONFIG_SOC_CPU_CORES_NUM=1 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FLEXIBLE_INTC=y +CONFIG_SOC_INT_PLIC_SUPPORTED=y +CONFIG_SOC_CPU_HAS_CSR_PC=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=4 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=4 +CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x80000000 +CONFIG_SOC_CPU_HAS_PMA=y +CONFIG_SOC_CPU_IDRAM_SPLIT_USING_PMP=y +CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=3072 +CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 +CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 +CONFIG_SOC_AHB_GDMA_VERSION=1 +CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1 +CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=3 +CONFIG_SOC_GDMA_SUPPORT_ETM=y +CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_ETM_GROUPS=1 +CONFIG_SOC_ETM_CHANNELS_PER_GROUP=50 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=31 +CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y +CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM=8 +CONFIG_SOC_GPIO_SUPPORT_ETM=y +CONFIG_SOC_GPIO_SUPPORT_RTC_INDEPENDENT=y +CONFIG_SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP=y +CONFIG_SOC_LP_IO_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_GPIO_IN_RANGE_MAX=30 +CONFIG_SOC_GPIO_OUT_RANGE_MAX=30 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=8 +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x000000007FFFFF00 +CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y +CONFIG_SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP=y +CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y +CONFIG_SOC_CLOCKOUT_HAS_SOURCE_GATE=y +CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 +CONFIG_SOC_RTCIO_PIN_COUNT=8 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_RTCIO_VALID_RTCIO_MASK=0xFF +CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_PERIPH_ALWAYS_ENABLE=y +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_HP_I2C_NUM=1 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_CMD_REG_NUM=8 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_HW_FSM_RST=y +CONFIG_SOC_I2C_SUPPORT_HW_CLR_BUS=y +CONFIG_SOC_I2C_SUPPORT_XTAL=y +CONFIG_SOC_I2C_SUPPORT_RTC=y +CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y +CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH=y +CONFIG_SOC_I2C_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_LP_I2C_NUM=1 +CONFIG_SOC_LP_I2C_FIFO_LEN=16 +CONFIG_SOC_I2S_NUM=1 +CONFIG_SOC_I2S_HW_VERSION_2=y +CONFIG_SOC_I2S_SUPPORTS_XTAL=y +CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y +CONFIG_SOC_I2S_SUPPORTS_PCM=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 +CONFIG_SOC_I2S_SUPPORTS_TDM=y +CONFIG_SOC_LEDC_SUPPORT_PLL_DIV_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y +CONFIG_SOC_LEDC_CHANNEL_NUM=6 +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20 +CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y +CONFIG_SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED=y +CONFIG_SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX=16 +CONFIG_SOC_LEDC_FADE_PARAMS_BIT_WIDTH=10 +CONFIG_SOC_MMU_PAGE_SIZE_CONFIGURABLE=y +CONFIG_SOC_MMU_PERIPH_NUM=1 +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 +CONFIG_SOC_MMU_DI_VADDR_SHARED=y +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=4 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE=y +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=4 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 +CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y +CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y +CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y +CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y +CONFIG_SOC_RMT_SUPPORT_XTAL=y +CONFIG_SOC_RMT_SUPPORT_RC_FAST=y +CONFIG_SOC_MCPWM_GROUPS=1 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MCPWM_SWSYNC_CAN_PROPAGATE=y +CONFIG_SOC_MCPWM_SUPPORT_ETM=y +CONFIG_SOC_MCPWM_CAPTURE_CLK_FROM_GROUP=y +CONFIG_SOC_PARLIO_GROUPS=1 +CONFIG_SOC_PARLIO_TX_UNITS_PER_GROUP=1 +CONFIG_SOC_PARLIO_RX_UNITS_PER_GROUP=1 +CONFIG_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH=16 +CONFIG_SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH=16 +CONFIG_SOC_PARLIO_TX_RX_SHARE_INTERRUPT=y +CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 +CONFIG_SOC_MPI_OPERATIONS_NUM=3 +CONFIG_SOC_RSA_MAX_BIT_LEN=3072 +CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 +CONFIG_SOC_SHA_SUPPORT_DMA=y +CONFIG_SOC_SHA_SUPPORT_RESUME=y +CONFIG_SOC_SHA_GDMA=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA224=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=4 +CONFIG_SOC_SDM_CLK_SUPPORT_PLL_F80M=y +CONFIG_SOC_SDM_CLK_SUPPORT_XTAL=y +CONFIG_SOC_SPI_PERIPH_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=6 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_SUPPORT_DDRCLK=y +CONFIG_SOC_SPI_SLAVE_SUPPORT_SEG_TRANS=y +CONFIG_SOC_SPI_SUPPORT_CD_SIG=y +CONFIG_SOC_SPI_SUPPORT_CONTINUOUS_TRANS=y +CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y +CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y +CONFIG_SOC_SPI_SUPPORT_CLK_PLL_F80M=y +CONFIG_SOC_SPI_SUPPORT_CLK_RC_FAST=y +CONFIG_SOC_SPI_SCT_SUPPORTED=y +CONFIG_SOC_SPI_SCT_REG_NUM=14 +CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y +CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA +CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16 +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y +CONFIG_SOC_SPI_MEM_SUPPORT_IDLE_INTR=y +CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_CHECK_SUS=y +CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 +CONFIG_SOC_SYSTIMER_ALARM_NUM=3 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_HI=20 +CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y +CONFIG_SOC_SYSTIMER_SUPPORT_RC_FAST=y +CONFIG_SOC_SYSTIMER_INT_LEVEL=y +CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y +CONFIG_SOC_SYSTIMER_SUPPORT_ETM=y +CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16 +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=1 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=54 +CONFIG_SOC_TIMER_GROUP_SUPPORT_XTAL=y +CONFIG_SOC_TIMER_GROUP_SUPPORT_RC_FAST=y +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=2 +CONFIG_SOC_TIMER_SUPPORT_ETM=y +CONFIG_SOC_TIMER_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_MWDT_SUPPORT_XTAL=y +CONFIG_SOC_TWAI_CONTROLLER_NUM=2 +CONFIG_SOC_TWAI_CLK_SUPPORT_XTAL=y +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_BRP_MAX=32768 +CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y +CONFIG_SOC_EFUSE_DIS_PAD_JTAG=y +CONFIG_SOC_EFUSE_DIS_USB_JTAG=y +CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y +CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y +CONFIG_SOC_EFUSE_DIS_ICACHE=y +CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y +CONFIG_SOC_SECURE_BOOT_V2_RSA=y +CONFIG_SOC_SECURE_BOOT_V2_ECC=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3 +CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=64 +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y +CONFIG_SOC_CRYPTO_DPA_PROTECTION_SUPPORTED=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_HP_NUM=2 +CONFIG_SOC_UART_LP_NUM=1 +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_LP_UART_FIFO_LEN=16 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_UART_SUPPORT_PLL_F80M_CLK=y +CONFIG_SOC_UART_SUPPORT_RTC_CLK=y +CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y +CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y +CONFIG_SOC_UART_HAS_LP_UART=y +CONFIG_SOC_UART_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y +CONFIG_SOC_COEX_HW_PTI=y +CONFIG_SOC_EXTERNAL_COEX_ADVANCE=y +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BEACON_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN=y +CONFIG_SOC_PM_SUPPORT_CPU_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_PM_SUPPORT_XTAL32K_PD=y +CONFIG_SOC_PM_SUPPORT_RC32K_PD=y +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +CONFIG_SOC_PM_SUPPORT_TOP_PD=y +CONFIG_SOC_PM_SUPPORT_HP_AON_PD=y +CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_PMU_MODEM_STATE=y +CONFIG_SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY=y +CONFIG_SOC_PM_CPU_RETENTION_BY_SW=y +CONFIG_SOC_PM_MODEM_RETENTION_BY_REGDMA=y +CONFIG_SOC_PM_RETENTION_HAS_CLOCK_BUG=y +CONFIG_SOC_PM_PAU_LINK_NUM=4 +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +CONFIG_SOC_MODEM_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +CONFIG_SOC_CLK_OSC_SLOW_SUPPORTED=y +CONFIG_SOC_CLK_RC32K_SUPPORTED=y +CONFIG_SOC_RCC_IS_INDEPENDENT=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL=y +CONFIG_SOC_TEMPERATURE_SENSOR_INTR_SUPPORT=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_ETM=y +CONFIG_SOC_RNG_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_WIFI_HW_TSF=y +CONFIG_SOC_WIFI_FTM_SUPPORT=y +CONFIG_SOC_WIFI_GCMP_SUPPORT=y +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_WIFI_HE_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_ESP_NIMBLE_CONTROLLER=y +CONFIG_SOC_BLE_50_SUPPORTED=y +CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y +CONFIG_SOC_BLE_POWER_CONTROL_SUPPORTED=y +CONFIG_SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED=y +CONFIG_SOC_BLUFI_SUPPORTED=y +CONFIG_SOC_BLE_MULTI_CONN_OPTIMIZATION=y +CONFIG_SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND=y +CONFIG_SOC_PHY_COMBO_MODULE=y +CONFIG_SOC_CAPS_NO_RESET_BY_ANA_BOD=y +CONFIG_SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR=y +CONFIG_SOC_LP_CORE_SUPPORT_ETM=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TOOLCHAIN="gcc" +CONFIG_IDF_TARGET_ARCH_RISCV=y +CONFIG_IDF_TARGET_ARCH="riscv" +CONFIG_IDF_TARGET="esp32c6" +CONFIG_IDF_INIT_VERSION="5.3.1" +CONFIG_IDF_TARGET_ESP32C6=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x000D + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# end of Build type + +# +# Bootloader config +# + +# +# Bootloader manager +# +CONFIG_BOOTLOADER_COMPILE_TIME_DATE=y +CONFIG_BOOTLOADER_PROJECT_VER=1 +# end of Bootloader manager + +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_ECC_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_PREFERRED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +CONFIG_SECURE_ROM_DL_MODE_ENABLED=y +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=9 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y +CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=3 +CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y +CONFIG_ESP_ROM_GET_CLK_FREQ=y +CONFIG_ESP_ROM_HAS_RVFPLIB=y +CONFIG_ESP_ROM_HAS_HAL_WDT=y +CONFIG_ESP_ROM_HAS_HAL_SYSTIMER=y +CONFIG_ESP_ROM_HAS_HEAP_TLSF=y +CONFIG_ESP_ROM_TLSF_CHECK_PATCH=y +CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH=y +CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y +CONFIG_ESP_ROM_HAS_SPI_FLASH=y +CONFIG_ESP_ROM_HAS_REGI2C_BUG=y +CONFIG_ESP_ROM_HAS_NEWLIB=y +CONFIG_ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT=y +CONFIG_ESP_ROM_REV0_HAS_NO_ECDSA_INTERFACE=y +CONFIG_ESP_ROM_WDT_INIT_PATCH=y +CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y +CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y +CONFIG_ESP_ROM_HAS_SW_FLOAT=y +CONFIG_ESP_ROM_USB_OTG_NUM=-1 +CONFIG_ESP_ROM_HAS_VERSION=y +CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEBUG=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +# CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_RVFPLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +CONFIG_COMPILER_RT_LIB_GCCLIB=y +CONFIG_COMPILER_RT_LIB_NAME="gcc" +# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set +CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +CONFIG_BT_ALARM_MAX_NUM=50 +# end of Bluetooth + +# +# Console Library +# +# CONFIG_CONSOLE_SORTED_HELP is not set +# end of Console Library + +# +# Driver Configurations +# + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# end of TWAI Configuration + +# +# Legacy ADC Driver Configuration +# +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Driver Configuration + +# +# Legacy MCPWM Driver Configurations +# +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy MCPWM Driver Configurations + +# +# Legacy Timer Group Driver Configurations +# +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Timer Group Driver Configurations + +# +# Legacy RMT Driver Configurations +# +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy RMT Driver Configurations + +# +# Legacy I2S Driver Configurations +# +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy I2S Driver Configurations + +# +# Legacy PCNT Driver Configurations +# +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy PCNT Driver Configurations + +# +# Legacy SDM Driver Configurations +# +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy SDM Driver Configurations + +# +# Legacy Temperature Sensor Driver Configurations +# +# CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Temperature Sensor Driver Configurations +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set +# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set +# CONFIG_ADC_ENABLE_DEBUG_LOG is not set +# end of ADC and ADC Calibration + +# +# Wireless Coexistence +# +CONFIG_ESP_COEX_ENABLED=y +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y +# CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE is not set +# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set +# end of Wireless Coexistence + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# ESP-Driver:GPIO Configurations +# +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:GPIO Configurations + +# +# ESP-Driver:GPTimer Configurations +# +CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:GPTimer Configurations + +# +# ESP-Driver:I2C Configurations +# +# CONFIG_I2C_ISR_IRAM_SAFE is not set +# CONFIG_I2C_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2C Configurations + +# +# ESP-Driver:I2S Configurations +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2S Configurations + +# +# ESP-Driver:LEDC Configurations +# +# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:LEDC Configurations + +# +# ESP-Driver:MCPWM Configurations +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:MCPWM Configurations + +# +# ESP-Driver:Parallel IO Configurations +# +# CONFIG_PARLIO_ENABLE_DEBUG_LOG is not set +# CONFIG_PARLIO_ISR_IRAM_SAFE is not set +# end of ESP-Driver:Parallel IO Configurations + +# +# ESP-Driver:PCNT Configurations +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:PCNT Configurations + +# +# ESP-Driver:RMT Configurations +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:RMT Configurations + +# +# ESP-Driver:Sigma Delta Modulator Configurations +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Sigma Delta Modulator Configurations + +# +# ESP-Driver:SPI Configurations +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of ESP-Driver:SPI Configurations + +# +# ESP-Driver:Temperature Sensor Configurations +# +# CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG is not set +# CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE is not set +# end of ESP-Driver:Temperature Sensor Configurations + +# +# ESP-Driver:UART Configurations +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of ESP-Driver:UART Configurations + +# +# ESP-Driver:USB Serial/JTAG Configuration +# +CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y +# end of ESP-Driver:USB Serial/JTAG Configuration + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +CONFIG_ESP_GDBSTUB_ENABLED=y +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y +CONFIG_ESP_GDBSTUB_MAX_TASKS=32 +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32C6_REV_MIN_0=y +# CONFIG_ESP32C6_REV_MIN_1 is not set +CONFIG_ESP32C6_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32-C6 Revision (Rev v0.99) +# +CONFIG_ESP32C6_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_IEEE802154=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0 +# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set +# CONFIG_ESP_SLEEP_DEBUG is not set +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_RC32K is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# ETM Configuration +# +# CONFIG_ETM_ENABLE_DEBUG_LOG is not set +# end of ETM Configuration + +# +# GDMA Configurations +# +CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# CONFIG_GDMA_ENABLE_DEBUG_LOG is not set +# end of GDMA Configurations + +# +# Main XTAL Config +# +CONFIG_XTAL_FREQ_40=y +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config + +# +# Crypto DPA Protection +# +CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP=y +CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_LOW=y +# CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_MEDIUM is not set +# CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_HIGH is not set +CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL=1 +# end of Crypto DPA Protection + +CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y +# CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# PHY +# +CONFIG_ESP_PHY_ENABLED=y +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +# CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is not set +# end of Power Management + +# +# ESP PSRAM +# + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_120 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 +CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y +# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set + +# +# Memory protection +# +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=7 +# end of Brownout Detector + +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +CONFIG_ESP_SYSTEM_HW_STACK_GUARD=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +CONFIG_ESP_SYSTEM_HW_PC_RECORD=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +# end of IPC (Inter-Processor Call) + +# +# ESP Timer (High Resolution Timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of ESP Timer (High Resolution Timer) + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_ENABLED=y +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP_WIFI_CSI_ENABLED is not set +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP_WIFI_TX_BA_WIN=6 +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=6 +CONFIG_ESP_WIFI_NVS_ENABLED=y +CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP_WIFI_IRAM_OPT=y +CONFIG_ESP_WIFI_EXTRA_IRAM_OPT=y +CONFIG_ESP_WIFI_RX_IRAM_OPT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP_WIFI_ENABLE_SAE_PK=y +CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_ESP_WIFI_SLP_IRAM_OPT=y +CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50 +CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10 +CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15 +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +CONFIG_ESP_WIFI_GMAC_SUPPORT=y +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y +CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=y +# CONFIG_ESP_WIFI_WAPI_PSK is not set +# CONFIG_ESP_WIFI_SUITE_B_192 is not set +# CONFIG_ESP_WIFI_11KV_SUPPORT is not set +# CONFIG_ESP_WIFI_MBO_SUPPORT is not set +# CONFIG_ESP_WIFI_DPP_SUPPORT is not set +# CONFIG_ESP_WIFI_11R_SUPPORT is not set +# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS is not set +# CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS is not set +CONFIG_ESP_WIFI_TX_HETB_QUEUE_NUM=3 + +# +# WPS Configuration Options +# +# CONFIG_ESP_WIFI_WPS_STRICT is not set +# CONFIG_ESP_WIFI_WPS_PASSPHRASE is not set +# end of WPS Configuration Options + +# CONFIG_ESP_WIFI_DEBUG_PRINT is not set +# CONFIG_ESP_WIFI_TESTING_OPTIONS is not set +CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=y +# CONFIG_ESP_WIFI_ENT_FREE_DYNAMIC_BUFFER is not set +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +# CONFIG_FATFS_SECTOR_512 is not set +CONFIG_FATFS_SECTOR_4096=y +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 +# CONFIG_FATFS_IMMEDIATE_FSYNC is not set +# CONFIG_FATFS_USE_LABEL is not set +CONFIG_FATFS_LINK_LOCK=y +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +CONFIG_FREERTOS_UNICORE=y +CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" +# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set +CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y +CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# end of Port + +CONFIG_FREERTOS_PORT=y +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y +CONFIG_FREERTOS_NUMBER_OF_CORES=1 +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=y +CONFIG_HAL_WDT_USE_ROM_IMPL=y +CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y +CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_USE_HOOKS is not set +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +CONFIG_HEAP_TLSF_USE_ROM_IMPL=y +# end of Heap memory debugging + +# +# IEEE 802.15.4 +# +CONFIG_IEEE802154_ENABLED=y +CONFIG_IEEE802154_RX_BUFFER_SIZE=20 +# CONFIG_IEEE802154_CCA_CARRIER is not set +CONFIG_IEEE802154_CCA_ED=y +# CONFIG_IEEE802154_CCA_CARRIER_OR_ED is not set +# CONFIG_IEEE802154_CCA_CARRIER_AND_ED is not set +CONFIG_IEEE802154_CCA_MODE=1 +CONFIG_IEEE802154_CCA_THRESHOLD=-60 +CONFIG_IEEE802154_PENDING_TABLE_SIZE=20 +# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set +# CONFIG_IEEE802154_TIMING_OPTIMIZATION is not set +# CONFIG_IEEE802154_DEBUG is not set +# end of IEEE 802.15.4 + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 +# CONFIG_LOG_MASTER_LEVEL is not set +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_ENABLE=y +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +# CONFIG_LWIP_EXTRA_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_ND6=y +# CONFIG_LWIP_FORCE_ROUTER_FORWARDING is not set +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV4=y +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# CONFIG_LWIP_TCP_SACK_OUT is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +CONFIG_LWIP_SNTP_STARTUP_DELAY=y +CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# end of DNS + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +CONFIG_MBEDTLS_PKCS7_C=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +CONFIG_MBEDTLS_CMAC_C=y +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y +CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y +CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_HARDWARE_ECC=y +CONFIG_MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ENCRYPTION is not set +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set + +# +# Thread Operational Dataset +# +CONFIG_OPENTHREAD_NETWORK_NAME="OpenThread-ESP" +CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX="fd00:db8:a0:0::/64" +CONFIG_OPENTHREAD_NETWORK_CHANNEL=15 +CONFIG_OPENTHREAD_NETWORK_PANID=0x1234 +CONFIG_OPENTHREAD_NETWORK_EXTPANID="dead00beef00cafe" +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="00112233445566778899aabbccddeeff" +CONFIG_OPENTHREAD_NETWORK_PSKC="104810e2315100afd6bc9215a6bfac53" +# end of Thread Operational Dataset + +CONFIG_OPENTHREAD_XTAL_ACCURACY=130 +# CONFIG_OPENTHREAD_SPINEL_ONLY is not set +# CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE is not set + +# +# Thread Address Query Config +# +# end of Thread Address Query Config +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# Main Flash configuration +# + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORTED=y +# CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_GD_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set + +# +# ULP Debugging Options +# +# end of ULP Debugging Options +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_VFS_SELECT_IN_RAM is not set +CONFIG_VFS_SUPPORT_TERMIOS=y +CONFIG_VFS_MAX_COUNT=8 + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# I2C +# +CONFIG_I2CDEV_TIMEOUT=2000 +# CONFIG_I2CDEV_NOLOCK is not set +# end of I2C + +# +# IoT Button +# +CONFIG_BUTTON_PERIOD_TIME_MS=5 +CONFIG_BUTTON_DEBOUNCE_TICKS=2 +CONFIG_BUTTON_SHORT_PRESS_TIME_MS=180 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=1500 +CONFIG_BUTTON_LONG_PRESS_TOLERANCE_MS=20 +CONFIG_BUTTON_SERIAL_TIME_MS=20 +# CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE is not set +CONFIG_ADC_BUTTON_MAX_CHANNEL=3 +CONFIG_ADC_BUTTON_MAX_BUTTON_PER_CHANNEL=8 +CONFIG_ADC_BUTTON_SAMPLE_TIMES=1 +# end of IoT Button + +# +# CMake Utilities +# +# CONFIG_CU_RELINKER_ENABLE is not set +# CONFIG_CU_DIAGNOSTICS_COLOR_NEVER is not set +CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS=y +# CONFIG_CU_DIAGNOSTICS_COLOR_AUTO is not set +# CONFIG_CU_GCC_LTO_ENABLE is not set +# CONFIG_CU_GCC_STRING_1BYTE_ALIGN is not set +# end of CMake Utilities + +# +# Zigbee +# +CONFIG_ZB_ENABLED=y +CONFIG_ZB_ZCZR=y +# CONFIG_ZB_ZED is not set +# CONFIG_ZB_ZGPD is not set +CONFIG_ZB_RADIO_NATIVE=y +# CONFIG_ZB_RADIO_SPINEL_UART is not set + +# +# Zigbee Example +# +CONFIG_ZB_GP_ENABLED=y +# end of Zigbee Example + +# CONFIG_ZB_DEBUG_MODE is not set +# end of Zigbee +# end of Component config + +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y +# CONFIG_EXTERNAL_COEX_ENABLE is not set +# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +CONFIG_GDBSTUB_SUPPORT_TASKS=y +CONFIG_GDBSTUB_MAX_TASKS=32 +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_BROWNOUT_DET_LVL=7 +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/tools/commit.sh b/tools/commit.sh new file mode 100755 index 0000000..e45285e --- /dev/null +++ b/tools/commit.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +# Define colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Ask for confirmation to pull changes +echo -e "${YELLOW}Do you want to pull the latest changes from the repository? 🔄 (Y/n)${NC}" +read -r response +response=${response:-y} # default 'yes' if empty +if [[ "$response" =~ ^[Yy]$ ]]; then + git pull + echo -e "${GREEN}Changes pulled successfully. ✔️${NC}" +else + echo -e "${YELLOW}Pull skipped. Continuing without pulling changes. ⚠️${NC}" +fi + +# Adding all changes to staging +git add -A +echo -e "${GREEN}All changes added to staging. ✔️${NC}" + +# Path to the version and commit message files +COMMIT_MESSAGE_FILE="commit.md" + +# Get the latest tag +latest_tag=$(git describe --tags --abbrev=0) + +# Check if any tags exist +if [ -z "$latest_tag" ]; then + echo -e "${RED}No tags found. ❌${NC}" + git_version_number=1 +else + + # Extract the version number from the latest tag + git_version_number=${latest_tag} +fi + +# Set the first release date +first_release_date="20241001" + +# Get the current date +current_date=$(date +%Y%m%d) + +# Calculate the version number +local_version_number=$((current_date - first_release_date)) +if [ $local_version_number -lt 1 ]; then + local_version_number=1 +fi + +if [ "$git_version_number" -lt "$local_version_number" ]; then + version_number=$((local_version_number)) +else + version_number=$((git_version_number + 1)) +fi + +tag=$version_number + +echo "Using tag to $tag" + +# Checking for commit message file +if [ -f "$COMMIT_MESSAGE_FILE" ]; then + echo -e "${YELLOW}Commit message file found. Do you want to use the existing commit message? (y/N) 📝${NC}" + read -r useExistingMessage + useExistingMessage=${useExistingMessage:-n} # default 'no' if empty + if [[ "$useExistingMessage" =~ ^[Yy]$ ]]; then + commitMessage=$(cat "$COMMIT_MESSAGE_FILE") + # Prepend version to the commit message with a newline for separation + formattedCommitMessage="${tag} + ${commitMessage}" + # Cleaning up the commit message file, if used + if [ -f "$COMMIT_MESSAGE_FILE" ]; then + tools/clean_file.sh "$COMMIT_MESSAGE_FILE" + fi + else + echo -e "${YELLOW}Please enter your commit message: 📝${NC}" + read -r commitMessage + formattedCommitMessage="${commitMessage}" + fi +else + echo -e "${YELLOW}Commit message file not found. Please enter your commit message: 📝${NC}" + read -r commitMessage + formattedCommitMessage="${commitMessage}" +fi + +# Committing changes +git commit -m "$formattedCommitMessage" +echo -e "${GREEN}Changes committed with version prepended to message: ✔️${NC}" + +# Tagging process +echo -e "${YELLOW}Do you want to create a new release by publishing a tag? 🏷️ (y/N)${NC}" +read -r tagCommit +tagCommit=${tagCommit:-n} # default 'no' if empty +if [[ "$tagCommit" =~ ^[Yy]$ ]]; then + git tag "$tag" + echo -e "${GREEN}Tag assigned: $tag 🏷️${NC}" + + # Pushing changes and tag + echo -e "${YELLOW}Do you want to push the changes and the new tag to the remote repository? 🚀 (Y/n)${NC}" + read -r pushChanges + pushChanges=${pushChanges:-y} # default 'yes' if empty + if [[ "$pushChanges" =~ ^[Yy]$ ]]; then + git push + git push origin "$tag" + echo -e "${GREEN}Changes and new tag pushed successfully. ✔️${NC}" + else + echo -e "${RED}Push of changes and tag skipped. ❌${NC}" + fi +else + echo -e "${YELLOW}No new release will be created. Do you still want to push the changes? (Y/n) 🚀${NC}" + read -r pushChanges + pushChanges=${pushChanges:-y} # default 'yes' if empty + if [[ "$pushChanges" =~ ^[Yy]$ ]]; then + git push + echo -e "${GREEN}Changes pushed successfully without creating a new release. ✔️${NC}" + else + echo -e "${RED}Push skipped. ❌${NC}" + fi +fi + diff --git a/tools/create-ota.py b/tools/create-ota.py new file mode 100644 index 0000000..00a8b73 --- /dev/null +++ b/tools/create-ota.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# create-ota - Create zlib-compressed Zigbee OTA file +# Copyright 2023 Simon Arlott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +import functools +import zlib + +import zigpy.ota + + +def create(filename, manufacturer_id, image_type, file_version, header_string): + with open(filename, "rb") as f: + data = f.read() + + #zobj = zlib.compressobj(level=zlib.Z_BEST_COMPRESSION) + #zdata = zobj.compress(data) + #zdata += zobj.flush() + zdata = data + + image = zigpy.ota.image.OTAImage( + header=zigpy.ota.image.OTAImageHeader( + upgrade_file_id=zigpy.ota.image.OTAImageHeader.MAGIC_VALUE, + header_version=0x0100, + header_length=0, + field_control=zigpy.ota.image.FieldControl(0), + + manufacturer_id=manufacturer_id, + image_type=image_type, + file_version=file_version, + + stack_version=2, + header_string=header_string[0:32], + image_size=0, + ), + subelements=[ + zigpy.ota.image.SubElement( + tag_id=zigpy.ota.image.ElementTagId.UPGRADE_IMAGE, data=zdata, + ) + ], + ) + + image.header.header_length = len(image.header.serialize()) + image.header.image_size = image.header.header_length + len(image.subelements.serialize()) + return image.serialize() + +if __name__ == "__main__": + any_int = functools.wraps(int)(functools.partial(int, base=0)) + parser = argparse.ArgumentParser(description="Create zlib-compressed Zigbee OTA file", + epilog="Reads a firmware image file and outputs an OTA file on standard output") + parser.add_argument("filename", metavar="INPUT", type=str, help="Firmware image filename") + parser.add_argument("output", metavar="OUTPUT", type=str, help="OTA filename") + parser.add_argument("-m", "--manufacturer_id", metavar="MANUFACTURER_ID", type=any_int, required=True, help="Manufacturer ID") + parser.add_argument("-i", "--image_type", metavar="IMAGE_ID", type=any_int, required=True, help="Image ID") + parser.add_argument("-v", "--file_version", metavar="VERSION", type=any_int, required=True, help="File version") + parser.add_argument("-s", "--header_string", metavar="HEADER_STRING", type=str, default="", help="Header String") + + args = parser.parse_args() + output = args.output + del args.output + + data = create(**vars(args)) + with open(output, "wb") as f: + f.write(data) diff --git a/tools/make_ota.sh b/tools/make_ota.sh new file mode 100755 index 0000000..2607a19 --- /dev/null +++ b/tools/make_ota.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Set the script to exit on any errors +set -e + +# Description: This script creates an OTA file from the Q_sensor.bin file. +cd ./tools + +# Install the required Python packages +python3 -m pip install -q zigpy + +# Read the values from const.h +MANUFACTURER=$(grep -o '#define\s\+OTA_UPGRADE_MANUFACTURER\s\+0x[0-9a-fA-F]\+' ../main/const.h | awk '{print $3}') +IMAGE_TYPE=$(grep -o '#define\s\+OTA_UPGRADE_IMAGE_TYPE\s\+0x[0-9a-fA-F]\+' ../main/const.h | awk '{print $3}') +FILE_VERSION=$(grep -o '#define\s\+OTA_FW_VERSION\s\+0x[0-9a-fA-F]\+' ../main/const.h | awk '{print $3}') + +# Check if the Q_sensor.bin file exists +if [ ! -f "../build/Q_sensor.bin" ]; then + echo "Q_sensor.bin file not found!" + exit 1 +fi + +# Print the values +echo "M: $MANUFACTURER | IT: $IMAGE_TYPE | FV: $FILE_VERSION"; + +# Create the output folder if it doesn't exist yet +mkdir -p ../output + +# Create the OTA file +python3 create-ota.py -m "$MANUFACTURER" -i "$IMAGE_TYPE" -v "$FILE_VERSION" ../build/Q_sensor.bin ../output/Q_sensor.ota + +# Copy the Q_sensor.bin file to the output folder +cp ../build/Q_sensor.bin ../output/Q_sensor.bin + +echo "OTA file created successfully! Version: $FILE_VERSION" \ No newline at end of file diff --git a/tools/update_version.sh b/tools/update_version.sh new file mode 100755 index 0000000..ba5292b --- /dev/null +++ b/tools/update_version.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +current_date=$(date +%Y%m%d) + +# Check if the script is being run in a GitHub workflow +if [ "$GITHUB_ACTIONS" = true ]; then + # Get the latest tag + latest_tag=$(git describe --tags --abbrev=0) + # Extract the version number from the latest tag + version_number=${latest_tag} + +else + # Set the first release date + first_release_date="20241001" + + # Get the current date + current_date=$(date +%Y%m%d) + + # Calculate the version number + version_number=$((current_date - first_release_date)) + if [ $version_number -lt 1 ]; then + version_number=1 + fi +fi + +# Convert the version number to hexadecimal +hex_version=$(printf "%08X" $version_number) + +# Print the new version number, HEX version, date +echo "New version number: $version_number" +echo "HEX: 0x$hex_version" +echo "build date: $current_date" + +# Set the output date variable +echo "version=$version_number" >> $GITHUB_ENV +# Set the output date variable +echo "build_date=$current_date" >> $GITHUB_ENV + +# Update the device version in const.h using awk +awk -v hex_version="$hex_version" '/OTA_FW_VERSION/ {sub(/0x[0-9A-F]*/, "0x" hex_version)} 1' main/const.h > temp && mv temp main/const.h +awk -v fw_date="$current_date" '/FW_BUILD_DATE/ {sub(/"[^"]*"/, "\"" fw_date "\"")} 1' main/const.h > temp && mv temp main/const.h \ No newline at end of file